JavaScriptの最近のブログ記事

だから JavaScript って嫌い。完全に備忘録として。

一個目。
uebu: JavaScript trouble shootingより。

onClickで関数をコールすると、
「オブジェクトでサポートされていないプロパティまたはメソッドです」
→ 関数名と同名のフォーム要素がある。

こんなん知るかボケ。めっさハマったつーの。


もう一個。

beginners CGI  - 有効期限を省略したCookieは保存されない -
より。

通常はテキストファイルとしてハードディスク上に保存されますが、
有効期限を省略した場合、ハードディスク上には保存されず、
ブラウザを閉じると無効になります。(開いている間のみ有効)
Cookie の発行や読み出しのテスト、確認などをする際有効期限が無いと実際のクッキーデータをテキストエディタで開いて確認する事ができませんので、必ず有効期限をつけましょう。

これって IE 限定っぽくて、IE で有効期限を省略した Cookie を確認しようとして、キャッシュの中をどんなに探しても見つからないという。てっきり Cookie 生成に失敗したかと思ったぞコラ。

クライアントからの報告で初めて知ったIEの不具合っぽい現象。 「Windows Update をしたらFlashが表示されなくなったんですか・・・」と。 Adobe公式サイトから最新版のFlashPlayerを入れなおしてもダメなんだそうで。。 色々と先方の環境を聞いてみたところ、SWFObjectはダメで、Adobe公認のAC_RunActiveContent.jsの場合は問題なし。 これって SWFObject のバグ?かと思いながらもさらに調査。 すると、どうもブラウザから FlashPlayer のバージョンを取得できないのが原因。 SWFObjectの場合、こんな感じにして、コンストラクタ引数の5番目で対象バージョンを指定できるんだけど、それに満たない場合は HTML 置換が行われないのは周知の事実。
var so = new SWFObject("test.swf", "movie", "400", "200", "8", "#FFFFFF");
その内部処理において、FlashPlayerのバージョンをJSで判断してるようで、今回の不具合の場合はそれが取得できないらしく、結果としてFlashが表示されないみたい。 試しに次のコードで単体テストをしてみたら、先方の環境でやっぱり取得できませんでした。。
var version = 0;
var isIE = (navigator.appVersion.indexOf("MSIE") != -1) ? true : false;
var isWin = (navigator.appVersion.indexOf("Windows") != -1) ? true : false;
if(navigator.plugins["Shockwave Flash"]){
	var tmp = navigator.plugins["Shockwave Flash"].description.split(" ");
	for(i=0; i<tmp.length; i++){
		if(!isNaN(parseInt(tmp[i]))){	version = tmp[i];}
	}
}
else if(isWin && isIE){
	version = new ActiveXObject("ShockwaveFlash.ShockwaveFlash").FlashVersion();
	version = Math.floor(version / 0x10000);
}
alert(version);
参ったなと思って調べてみると、SWFObject のフォーラムで同様の現象が報告されて議論されてます。 deconcept › Corrupt Flash Player install after IE 7 upgrade この問題はIE7自身よりも、WindowsやIE、FlashPlayerのアップデートに生じる問題だそうで、FlashPlayer更新の際に過去の古いバージョンを消せずにインストールするからっぽいです。 複数のPlayerがあるからバージョンが取得できないんでしょうか。
解決方法としては、
1. Quit all open programs. This step is important because other programs may be using the Flash Player, and if they are, the uninstaller will fail silently.
2. Run the Adobe Flash Player Uninstaller.
3. Reinstall your Flash player.
と、一度アンインストーラで完全に削除してから再インストールすればよいようです。 クライアントにその旨を伝えて、試していただいたところ、無事修正完了っ!やったっ!! まったくマイクロソフトさん、困ります~ ・・・でも、フォーラムでそれでも直らない、という報告があるのが気になるぅ~ ちなみに、SWFObjectの作者の人、今 YouTube の中で働いているんですね。スゴいなぁ。 YouTubeにも同様の現象の人のためのページがありました。 YouTube - Broadcast Yourself.- The video won't play—what's wrong? + Video たまにはタメになりそうなエントリを。

[ 追記 2008/02/22 ]
メディアテクノロジーラボさんの方でもっと詳しい点をまとめていますので紹介します。 ActiveX とはみなされないからなんですってね。うーむ、わからん・・・。
IE7でswfobjectが動作しない件 : Media Technology Labs (MTL) : メディアテクノロジーラボ ブログ

