使用JSCookMenu碰到的小問題

 Wed, 06 Jun 2007 16:03:05 +0800

JSCookMenu是一個相當容易用的JavaScript Base選單程式,可以很簡單地用陣列來製作選單,支援不同的佈景主題,作者也持續有在更新(目前最新版本到2.0.3)。

作者的網頁裡面有詳細的說明:http://jscook.yuanheng.org/JSCookMenu/

最近使用上卻遇到一點小問題,就是選單有時會失靈....花了一些時間嘗試,發現了一點小問題,問題發生在防毒軟體、瀏覽器toolbar上面的攔阻彈出視窗功能。

JSCookMenu用cmItemMouseUp函數來處理mouseup動作,click之後的處理也是用到這一個函數。這個函數中處理link的方法大致如下:

if (link != null)
{
_cmClicked = false;
window.open (link, target);
}

Symantec Internet Security 2006(我的筆記本預裝的防毒軟體)會在網頁中自動加上一段JavaScript,用來攔截彈出視窗:

function SymError()
{
return true;
}
window.onerror = SymError;
var SymRealWinOpen = window.open;
function SymWinOpen(url, name, attributes)
{
return (new Object());
}
window.open = SymWinOpen;

結果就是window.open被攔截了,當然無法使用。先嘗試用幾個方法來對付,在firefox下global scope的變數會放在window物件中,所以可以用這樣的方法來試探究竟window.open被改到哪裡去了(不直接使用SymRealWinOpen變數,是因為希望對所有用這個方法封鎖彈出視窗的方式都可用),然後再把他改回來:

for (obj in window) {
str1 = "";
str1 += obj;
str2 = "";
str2 += window[str1];
if (str2.indexOf("function open()")>-1) {
//懶得用re,先用indexOf比較快
window.open = window[str1];
}
}

很可惜,這個方法在ie7裡面沒有作用....似乎ie7的javascript引擎並沒有把global scope的變數放在window物件中....(沒仔細測試,但是至少用firefox可行的方法出不來)

後來試用了一下google toolbar,發現他根本不依靠javascrpt來攔阻彈出視窗,所以即使用window.open=SymRealWinOpen也沒用,照樣攔截。這樣JSCookMenu就會有問題了....

袁衡的JSCookMenu支援可以在click選單時依照target指定的目標來開啟連結,通常的應用是指定"_self"來在原來的網頁視窗開啟,指定"_blank"開啟新視窗,指定其他的目標(frame、iframe等等)則會在相應的目標開啟。光用window.location.href=link沒辦法支援這麼多應用。

後來想到一個方法理論上可以兩全其美(還是有缺點,後面會提到),就是form。因為form一樣有target屬性,可以利用這個方法來彈出新視窗也不會被攔阻。我稍微改了一下JSCookMenu的程式:

if (link != null)
{
_cmClicked = false;
tmp = document.createElement("form");
//動態產生form物件
tmp.target = target;
tmp.method = "post";
//用post方法網址尾巴才不會出現?
tmp.action = link;
document.body.appendChild(tmp);
tmp.submit();
//送出post
document.body.removeChild(tmp);
delete tmp;
//form不用了,把他移除
}

試了一下,果然可以動了。不過因為是用post,連結的網頁必須避免錯誤處理這個post,另外有一些網站還是可能用referer來攔阻不恰當來源的post,也有可能有問題。我在寫的東西全部在自己網頁裡,就不需要擔心了:D

另外需要考慮的是動態改動node tree其實是會給瀏覽器帶來一些額外的負擔,比較起來用window.location.href=link速度的確快了一些。不過因為原本的目的就是要跳到不同的網頁或是開啟新視窗,所以這樣的延遲就比較不要緊了。

其實並沒有測試過所有的彈出視窗攔阻程式,所以不一定都可以通過啦。我還有注意到,用滑鼠右鍵點JSCookMenu選單時,會被google toolbar攔截.....不過用左鍵點選沒問題。感覺google toolbar攔阻的policy似乎必須用滑鼠左鑑,並且用form來開新視窗才能通過的樣子。