一直有用 Firefox 的 FoxAge2ch 和 bbs2chreader 兩個套件來訂閱 2ch 的討論,不過後來遇到一些我也懶得研究的問題,其實不是那麼順手……直到昨天 FoxAge2ch 公開了 3.0b2 版,試用後一些疑難雜症都不見了!功能完善,值得寫個簡單入門步驟、介紹一下:

先說明一下,如果你不想寫/改套件,這篇文章很慚愧地幫不上什麼忙。
問題是這樣:Firefox「附加元件管理員」開啟的選項視窗(prefwindow)是不能縮放的;所以視窗過大、過小都會變成痛苦。以往要突破此限制,可能會另外提供開視窗的方法,例如把選項放在工具列以便自行操作開視窗的行為;但不是每個套件都值得為了這個,特別新增選單項目佔空間吧。
正好前幾天 Tab Mix Plus 放出新版 0.3.7,發現他的選項視窗很特別,開了以後還能把套件管理員關掉(本來是暫時關不掉),於是看了原始碼,在 chrome/content/tabmixplus/links/setup.js 第 29 行找到魔法的痕跡……細節就省略,因為跟下面改的東西原理相同(改的極少,恐怕說抄比較貼切。)
這是一個 XUL、overlay 檔案,讓附加元件管理員開出可縮放的視窗:
- <?xml version="1.0" encoding="UTF-8"?>
- <overlay id="resizable-extensions-overlay"
- xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
- <script type="application/x-javascript"><![CDATA[
- // Make prefwindow resizable.
- // overwrite cmd_options, see chrome/tookit/content/mozapps/extensions/extensions.js
- window.addEventListener("load", function(){
- eval("gExtensionsViewController.commands.cmd_options ="+gExtensionsViewController.commands.cmd_options.toString().replace(
- 'openDialog(optionsURL, "", features);',
- 'openDialog(optionsURL, "", features + ",resizable=yes"';
- ));
- return;
- }, false);
- ]]></script>
- </overlay>
<?xml version="1.0" encoding="UTF-8"?> <overlay id="resizable-extensions-overlay" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <script type="application/x-javascript"><![CDATA[ // Make prefwindow resizable. // overwrite cmd_options, see chrome/tookit/content/mozapps/extensions/extensions.js window.addEventListener("load", function(){ eval("gExtensionsViewController.commands.cmd_options ="+gExtensionsViewController.commands.cmd_options.toString().replace( 'openDialog(optionsURL, "", features);', 'openDialog(optionsURL, "", features + ",resizable=yes"'; )); return; }, false); ]]></script> </overlay>
看來是鑽到某個不為人知的物件,把它的方法轉成字串修改後再 eval ……感覺很不可靠,但是寫法好簡單,乾脆急病亂投醫吧。

幾乎所有 blogger.com 的 blog 送交 W3C Markup Validator 都能驗出錯誤,其中很多是 blogger 自動產生的原始碼,想改也改不掉。
這個問題至少 2006 年起就有人在 Blogger Help Group 留言或寄信反應,但是官方一直沒修正,儘管問題看起來好像很簡單——以此 blog 來說,只剩下新/舊文章連結的 &
要改成 &
、留言內容的標籤名稱要改成小寫,兩個地方而已。
當然 invalid 未必有什麼毒害,只是 Google 擺著幾個小問題(假設是小問題)不管以致無法通過檢驗,教人煩悶。
回報方式除了 Blogger Help Group 外,說明中心有個 Wishlist,另好像也有 Contacting Support 不過我找不到信箱位址……根據論壇使用者說法,官方回信這問題被歸為「低優先性」所以進展較慢。至於有多慢呢?至少在 Known Issues for Blogger 還找不到,可見 valid XHTML 真是沒有普遍需求的東西啊。
多虧貢獻者回報,總算找到某 Firefox 套件為啥在 Mac 沒反應了——就是作者沒注意到 browser.preferences.instantApply
這個設定啦(其實抄程式的時候有看過,但是不解其意就順理成章地忽略了……)
instantApply 中文意思是「立即套用」,在 Windows 預設是 False(不會立即套用):
選項視窗會出現「確定」和「取消」按鈕,等使用者按了「確定」後設定才會生效。
另一方面在 Linux 和 Mac,這個選項預設是 True:
選項視窗不會出現確定/取消,而是出現「關閉」按鈕。使用者一旦更改選項(比方勾了某個框框),該選項便當場生效。
問題是,如果套件只知道等使用者按「確定」才動作,那在 instantApply 有效而沒有確定鈕的情形下,套件就跟冷凍魚一樣不會動了。
出錯的是這種寫法:在 prefwindow 的 ondialogaccept(按確定/接受)事件發生時進入處理動作,結果 instantApply 啟用時,按關閉按鈕觸發的是 ondialogcancel(取消)而非 ondialogaccept 事件,導致視窗關了,套件卻什麼也沒做。
解決方式
- 如果是單純開、關、修改對應到 prefs 的選項,那聰明的 Firefox 會自己搞定,不需特別照顧。
- 如果要做的動作比較複雜,可以用
document.documentElement.instantApply
來取得 instantApply 到底有開沒開,有的話,再捕捉選項改變的時機,另行處理。 - 如果做不到前一個辦法(捕捉改變時機再處理),還是可以退一步在 ondialogcancel 裡面做原本 ondialogaccept 要做的事。只是這麼一來就不是真的 instantApply 了。
實際在 Noise 套件中,因為改設定的處理比較囉唆,會存 RDF 和一些有的沒的,所以目前決定不做真正的 instantApply,而是在改變選項時,顯示一個「關閉後才會套用」的提示:
這個方式我覺得很好,可以接受。
參考:About:config entries - MozillaZine Knowledge Base 下的 browser. preferences. instantApply 項目