顯示具有 JavaScript 標籤的文章。 顯示所有文章
顯示具有 JavaScript 標籤的文章。 顯示所有文章

2010/02/22

版面 Script 更新‧Ⅷ

看了看紀錄,距離上次修改部落格的核心,已經是好幾年前了。一直放話說要重寫不過似乎都沒有動手過,Blogger這幾年強化了不少,值得提的就屬「繼續閱讀」功能了,這功能當初推出的時候官方提供的樣板都還沒全部支援咧,現在應該都已經支援了吧。

可惜這個功能我已經利用官方以前的hack:隱藏部分文章的方式來達成了,萬一我現在追尋官方的架構,那舊的文章要一篇篇改動。我太懶了所以暫時還是維持原狀好了。如果可以維持舊的繼續使用隱藏法;新的使用官方提供的功能的話,那就更好了,我還要研究看看。

總之我先把部落格使用到的JavaScript檔案給更新一下好了:jQuery從1.2.6也升級到了1.4.2,有一些語法變了 (最大的變動就是屬性前面不用再加 @,ex: div[@id='test'] → div[id='test'])。JavaScript設計師最愛用的工具 JSLint 也是越變越嚴格了 (這玩意兒竟可以一直保持更新到現在,真厲害),之前寫的東西已經有些過不去了,經過幾番修改後才又符合了 JSLint 的規範。印象比較深刻的是正規表達式 (RegExp) 的 "." 不精確的問題,這真是切重要點啊,反正我就是要任意文字所以就用了 .,但通常你可能只需要 \S (除了換行等特殊符號以外的字元) 之類的。

最後將程式碼用 Google 釋出的 Closure Compiler Service 壓縮。以前很多人喜歡用 Dean 的 Packer 來壓縮,雖然壓出來的檔案確實很小,但執行解壓的程式碼所需的時間反而拖長,現在已經沒什麼人在用的樣子。以前也有很多像是 JSMin, YUI Compressor 之類的......總之,經過壓縮之後縮小了37%以上。光這些十幾KB的程式檔一個月就能吃掉30MB的流量,縮小一點除了減少流量以外,瀏覽器端的讀取速度也會快一點,總之是有正向幫助的。

2010/02/10

Auto follow Echofon on Twitter?

English summary:

Echofon since version 1.9.5 has a bug that will ask for following @echofon on Twitter at your next time running Firefox. When you choose No, it'll let your Twitter account auto follow echofon account. That makes users feel inconvenient or impolite.

Reproduction step:

1. Type "about:config" in Address bar
2. Filter: twitternotifier
3. Set extensions.twitternotifier.checkFollow to 1
4. Restart Firefox

When you open Firefox, the prompting will popup again.

在Firefox很好用的一個擴充套件 EchoFon (舊稱 TwitterFox) 是知名微網誌推特 (Twitter) 的 Notifier。一直以來使用它來收發 Tweets 都非常方便,不過這篇不打算對它作介紹,而是要來紀錄一個在 1.9.5 版本會遇到的問題。(1.9.5.1 版確認此問題仍舊存在)

1.9.5 版本中,新增了一個可以讓使用者自動追蹤官方帳號的功能,這個功能在你第一次安裝或更新到此版本的時候並不會有所反應。而是在你下一次重新啟動 Firefox 時才會啟動,它會跳出視窗詢問你:



看起來很友善,不過一般人通常都會按否吧?所以我的第一反應也是按下了否。但使用著,發現奇怪,我的 following 為什麼多了 echofon? 我剛才按的是否沒錯吧?



數度想再次重現這個機制,不過設定視窗內並沒有明顯的選項可以重新啟動,只好把腦筋動到了程式碼內。發現了這個問題的重現方法。

重現步驟:

1. Firefox 瀏覽器網址列鍵入 about:config
2. 篩選條件打 twitternotifier
3. extensions.twitternotifier.checkFollow 改成 1


4. 重新啟動 Firefox

這麼一來,我們就可以看看剛才是不是誤按了......確實不是,明明按了否但是 following 卻自動增加了官方帳號,難怪官方帳號的 followers 那麼多,我覺得這是很不尊重使用者的 Bug,希望下一版能夠改掉這個問題。順便做個紀錄。

發生原因 / Cause:

Echofon.jar/content/twitterfox.js:

According to MDC, confirmEx always returns index of the button pressed (like 0, 1, 2). No is 1, so followEchofon will be run. Instead, press Yes (index 0) won't run it.

根據 MDC 說明,confirmEx 回傳按下按鈕的索引值。由於 No 應屬索引 1,所以按下後 followEchofon 會被執行,按下 Yes (index 0) 反而不會執行。

2008/09/03

Google Chrome beta