今携わっている案件で、JavaScript の document.referrer 使ってリファラで処理分岐をしてたんだけどハマったよウフ☆
調べたところ、Windows IE に限って、Flash の getURL() あるいは JS の location.href を使ったページ遷移でリファラが無視されるっぽい。凄い仕様だよー

回避策として、Flashで遷移する瞬間リファラのような cookie を作ってからページ遷移して、遷移後のページのその cookie を削除するという。これは厳密に言うと F5 リロードに無防備だけど、そこまで責任もてるかコラ~

ExternalInterfaceって匿名関数とかいけるのかなと思って試してみたら案の定いけちゃった。
これって、HTMLや外部JSファイルなどに定義する必要がなくなるって考えられるから素敵。将来のコンテナ拡張はあれだけど・・・。

Flash側でこんなカンジで記述。

import flash.external.*;
var js:String =  "function(){alert('Hello World!');}";
ExternalInterface.call(js);
たしかにアラートが表示されるっ・・・!!
今のところFirefoxとIEで動作確認済み。

すごい昔に同じような手法で、Flash側からコンテナHTMLのテキストを隠すというSEOをやったことがあって、それはJavaScriptのコードもFlashのフレームアクションに文字列として定義してgetURLで実行という手法だったんだけど、ExternalInterfaceでも問題なくいけるのね。

ブラウザの挙動全部見てないからクラスパッケージ化するかは微妙だけど、Firefox2の日本語パス問題の解決に使えそうだなコレ。

ActionScriptもJavaScriptも、どっちもECMAScriptに準拠していているから、コアな部分ではほとんど同じだろうと思っていたら、ハマった・・・(MacIE)。

いつもASでやるように、
var a = new Array();
a.push({b:1, c:"22", d:333});
とやったらエラー。
Google先生曰く、「MacIEはArrayクラスでpushをサポートしてねぇ」だそうで。マジすか。どうもWinIE5.0あたりもそうみたい。
結局、pushは使わずにすることでクリア。

で、SWFObjectのソースを読みまくっていたら、こんな記述が(インデントなどはこちらでつけたもの)。
if(Array.prototype.push == null){
	Array.prototype.push = function(_31){
		this[this.length] = _31;
		return this.length;
	};
}
MacIEなどではArrayのpushを自作しているのか!
すごいっ!すごすぎる!!
すかさずprototype.jsはどうなってんだろうと思って調べたら、こっちも同じくサポートしてるっ!

SWFObjectにしてもprototypeにしても、先人は凄いなぁ。
ホント勉強になりまっす!

[ 2006/12/8 追記 ]
prototype.jsのソース見たり、いろいろ検索してみたら、prototype.jsでもサポートしていないっぽいです・・・。prototype.jsってIE6からを対象にしているようですね。
ウェブ人間(きっと)みんな大好きSWFObjectについて、一個だけ注意しなくてはいけないことが。対象バージョンに達しない場合、HTML置換が行われないというヤツ。 たとえば、
var so = new SWFObject("test.swf", "test", "550", "400", "8", "#FFFFFF");
so.write("content");
とすると、Player8以上では表示されるけど、7以下ではHTML置換が起きないので、置換対象タグが空だと何も表示されないという・・・。 これを防ぐためには、上記コンストラクタにリダイレクトURLを引数で渡すことでカスタムエラーページをつくることができるんだけど、他に何か方法ないかとおもって解析してみたら、SWFObjectインスタンスのプロパティで分岐させればいけたっす! SWFObjectのインスタンスは installedVer というObject型のプロパティ持ってて、そこに現在ブラウザにインストールされているFlashPlayerのバージョン情報を格納していると。それをif文かましたサンプルはこんな感じ。
var so = new SWFObject("test.swf", "test", "550", "400", "8", "#FFFFFF");
if(so.installedVer.major >= 8){
	so.write("main");
}else{
	var e = document.getElementById("main");
	e.innerHTML = "(ここにDLページへのリンクなど)";
}
so.installedVerには、major, minor, rev というプロパティがあって、それぞれメジャーバージョン、マイナーバージョン、(revって何の略?)。すべて数値型で文字列じゃないので余裕で比較可能。 うーん、SWFObjectって便利すぎ。ヤバい。作者、頭よすぎだわ。 ExpressInstallを使うなどいろいろあるけど、当分はこれでいこうかな~。