|
|
||
IRC: irc://irc.opera.com/japanese <--Opera 日本語ユーザのためのIRCチャンネル。
上のがつながらない場合は irc://irc.se.opera.com/japanese
この前 Kuruman が悩んでた問題*1.私の方でもその現象に遭遇したので検証してみる.
Opera でのみ起こった現象. Firefox では問題なし.
原因はどうもなんか新しいことがあったらページ上部に表示される
これのようだ.
これを消したければ もちろん hide this をクリックすればいいわけだけど,クリックしたときにどういうことが行われているかというと
function hideNotifyBar() {
Cookies.set('notifications_seen', Cookies.get('notifications_seen') + ',17');
(new fx.Height(
$id('notifybar'), {
duration:20,
onComplete: function(){ remove($id('notifybar')) }
}
)).toggle('height');
return false;
}
addLoadEvent(function() {
if ($id('notifyclose')) $id('notifyclose').onclick = hideNotifyBar;
});
この スクリプトでわかるように hideNotifyBar() が呼ばれている.
一度 hide this が呼ばれるとクッキーに保存されて以降このコード自体がソースに含まれなくなる.
ちなみに オブジェクト fx は定義されている javascript ファイルがロードされていないのでエラーとなる.これは今回とはまた別の問題.
今回問題なのは hideNotifyBar をイベント追加している addLoadEvent 関数.
これを定義しているのが http://del.icio.us/ui/static/delicious.old.js?v=61E-123 のスクリプト
どういう風に定義しているかというと
function addLoadEvent(f) { var old = window.onload
if (typeof old != 'function') window.onload = f
else { window.onload = function() { old(); f() }}
}
となっている.
つまり addLoadEvent で追加された関数は window.onload に追加していくという関数である.
ロードされたときに実行されるべきのは
となる.
どういう風に実行されるかをわかりやすくするためにテストページを用意した.
http://higeorange.com/tmp/testLoad.html
注意: alert が出る.
このページのソースは
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title></title>
<script type="text/javascript">
addLoadEvent(function() {
log("first is loaded");
});
function init() {
log("init is loaded");
}
function addLoadEvent(f) {
var old = window.onload;
if (typeof old != 'function') {
log("old is not function, " + 'add: ' +f);
window.onload = f;
} else {
log('old: ' + old + ', add: ' + f);
window.onload = function() {
old();
f();
}
}
}
function log(s) {
alert(s);
}
</script>
</head>
<body onload="init()">
<script type="text/javascript">
addLoadEvent(function() {
log("second is loaded");
});
</script>
</body>
</html>
となっており,
del.icio.us と同じように
body onload で init,
head 内の script で addLoadEvent で追加 (rmPostAddEvent にあたる) 実際には外部ファイルで呼び出しているけど同じはず 以下 first,
body 内の script で addLoadEvent で追加 (hide this にイベントを付加する関数にあたる) 以下 second,
としている.
でこれを Opera と Firefox 実行してみると違いが出た.
以下 alert の内容を列挙.
old is not function, add: function() {
log("first is loaded");
}
old: function() {
log("first is loaded");
}, add: function() {
log("second is loaded");
}
first is loaded
second is loaded
old is not function, add: function () {
log("first is loaded");
}
old: function onload(event) {
init();
}, add: function () {
log("second is loaded");
}
init is loaded
second is loaded
これから分かることは
window.onload の内容は
Opera: なし -> first (head内) -> first & second (body 内) あれ init はどこで追加されたのよ?
Firefox: なし -> first -> init -> init & second
と変化している.
実際に実行されるのが
Opera: first & second
Firefox: init & second
となる.
この結果から Opera では タグが表示されないのである ( init が呼ばれないため ).
また Firefox でも意図通り動いていない気がする.
このバグを直すためにスクリプトを書いた.
// ==UserScript==
// @include http://del.icio.us/*?*url=*
// ==/UserScript==
//
(function() {
opera.defineMagicFunction(
'addLoadEvent',
function(func, w, f) {
var old = window.onload;
if (typeof old != 'function') {
window.addEventListener('load', f, false);;
} else {
window.onload = function() {
old();
f();
}
}
}
);
})();
最初に追加される rmPostAddEvent を window.addEventListener で追加. window.onload が undefined であるとき
これで不思議なのが 2回目に addLoadEvent が呼ばれたときには window.onload に init が入っている.入っていないとこのスクリプトは動かないわけだが.
だったら直す前でもこの時点で init が入っててもおかしくないのになぁ.
ということで追加の順番に関してもう少し検証が必要.
とりあえず 上のスクリプトでタグが表示されないバグは直る.
お知らせが出たら hide this を押したらいいんだけども.
Konqueror は Firefox と同じ挙動.
IE & Safari での動作を知りたいので
http://higeorange.com/tmp/testLoad.html
において誰かテストお願いします.
Thx. os0x.
os0x さんのコメントどおりの挙動だとさらに疑問が.
second がなかった場合を考える.
window.onload の内容.
Opera 以外のブラウザ: first -> init
Opera : first -> init は追加されず.
実行結果
Opera 以外のブラウザ: init() 予想通り
Opera : init() あれ? first が実行されるのでは?
テストページ
http://higeorange.com/tmp/testLoad2.html
どうも混乱してきたのでこれで打ち切り.
<body onload="init()"> ってしてるのがまずいだろうな.
てことで del.icio.us に報告しておきました.
再追記で書いた second がなかった場合の挙動について多分分かった.
【javascript】body.onload=””とwindow.onloadについて|WEB制作のメモ
window.onload と document.body.onload が両方あった場合あとから追加されたほうが実行されるということ.
で、Operaさんは document.body.onload だけにinitが入っているみたいです。
この挙動から推察するには、bodyタグにonloadがあったらとりあえずdocument.body.onloadに入れて、window.onloadがnullだったらそっちにも入れる。けど、window.onloadがnullでなかったら上書きはしないようになってるぽいですね。