不來寫一下說不過去XD 最近正紅的玩意。

簡單說這個 Google Chrome (Google 瀏覽器)是Google釋出的開放原始碼軟體,核心採用 WebKit,另外 JavaScript 虛擬機器採用自行開發的 V8 引擎,可以提升 JavaScript 的執行速度。另外也同捆了 Google Gears 這個套件,可以讓 Web 應用程式在離線下依然能動作並儲存一些資料的功能。

他主要的獨特設計在於一個頁籤是一個 Process 的設計,加上自身的工作管理員就會有n+1個行程。另外嵌在網頁內的 Plug-ins 如 Flash 等執行時也會獨立成一個行程,避免在執行時發生錯誤把整個瀏覽器都給關閉了。這樣的設計不會影響其他行程,缺點是過多的行程吃的 CPU 跟記憶體十分可觀。

另外說的很好聽的「無痕式視窗」其實就是不留下本機紀錄的設計罷了,Trace Cookie 等東西要抓你來訪過網站的紀錄還是可以的,簡單說他的無痕是著重在客戶端使用者這方面的,可能拿來上一些エロ網站不錯用?怕被人家抓包的時候就用這個模式來瀏覽,不過我是傾向於瀏覽完畢手動清除歷史紀錄、Cookie 及快取,反正現在都內建一個按鈕輕鬆搞定。

V8 引擎值得大書特書。許多網站都對其作過諸如 SunSpider 的 JavaScript Benchmark,速度還比 Opera 9.52、Firefox 3.01 和 Safari 3.1.2 (w/ WebKit-r35986) 快許多。不過 Fx 最近有個新武器 TraceMonkey,不知道可否追上 V8?另外系出同源的 Apple Safari 不知有沒有機會享受 Google 的開發成果,將此 V8 引擎的技術編回 WebKit 造福自由社群。

最後預設的中文字型有點醜,Safari 的字型圓滑效果十分棒結果它竟然沒有得到半點好處。設定對於進階使用者也太過簡單了,至少留下 about:config 這種底層設定供玩家 hacking。不過以一般使用者來說,簡單好上手又清爽,應該是不錯的選擇。不過想要以此撼動 IE 帝國的占有率,對於那些無知的愚民們大概也無關痛癢,反正點兩下 e 圖示就能上網,根本就不會想換了。倒有可能跟既有的 Firefox, Opera 跟 Safari 使用者產生排擠現象,搶占這些本來就不多的比例。但我個人認為 Firefox 獨特的擴充自訂性是其他瀏覽器難以取代的,沒有滑鼠手勢或強大的分頁管理就跟斷了右手一樣難以上網,你能想像嗎?

假如少了 Google Gears,我覺得 Google Chrome 就只是另一種新設計的 WebKit 核心瀏覽器罷了。的確他許多的設計不錯 (一頁一行程、V8 Engine),但是少了 Gears 帶來的殺手級離線 Web 應用程式支援就變的一般。我了解 Google 想利用這個自訂的瀏覽器達成他自己的完美 Web 應用程式支援,但目前還看不出有什麼必須使用它的理由,我用 Firefox 也同樣可以看 GMail,並沒有因為使用 Chrome 就變得方便或功能增加,以前微軟的 MSN Explorer 就對自家服務整合的非常徹底且非常方便。當然 Google 可能只是想為未來的 RIA 豐富網路程式作一個理想運作平台而不僅僅為自身著想,我可能看到了他的目標,但我認為這樣還不太足夠就是了。現在只靠 Gears 還不足以有大突進,還是要看未來更多技術定案 (HTML 5) 並直接內建 (JavaScript Libraries) 支援這樣才有進化的感覺吧。

*本文使用Google Chrome撰寫。


09/04 追記:

Google Chrome 開源碼庫 Chromium (鉻元素) 及開放社群已經成立 (http://www.chromium.org/),另外還有 Nightly Build 可以嘗鮮,不過目前的程式碼十分混亂,還是等官方進一步公告開發進度再說吧。看來未來可以期待社群版 Chromium Build了。(官方釋出版才能用 Google Chrome,非官方編譯版只能用 Chromium 當名字)

另外看到有人提出 Chrome 跟 V8 一詞其實分別代表傳統美國大車的外觀跟引擎 (see: http://fred.ipod.to/blog/?post;1656#c4),能發現這點實在不簡單。

2007/09/22

JavaScript 1.6, 1.7, 1.8 新功能探討

此為 JavaScript 學習筆記。

目前 JavaScript 由 Mozilla 基金會所主導維護開發,目前最新版是 1.7 (in Firefox 2.0),開發中版本 1.8 (in Firefox 3) 是 jQuery 作者 John Resig 主導。雖然 1.5 以後的新版本大多只有 Firefox 自己支援,但是如果就這樣不去學習新功能也未免太可惜了點。有鑒於坊間的書都是介紹舊版本而不會介紹新版的關係,自本家的 Development Wiki 看資料最快速,搭配範例程式碼實際操作幾遍很快就會了。可惜的是這些新功能不是每個瀏覽器都支援,在等待迎向 JavaScript 2.0 的同時,也來關心一下這些版本到底多了什麼新玩意。

New in JavaScript 1.6:

‧Array 增加更多方法
- indexOf, lastIndexOf
- every, some, filter
- map, forEach

(last)indexOf 方法其實跟 String 的一樣,所以沒什麼好講的。要查詢某個陣列中是否有特定的元素用這個方法會更方便。至於 every, some, filter 可傳入一個函式讓陣列中的元素去試,every 全部符合回傳 true, some 部分符合回傳 true, filter 則會回傳符合元素。map 和 forEach 則可以丟入一個函式讓每個元素去跑 (map 可依函式執行結果修改陣列元素)。



New in JavaScript 1.7:

1.7 真是大改進。不像先前的版本只有方法的增加,這次更有語法方面的增加。

‧新增 Generator, Iterator 物件
- yield 敘述, next 方法

Generator 可以在迴圈內暫停,並將值先送出來。待下次呼叫時再行運作,並且重複以上步驟。用範例看會比較清楚。



這個 foo 用到了 yield 敘述,因此會回傳一個 Generator 物件並指定給變數 bar。變數 bar 具有 next() 方法,當每次呼叫時會執行 foo() 裡面的敘述,第一次碰到 yield 時就會將指定的 i++ 傳出來,於是印出 1。當下一次再呼叫 bar.next() 時便會繼續從剛才中斷處執行下去,又碰到 yield,中斷回傳 2,就這樣重複。雖然 foo() 內定義的是無限迴圈, 但是有了 Generator 就可以控制這個迴圈,不斷的以 next() 回傳希望的數值。

Iterator 就是迭代器(迴圈器),使用 Iterator() 包裹起來後便可以用 next() 來逐一取元素,當已經取到底的時候 next() 會觸發一個 StopIteration 例外藉以停止。



但是我覺得下面的方法更直覺:



‧Array comprehensions

將原本生成陣列時繁瑣的步驟變成一行式,不過這不好理解而且有點難用,似乎是從 Python 移植過來的功能。



[i for (i in ...) if ...] 是這個功能的重點,首先從 for...in 取出值來放入陣列,後面也可以指定 if 條件另外限制陣列值,符合 if 條件式的才放入陣列。

‧let 敘述
- let 敘述 / 區塊, 定義

在一個特定的範圍定義變數的值,就類似結界那樣,超過此範圍後設定無效,效果只在範圍內。當然也可以作用在一行,不要加中括號後面直接跟著一段敘述就可以了。



let 定義比較特別,用法跟 var 其實差不多,不過它只作用在一個指定的小區塊,比方說下面兩個例子:



第一例告訴我們可以在一個區塊內暫時更改變數值,範例中 let 被 if{ } 包住,故作用區塊就是這一塊。第二例告訴我們用在迴圈的 let 非常方便,不會影響到外面的變數,可以在獨立的環境中安心使用變數。

‧Destructuring assignment

這是個非常便利且直覺的好功能,可以直接一次對多個變數作指定,而不必再用暫時變數挪來挪去的,另外也可以在函式回傳陣列值時直接大量指定。

比較有趣的功能是可以在物件同時取得元素鍵值和資料,有點類似 PHP 的 foreach($arr as $k => $v) 那樣。



New in JavaScript 1.8:

‧Expression closures

為了實現簡單的 Lambda Function,JavaScript 1.8 簡化了這種特殊的語法:


簡單說就是省略大括號 {} 跟 return 這樣,這部分有人建議既然都改短了應該要改的更簡潔,例如 f(x) x * x; 這樣,看日後是否有修改機會。

‧Generator expressions

1.7 的 Generator 活用法,這好像還是 Python 移植過來的。類似 Array comprehensions 的做法:


這可以生成一個 Generator,每次執行 .next() 會回傳 "XX(new)" 字串。範例使用 for...in 來對其作 Iteration 的動作,可以當成陣列來處理的感覺。

‧其他
我比較期待原生支援 JSON encode/decode 方法,希望日後能內建成功。

2007/06/14

JavaScript Libraries CSS Selector Test

今天又閒晃看到個很有趣的測試。大家都知道 Web 2.0 網站有個滿重要的技術就是 AJAX (非同步 JavaScript 和 XML),也因這個技術使得 JavaScript 的地位逐漸被重視甚至上升。而開發當然有一些函式庫可以用,現在已經有很多可以選用了,第一次可能不知道從何選起吧。這裡有一個名為 SlickSpeed 的測試項目可以讓你以最現實的執行速度來做做考量。

我手上有 IE 6.0 SP2、Mozilla Firefox 2.0.0.4 (tete009 PGO Build)、Opera 9.21 和新的 Apple Safari 3 beta,就來做個測試吧。

測試環境:Windows XP Home Edition SP2, Intel Core2 Duo E6300, 2GB RAM
截圖:



簡單做個表格:

 PrototypejQueryMooToolsextcssQuerydojo query
IE6 SP21314264010606975598612
Firefox 2.0.0.4 (tete009)12423731125243233218
Opera 9.216415827613294280
Safari 3 beta76614120124797155
(Average)394.51802.25342369.252642.5266.25


結論:

  1. Safari 3 名不虛傳,確實夠快,正式版可以期待 (當然不是想它能夠普及大眾,而是又多個開發人員愛玩的瀏覽器)
  2. IE 6 果然奪冠 - 最慢的 XD
  3. jQuery 竟然這麼慢?希望未來開發團隊能最佳化。不然現實考量可能會轉用 Prototype 囉
  4. Firefox tete009 自有編譯版果然針對 JavaScript 執行最佳化。雖然這裡沒有 Firefox 官版的測試數據,不過從其他部落客的測試結果大略比較的確有差

2007/05/02

版面 Script 更新‧Ⅴ

最近才發現 Blogger 有 GData 可以玩,而且還隱藏很多秘密。

像是搜尋功能、瀏覽舊文章、訂閱 RSS / Atom 等等可以看到都有專屬的方式 (例如 /search?q=Text, /feeds/posts/default?alt=rss),Google Code 上也只有寫說 Blogger 的確有 Data API 可以用,不過那看起來比較像是 XML-RPC,我現在要講的是應用越來越廣的 GData 輸出 JSON / JSON in script

其實從訂閱文章就可以發現 Blogger 已經有提供一點東西了,例如 /feeds/posts/default 為 Atom 格式,加上 alt=rss 就變成 RSS 格式。如果網址改成 /feeds/comments/default 就變成近期所有回應的 Atom,是不是很方便啊 (還可以偶然發現 max-results 屬性控制輸出數量)。再進一步找找資料,可以發現它提供了 alt=json/json-in-script 方式,這會回傳一個 JSON 物件。後者更進一步提供了 callback 屬性設定可以直接把物件丟給指定方法處理。

如果觀看 GData 的說明,可以發現它很有條理,如此一來我們便可以傳送一些要求給 Google,而傳回來的東西我們再利用工具來分析取出想要的。在 Blogger 上我們就能作更多事情,例如剛才的 /feeds/comments/default 如果改成 /feeds/comments/default?max-results=5&alt=json 這不就是最近5個回應的 JSON 嗎?或者你可以用 /feeds/comments/default?max-results=5&alt=json-in-script&callback=showLatestComments ,利用 showLatestComments() 來接受並處理 JSON。這樣可發揮的空間更大!

其中有一個是我目前拿來用的: /feeds/posts/default/-/(類別名稱)?alt=json-in-script&callback=XXX,這可以用來搜尋同類別標籤的其他文章,說穿了就是其他類似文章的設計。只需要隨機抓取資料並排版印出即可。當然隨機重複和可能抓到自己的問題都要先解決。其他應用可以參考各項提供的參數想出其他更有趣的東西。

以下為程式碼擷取,注意這本來是一個物件,我將其關鍵程式碼取出,故標示方式略有差異,實際上也不能直接套用在您的部落格。純供技術展示,挑戰這樣。如果想要使用的,建議您可以利用估狗尋找其他已代為完成可直接使用的程式碼。

05/03: 改了一下隨機取出文章的方法,先生成順序的 Array 再利用 Fisher-Yates Shuffle 演算法打散, 接著依序取就不會取到重複的,就不需要再判斷有的沒的,這方法不錯,較有效率。 05/04: 突然想幫 Blogger 圖檔連結使用 ThickBox 來顯示,應該較美觀。不過試了幾遍發現 Blogger 十分機車。擋直連不說 (它的唯一可用參照頁是它產生的那個頁面...連網誌本身都不行),連用 iframe 引用都會強迫覆蓋視窗。 雖然有利用 PHP 偽造 Referer 的方式要求,不過那樣會增加使用 PHP 伺服器的負擔及流量,想想只好用原始方式,頁面載入後逐一檢查連結是否連圖,是的話更改開啟目標為新視窗。 用估狗找了一下也沒人有具體解決方法,看來目前真的是無解啦。但假使成功了,thickbox.css 會改動預設的 padding 和 margin,也是會讓我十分不爽啊。維持現況吧。

2007/03/16

裝好的 Fedora Core 被我搞爛了

我之前有利用 MS Virtual PC 2004 (已升級為 2007) 安裝 Fedora Core 5,也在其上架了伺服器以當測試環境,順便練習自己操作 Unix 系統的功力。不過最近發現 Kernel 升級到 2.6.18 以後的版本,一開機就卡在硬碟掛載 (看起來是),不過用 2.6.15 開機就沒什麼問題。同樣地,我想另外安裝新的 Fedora Core 6 虛擬系統,進入安裝介面按下 Enter 或鍵入 linux text 開始解壓 Kernel 執行後,便卡在檢查的地方 (我記得是檢查 AT 鍵盤和掛載某個檔案系統)。查一下 Kernel 是 2.6.18。而拿舊的 FC5 DVD (2.6.14 吧) 就不會卡,實在有夠奇怪。本來以為是 VPC 2007 本身的模擬問題,誰知道拿了 InnoTek VirtualBox 模擬,卻也是相同的結果? (不過 VirtualBox 效率很高,有空再介紹) 找遍 Google 似乎沒有類似的資料,只好自認倒楣收場,繼續玩 FC5 搭配舊核心。

至於搞爛又是怎麼一回事呢?由於虛擬硬碟竟然吃了 6GB 有餘,一般來說 Windows 要吃這麼多也是其他程式的影響,同理我覺得這應該是用不到的套件造成的,於是開了 yumex 把不用的套件解除安裝,誰之到重新開機後漂亮的 GDM 登入不見了,取而代之的是醜到不行的 XDM,而且輸入帳號密碼還不能進入桌面環境?(GNOME 確定裝了) 真是匪夷所思,好在 Ctrl + Alt + F1 和 SSH 遠端登入還可以用,而 http://192.168.1.5 的 lighttpd 也正常,算是不幸中的大幸。不過少了桌面感覺好像少了什麼,操作也不很方便。



另外遇過一個較為奇怪的問題是開啟 Virtual PC 2007 / VirtualBox 模擬時,有時候虛擬電腦的速度會像開了加速器一樣提升十倍有的速度,連開機都變快了 XD 問題是這樣一來輸入密碼登入只要按一下鍵盤就會跑出連續的字母 (ex: ZZZZZZZZZZZZZZZZZZ) ,叫我如何登入?用 SSH 也沒用,因為連線逾時時間也變短了,如果密碼沒在 0.5 秒內輸入完成,恭喜你連結又中斷了 囧
---
題外,版面改用 pHistory (搭配其他 Blog 元件改稱 Thistory) 作 AJAX 的頁面歷史模擬,但是要以 #res;12345678790 就能做出動作還是有點難度 (抓取回應網址沒給,只給編號沒用),所以還是著重在按下回應後,其上一頁有用這樣就夠了。另外發現先前的配置對 xxx.html 連過來看的會有問題,也一併修正。

2007/03/14

AJAX 上一頁問題 Part.2

沒想到才貼出幾小時就有迴響,感覺還不錯。昨日研究了一些函式庫後,發現其實要修補這個上一頁問題也十分容易。但坊間很多函式庫都是跟什麼大函式庫綁在一起,有殺雞用牛刀的感覺。或有的雖然不是綁在函式庫上,但是本體又大又難懂。直到真正懂了原理後,自己能作出剛好夠用的函式,處理範圍就只有歷史物件,其他的交給你自己吧!

再更詳細的談一下處理 AJAX Backward / Forward 上(下)一頁問題的關鍵:

1. 因為使用 AJAX 會造成實質上網頁沒有改位置 (location.href),因此傳統的瀏覽器歷史並無法作用。但是這時候如果改變錨點 (location.hash),卻能使 Firefox / Opera 瀏覽器的瀏覽器歷史產生改變,IE 比較奇怪,單純改變錨點是不會改動到瀏覽器歷史,不過如果有 iframe 內嵌頁框輔助,以它的頁面改變來使瀏覽器的歷史物件改變,卻能成功。因此我們可以知道以錨點或 iframe 來模擬傳統改變頁面位置的做法,進而使瀏覽器歷史又活了起來。

2. 活了之後還是沒有用。你發現雖然上一頁可以按了,但按了卻也沒效果。因為以 DOM 改變頁面元素的做法,瀏覽器歷史不會幫你還原,而傳統的頁面更換,瀏覽器卻能幫你更改頁面位置。也就是說我們只成功了一半。成功哪邊呢?瀏覽器歷史的再啟用 (Reactivate)。仔細看可以發現,按了上一頁按鈕後,頁面位置 / iframe 頁面的錨點是有改變的,假如說有個 onhashchange 事件,我們就能捕捉當 index.htm#play -> index.htm#stop 的改變時,能夠做點動作。方法是 setInterval ,以某個檢查器每隔一段時間偵測錨點改變沒,當一改變即觸動我們所謂的 onhashchange 事件。

3. 有了我們需要的 onhashchange 這種事件後,只需要在這時用一個控制函式判斷目前錨點是什麼,就可以進行對應內容。例如 #play 可能是開啟什麼資源印出來, #stop 就是把印出來的東西清掉。所有的動作全利用這個控制函式即可。連結只需要作改變錨點 / iframe頁面錨點的動作就可以很輕鬆了。

4. 來談談讓 IE 怎麼以 iframe 模擬吧。以前的做法是讓 iframe 的 src 改變,例如說 blank.htm?play -> blank.htm?stop,最近的好方法改成使用 IE 的密技,也就是打開 iframe 文件物件再關閉,這樣可以產生一個虛頁面 (頁面位置根本不存在,純為臨時創立),再改變這個頁面的 Hash 值當作記錄就可以了。當要再改變時,再開一次文件物件、關閉、設定錨點,IE 會以為頁面位置改變了,於是瀏覽器記錄就加了一筆。而按上一頁按鈕之時,錨點就會改變,成功模擬出我們要的效果。

5. 其實用這個方法又順便解決了 AJAX 沒有永久連結的設計,因為是 DOM 改變頁面元素,所以預設不會有一個 URL 資源對應目前頁面的狀態。用了 Hash 後就能成功解決。只要在頁面一載入之時把目前頁面的 Hash 丟給 3. 提到的控制函式處理,不就得了?所以 onhashchange 執行時機有二 (1. 頁面 Hash 因瀏覽器上一頁或操作而改變時 2.一開始進入頁面網址有添附 Hash 時)
---
這裡有一個簡單的範例,大家可以試試:pHistory
原始碼應該很好懂,其中註冊歷史 (pHistory.register) 是給 IE 暗中去改變 iframe 用的。關鍵就在檢查器而已。

這個範例還不支援 Safari,因為其行為較為特殊,手上也沒樣本可以觀察。

2007/03/13

AJAX 上一頁問題

最近仍然在研究 PMC2 的框架發展,話說明明用想的就很簡單,用作的卻老是做不出來。也許該像捏黏土一樣,先捏出整個外觀再慢慢修細比較好吧,一直想把某一部份搞完美了才進行下一部分,莫怪乎進度一直快不起來。 (其實也沒有具體的時程表啦)

今日來談使用 AJAX 開發網路應用程式會發生的問題:上一頁問題。其實這個問題早被談爛了,而網路上也不少解決方案,但是我為啥還要搬出來談?我自己對所謂的 Framework 其實是不很能習慣,總覺得自己寫出來的東西才能最能貼近我的需要,也因此別人用 Prototype、 jQuery 幾步驟就完成的東西,我可能要搞很久才能實作出來。

回到「上一頁」問題。AJAX 即時取得遠端資料後,即排版利用 DOM 插入於網頁之中,但頁面內容已改變。假如此一改變是像回應模式、詳細列表一類的,當使用者看完後想回到之前的頁面,卻發現上一頁沒有辦法作用,導覽功能完全被打亂了,於是乎容易造成迷失的現象。另一個有點關聯的是這些回應模式、詳細列表需要以事件驅動,使用者無法直接連往某些位置就看到,可能需要再動動滑鼠點幾下才能看到他想要的結果,如果這些頁面能夠以一個唯一的 URL 資源連結,例如 index/list 可能就是詳細列表,這樣也能讓導覽功能變得較為親和。(延伸: Taiwan.CNET.com AJAX的七項致命原罪)

一個好的 AJAX Web Application 應該要讓使用者以習慣的導覽功能來使用,所以這還是不可忽視。目前解決「上一頁」問題的方法已大致底定,統整後歸納如下:

視瀏覽器而定,像 IE 就需要另外一個 iframe 來幫助記憶瀏覽記錄,而使瀏覽器的瀏覽記錄能夠被我們所控制的關鍵是錨點 (document.location.hash) 值,這個值一旦變動,瀏覽器的瀏覽記錄便會增加記錄。但這在 IE 是例外,但如果以 iframe 輔助並改變其內頁面的 Hash 值,瀏覽器的記錄又有用了。

能操作瀏覽紀錄後,接著我們需要模擬一個 window.onback() (目前瀏覽器當然沒有這個事件,希望日後有) 偵測是否按下上一頁按鈕。很遺憾的前面說過目前沒有按下上一頁按鍵事件可以用,而頁面的 onload 又只適用於初次載入 (也就是說後續使用 DOM 修改頁面、更動 Hash 值都不會再觸發 onload 事件)。所以我們需要設一個 Listener,定期偵測瀏覽記錄記載的的 Hash 改了沒。可用的方法就是 setInterval 定期執行檢查 (例如每 100 毫秒),當瀏覽記錄的 Hash 變了 (比方說從 index.htm => index.htm#list) 就是 window.onback() 模擬事件的執行時機。

最後,在我們做的這個 onback 事件被驅動之時,需要作一個控制函式,利用目前頁面的 Hash 完成某些特定動作。例如上面的 index.htm -> index.htm#list,抓取目前的 document.location.hash (=#list),並執行對應的動作 (如 JavaScript: GetList()),這樣不但可以模擬出上一頁效果,也可以利用 index.htm#list 這個 URL 資源直接連結到顯示詳細列表的功能了。

要說一下的是,最後提到的控制函式類似中央集權,所有的 AJAX 相關操作通通給他掌權,那觸動的超連結或按鈕只需想辦法改變瀏覽記錄的 Hash 即可 (直接連結至錨點 / 修改 iframe 錨點),例如 <a href="#list" rel="ajaxlink" onclick="setHistory(this.href.replace(/^.*#/, ''));"> List </a>。如果嫌每個連結都要加入修改 iframe Hash 事件太煩,可以利用 window.onload 搭配超連結尋找特定 rel 值標記來辨識各連結物件並動態增加 onclick 事件。

值得一提的是以往的舊方法需要 iframe 連結至一個 blank.htm 並傳遞參數以記錄相關資訊,現在的做法多直接把 iframe 當成一個畫布般,對其初始化後直接修改頁面 Hash。方法如下:


var iframe = document.getElementById('ieHistory').contentWindow.document;
iframe.open(); iframe.close();


只需開啟文件後再關閉即達成初始化動作,就可以當作一般網頁自由修改 Hash 值而不必再用一個頁面來模擬。
---
最後,我嘗試一下 jQuery.history 的功能,幫這個頁面的回應模式加上了上一頁模擬,如果你按了[回應]觀看文章全文及回應後,可以再按瀏覽器上一頁回到文章瀏覽模式。

2007/02/23

備忘: Windows Compatibility Layer

看到網路上常見的 LocaleStart.vbs (作者網站) 沒有直接叫用 AppLoc.exe 而是用其他方式感到好奇 (我發現的有點晚,沒想到已經 Lag 快三年),無意中發現 Windows 的一套相容性階層操作,可以搭配 BAT / JS / VBS 來自訂化執行程式,方便的很。

先引用幾份資料:
  1. Script Compatibility Layers tip
  2. 如何:在 Windows XP 中撰寫相容性階層指令碼
  3. NLS information page
Windows XP中新增了一套相容性階層 (但我曾經在 Windows 2000 的光碟中發現改相容性小工具,那應該是最早的實作) 。而後來強化這套相容性階層,作了 AppLocale 這個公用程式。這個公用程式主要強化相容性階層,新增了一個參數 #ApplicationLocale (其餘參數請參考資料 1.)。設定方法呢,是在系統的環境變數內設定的 (常見的有 PATH, WINDIR 一類的,命令列執行 set 列出) ,有一個 __COMPAT_LAYER 的變數呢,就是相容性階層的設定。

假如今天在命令列下了 set __COMPAT_LAYER=Win98 640x480,即會將目前的相容性階層設為 Win98 相容, 解析度 640x480 模式。而後以命令列執行各類程式都會依照 __COMPAT_LAYER 的設定,由系統層面來作相容性的處理。

安裝了 AppLocale 後,__COMPAT_LAYER 新增了參數 #ApplicationLocale。於是要讓非 Unicode 程式使用指定字碼表的方法也很簡單,先 set __COMPAT_LAYER=#ApplicationLocale,再 set AppLocaleID=(字碼表LCID) (LCID 請參考資料 3.),這樣執行程式系統層便會以這些資料來作適當的轉換以完成工作。所以說 AppLoc.exe 也只不過是一個設定環境變數的工具,其實我們也可以手動設定的。(注意一下,若是 __COMPAT_LAYER 有多個設定,請以空格隔開。如果有包含 #ApplicationLocale,務必讓他排在第一順位,執行才會正常)

總結一下,如果要開啟 C:\test.exe 並以 Win2000 相容性模式、簡體中文字碼表的方式啟動,則在命令提示字元依序下以下指令即可:


set __COMPAT_LAYER=#ApplicationLocale Win2000
set AppLocaleID=804
C:\test.exe


附:以下是將原 LocaleStart.vbs 改寫成 JScript 形式的練習:

容我在這說幾句:WScript 的 JScript 跟網頁上常用的 JavaScript 有些不一樣,應該是版本的問題。前者不但 Array 是使用 () 而非 [],Array 也沒有 .join() 等方法,有點難以適應。

2007/02/12

版面 Script 更新‧Ⅳ

我得承認本網誌幾乎跟 ACG 沒有關係了 XD
雖然我很想寫點什麼,不過你知道的,嗯,寫點技術文章似乎比較爽,
而且遊戲我也玩不多、動畫、漫畫、小說也看不多,音樂是有在聽不過也很少量。
所以呢...哈哈 (裝傻)

不多說,最近發現 Google Pages 載入速度慢的跟什麼一樣,本來想說連日本比較遠,
把原本放 Cool 的一些東西丟到 Google Pages 上以加快速度 (美國 + 即時 Gzip 壓縮傳輸)
結果沒想到光 Ping 就慢很多,尤其現在版面可說是中量使用 JavaScript (哪天會變成大量呢?)
光基本載入的函式庫就有主函式庫、Trip生成函式庫 (DES編碼)和 XMLHttpRequest 函式庫。
最近又加上 dp.SyntaxHighlighter,這樣就算了。它還需要其他 Brush檔案 (ex: shBrushPhp.js)
萬一需要標亮的程式語言繁多,就不得不每個都載入。
假如版面剛好只用一兩個時,那又怎麼辦?每次都全部載入豈不耗時又耗頻寬?

於是首要之務先輕量化 Trip生成函式庫,原始檔案從日本網站弄下來的,
把它改成能通過 JSLint 檢測,再以 JSMin 壓縮,果然小多了。

再者修改 dp.SyntaxHighlighter,我打算讓它以動態需求載入的方式來運作。
首先會先查看各個 <textarea> 是否為目標,然後再取出其 class 值來判斷需要載入類型。
節錄自 mainscript.js:


以 e.getAttribute('name') 或是 e.name 來判斷是否為需要自動標亮的欄位,
而以 e.className 來取得 class 設定 (如 php, c++, js)。
這邊有一個怪處,單純用 e.getAttribute('class') 看來似乎可以達成,事實上 IE 會失敗。
IE有自己的一套 e.getAttribute('className')。這個地方讓我除錯除了好幾小時找不出原因。
這邊使用 W3C DOM 節點都有的 className 屬性直接取來判斷,是各個瀏覽器都支援的手段。
取出屬性後我拿去和建立好的別名資料庫陣列作比對,例如 alias['Cpp'] = ['cpp', 'c', 'c++'],
如果我取出 c++ 一值,那我就知道得去載入 Cpp 這個刷子 (shBrushCpp.js),而後續就不必再載入,
所以刪除這個別名資料庫 (用 delete 關鍵字)

後續的動態載入需要利用 DOM 的 document.createElement 方法,
動態建立 script 標籤並載入我們需要的函式,程式碼一樣節錄如下:


產生了一個 sc 物件後,設定好相關參數,就把它附加到 <HEAD> 標籤之下,
這個是 DOM 的節點觀念,可以多利用 Mozilla Firefox 的 DOM 觀察器 來看看。
最後一個 Interval 又是怎麼一回事?因為我不知道這些標籤產生之後,是否已經讀取完畢,
只好設定一個計時器定期查看載入狀況,等全部都準備好再執行標亮步驟。



我使用判斷 dp.sh.Brushes[XXX] 是否為函數的方法來確認,如果 dp.sh.Brushes['Php'] 為函數,
我就知道它必定載入完畢可供我使用了,而當確認載入完畢便將其自載入列表中移除。
這個列表是剛才用來以迴圈逐個載入的,這邊只是再做一次利用,以刪減方式標記哪些已載完。
沒意外的話最後只會剩 Core 一項,這一個是特別的存在 (核心)。
故把陣列串起來之後如果為 'Core' 便表示其他函式庫皆已載入完畢,刪除計時器,執行標亮吧!

至於判斷途中使用 try 的原因是因為你不能保證 shCore.js 會優先載入完畢,
如果他沒有載入完畢,後面的刷子是無法掛載的,便會產生 dp 變數未定義錯誤警告。
於是使用 try 無視錯誤,反正一定會有載入好的一天 (檔案確實在的話)。
當真正載入完成了,其他刷子檔便可以正確掛載,也就能從載入列表中刪除了。
假設所有刷子檔皆已載入完成,唯獨 shCore.js 因為某些因素尚未載入完成 (前提是確實存在)
因為有 try 加持,即使 dp.sh.Brushes[XXX] 確實存在,但因為 dp 未定義錯誤,便不會去執行刪除而略過。

至此完成動態載入的工程。