古いIEだとAjaxのUserAgentが変わるので、CakePHPでセッションが切れてしまう

2010.02.01    CakePHP, IE, javascript, 馬場      baba   

CakePHPでjQueryを使ったAjaxを実装した際、IEの古いバージョンでのみエラーになる現象に見舞われました。
調べてみると、Ajaxリクエストを送った際にログインが切れているようです。

どうやら原因は、CakePHPのユーザエージェント検証機能でした。
app/config/core.phpで

Configure::write(’Session.checkAgent’, false);

を設定することで解決しました。

つまり、古いIEでは、通常時のリクエストとAjaxリクエストで、ユーザエージェントが違う、ということですね。
これはたぶん、歴史的な理由からXMLHttpRequestがActiveXオブジェクトで実装されていることに由来するのでしょう。

以下に、各ブラウザで確認したユーザエージェントを書いておきます。
PHPで、$_SERVER['HTTP_USER_AGENT'] を表示しています。また、Ajax通信は、jQueryの$.ajax()を使っています。

■Firefox 3.5.6
通常: Mozilla/5.0 (Windows; U; Windows NT 6.1; ja; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 (.NET CLR 3.5.30729)
Ajax: Mozilla/5.0 (Windows; U; Windows NT 6.1; ja; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 (.NET CLR 3.5.30729)

■Chrome 4 beta
通常: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.0.249.64 Safari/532.5
Ajax: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.0.249.64 Safari/532.5

■IE8
通常: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; .NET4.0C; .NET4.0E)
Ajax: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; .NET4.0C; .NET4.0E)

■IE7
通常: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; .NET4.0C; .NET4.0E)
Ajax: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; .NET4.0C; .NET4.0E)

■IE6
通常: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 6.1; WOW64; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; .NET4.0C; .NET4.0E)
Ajax: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; .NET4.0C; .NET4.0E)

JavaScript 第5版

Ajax開発を行うにあたり、昨日の「Java開発者のためのAjax実践開発入門」の次に購入した本がこれです。

JavaScript 第5版

著者/訳者:David Flanagan

出版社:オライリー・ジャパン( 2007-08-14 )

定価:¥ 4,410

Amazon価格:¥ 4,410

大型本 ( 704 ページ )

ISBN-10 : 4873113296

ISBN-13 : 9784873113296


完全にJavaScriptのリファレンス的な本です。700ページ近い厚さも威厳があります。

こんなに分厚い本を最初から読んでも仕方ないので、必要なときに参照できる場所に置いておくと便利です。
スクリプト言語らしく、若干言語仕様の理解が曖昧でも動いてしまうJavaScriptですが、本書が手元にあれば、分からない点をすぐに解決できます。

オライリーらしく、内容が濃くてきっちり書かれているので、リファレンスとして最適です。

読んでいて感動は無いですが、無いと困る本です。

Java開発者のためのAjax実践開発入門

・週2冊のペースで読書を進めている
・毎日ブログを更新する

この2つの目標を同時に達成するには、読書ネタだけだと間に合わないという事実にようやく気がつきました;;

私は社長ほど面白い文章、ためになる文章を書けないので、開発TIPSや雑誌・技術書などで気になったポイントの紹介などもやっていきます。

今回は、私がAjax開発を始める際に使った本を紹介します。

Java開発者のための Ajax実践開発入門

著者/訳者:河村 嘉之 川尻 剛 福沢 知海

出版社:技術評論社( 2007-11 )

定価:¥ 3,570

Amazon価格:¥ 3,570

単行本 ( 447 ページ )

ISBN-10 : 4774132977

ISBN-13 : 9784774132976


「Java開発者のための」と謳われているだけあり、入門書にありがちな同じ説明の繰り返しが省かれているのがポイントです。
「そもそもオブジェクト指向とはなんたらかんたら」ではなくて、「Javaとここが違う。この機能はJavaで書くとこうなる」と説明されているので、すんなり理解できます。

JavaScriptに入る際に躓きやすい、メソッドチェーンとプロトタイプチェーンも分かりやすい図で解説されています。

ただ、5章以降はフレームワークや開発環境の解説になるので、実質的に使ったのは2~4章のみです。
さらに、DOM APIとXMLHttpRequestも概要は把握していたので、本書を読んで良かった!と感じたのは2章がほとんどでした。

そう考えるとコストパフォーマンスは悪いですが、手っ取り早くJavaScriptアレルギーを克服できたので、満足しています。

JavaScriptって便利ですね

JavaScriptってあまり好きじゃないけど便利なものありますね。
先達者の皆様にいつも感謝です。

中でも普段の受注制作で使えそうで、
個人的に興味がある/好きなもの紹介してみます。

Anything Slider
http://css-tricks.com/examples/AnythingSlider/#panel-5
画像とか動画とかスライドできちゃいます。
ちょっとした“魅せ”にはいいですよね。
以外と感動してくれるお客様もいそうです。

CakePHP×FCK Editor
http://d.hatena.ne.jp/slywalker/20081125/1227621414
CMSで自由に画像を加えたりフォーマットをいじるためには、
HTMLを許容したり自由度を下げたりしないといけないですよね。
WordPress-likeなエディタUIを加えてあげることで
編集しやすいCMSをつくるのもいいですよね。

クロスドメインDojo

Dojoは、デフォルトでは読み込み元HTMLと同じサーバに置くことを前提に作られています。
具体的には、dojo.require()が、XMLHttpRequestを使ってデータを取得します。

このため、同じドメインにライブラリを設置できない場合(共有サーバで権限が無い時など)、クロスドメインの制限でdojo.require()が失敗してしまいます。
dojo.parserなどの内部でrequireを使っているため、ライブラリの読み込み時点でエラーが多発してしまいます。

この場合は、クロスドメインビルドをしたdojoライブラリ(XDomain Dojo)を使用します。

方法1: AOLを使用
お手軽に使うには、AOLのCDNを活用します。
http://dev.aol.com/dojo に書いてあるように、以下の形式でdojoライブラリを読み込むだけでOKです。

<script type=”text/javascript” src=”http://o.aolcdn.com/dojo/1.3/dojo/dojo.xd.js”></script>

この場合、dojo.requireは、デフォルトで用意されているdojo, dijit, dojoxのみ使用可能で、自前のコンポーネントは使用できません。

方法2: クロスドメインDojoのビルド
方法1はお手軽ですが、AOLのサーバが重いとか、自前で設置したいこともあると思います。
その場合、Dojoをソースからビルドします。

  1. ソースを入手
    まず、Dojoのダウンロードサイトから、ソースを取得します。dojo-release-1.3.0-src.zip のように、srcが付いているものがソースです。
    ダウンロードサイト: http://download.dojotoolkit.org/
  2. ビルド
    そして、以下のページの手順に従い、ビルドします。
    ビルドの手順: http://www.dojotoolkit.org/book/dojo-book-0-9/part-4-meta-dojo/package-system-and-custom-builds

    具体的には、以下のコマンドでビルドできます。(Linuxの場合)
    xdDojoPathに、Dojoライブラリを設置するディレクトリ名を記述します。テスト環境と本番環境ではURLが違うと思うので、その場合は2回ビルドする必要があります。
    パックするライブラリを変更したい場合は、profileを変更します。

    $ cd util/buildscripts
    $ build.sh profile=standard loader=xdomain xdDojoPath=http://www.bpsinc.jp/dojoxd action=release

    以上のコマンドを入力すると、ビルドが始まり、しばらくするとreleaseフォルダにXDomainビルドされたDojoが生成されます。

  3. 設置
    xdDojoPathに設定したフォルダに、dojoを設置します。
    上記の例では、DocumentRootのdojoxdフォルダに、dojo/dijit/dojox が入っている状態になります。
  4. 読み込み
    あとは、

    <script type=”text/javascript” src=”http://www.bpsinc.jp/dojoxd/dojo/dojo.xd.js”></script>

    のように読み込めばOKです。

dojoの細かいTIPS

dojo使いには当たり前かもしれない、ちょっとしたTIPSです。

(1)dojo.byId
dojo.byIdは、HTMLのエレメントを渡すと、そのまま帰ってきます。
つまり、dojo.byId(dojo.byId(’hoge’)); とやっても正常に動作します。

なので、dijit等で「ノードのIDを渡す」と書かれているところに、直接エレメントを渡しても、たいてい上手く動きます。
動的に要素が増えてIDを付けにくい場合などに、ちょっと役立ちます。

(2)dojo.query
dojo.queryは、CSSのセレクタで要素を選択できる便利なものです。
この第2引数にHTMLのエレメントを渡すと、その子要素のみ検索対象になります。

var img = dojo.query('img', hogeNode)[0];

基本かつ必須な機能のはずなのに、なぜか解説サイトにあまり書いていないという。。

(3)dojox.layout.ResizeHandle
ドラッグ&ドロップはサンプルがたくさんあるのに、リサイズはなぜか少ないですね。
dojoはリサイズも簡単なので、以下にサンプルを載せておきます。

<html>
<head>
	<script type=”text/javascript” src=”dojo/dojo.js”></script>
	<script type=”text/javascript”>
		dojo.require(’dojox.layout.ResizeHandle’);
		dojo.addOnLoad(function() {
		var handle = new dojox.layout.ResizeHandle({
		activeResize:true,
		minWidth:30,
		minHeight:30,
		targetId: ‘box’
		}, dojo.byId(’handle’));
		});
	</script>
	<link rel=”stylesheet” href=”dojox/layout/resources/ResizeHandle.css” />
</head>
<body>
	<div id=”box” style=”position:relative; background:yellow;”>
		<p>リサイズできます</p>
		<div id=”handle”></div>
	</div>
</body>
</html>

↓動作サンプル


リサイズ可能

JavaScriptでCSSのプロパティを削除する(IEでfilterがあるとClearTypeが無効になるバグ対策)

javascriptからCSSを変更したい場合は、

//生
var node = document.getElementById('hoge');
node.style.marginLeft = '10px';

//dojo
dojo.style(dojo.byId('hoge'), 'marginLeft', '10px');

といった感じになります。

しかしこれだと、CSSのプロパティ自体を削除することはできません。

普段はそんな必要も無いのですが、IEにはfilterプロパティの付いた要素のその子要素でフォントのアンチエイリアス(ClearType)が効かなくなるというバグがあるので、filterプロパティ自体を削除したいことがあります。

node.styleで取得できるオブジェクトはCSSStyleDeclarationで、これにはremoveProperty()というメソッドがあるので、

node.style.removeProperty('filter');

とすれば良さそうです。

しかしIEではなぜかこれが未定義です。代わりにremoveAttributeが使えます。

なので、

var node = document.getElementById(’hoge’);
if (node.style.removeProperty) {
	node.style.removeProperty(’filter’);
}
if (node.style.removeAttribute) {
	node.style.removeAttribute(’filter’);
}

のような使い方になります。

—–具体的な使用例—–
dojoでは簡単にフェードインが使えます。
しかし、IEだと、フェードインした要素はフォントがガタガタになります。特にメイリオ等のアンチエイリアス前提フォントだと悲惨です。
以下のようにonEndを設定することで、フェードイン完了後はなめらかになります。

//fadeInを使うのであらかじめ透明度を0にする
dojo.style(dojo.byId(’hoge’), ‘opacity’, ‘0′);

(new dojo.fadeIn({
	node: ‘hoge’, //フェードインさせるノードのID
	duration: 1000, //ミリ秒
	onEnd: function() {
		var node = dojo.byId(’hoge’);
		if (node.style.removeProperty) {
			node.style.removeProperty(’filter’);
		}
		if (node.style.removeAttribute) {
			node.style.removeAttribute(’filter’);
		}
	}
})).play();

上がonEndを設定しない場合、下が設定した場合です。メイリオフォント使用。
090822_cleartype

dojoで角丸ボタン

dojo toolkitはデフォルトで各種ウィジェットが付いていて便利ですが、現時点ではまだテーマが充実していません。
実質的に使えるのは、tundraとsoriaくらいだと思います。

どちらもコントロールが角張っているので、丸くしたくなることがあります。

ダイアログの角丸は、-moz-border-radius / -webkit-border-radius を使えば簡単にできますが、IEなどにも対応しようと思うと、ウィジェットテンプレートを書き換えたりJavascriptで要素を書き換えたりしないといけません。

ボタン(高さ固定)は、IEを含め比較的簡単に角丸にできますので、今回はこちらを紹介します。

テーマの自作になりますので、まずはsoriaあたりをコピーして、これを上書きしていくことにします。
soria.css を mytheme.css にリネームして、.soria を .mytheme に一括置換(手抜き)してしまいましょう。

そして、角丸実現のために以下のような記述を追加します。

.mytheme .dijitButtonNode .dijitButtonContents {
	background: url(images/button_back.png) repeat-x 0 0;
}
.mytheme .dijitButton .dijitRight {
	background: url(images/button_right.png) no-repeat top right;
}
.mytheme .dijitLeft.dijitButton {
	background: url(images/button_left.png) no-repeat top left;
}

button_leftは左側の丸い画像、button_rightは右側の丸い画像、button_backは中央の矩形部分の画像です。
これらのファイルは自分で作ってimagesに入れておきます。
これだけで丸くなります。

ちゃんとやるときは、soriaテーマをきちんと解読して矛盾が無いようにすべきですが、小規模ならこんな安易な改造も可能です。

IEでのdojo.requireの挙動

DojoToolkitのお話です。

dojo.requireを使うと、JavaScriptを動的に読み込むことができます。
<script>タグを書くのに比べて、読み込むタイミングを制御できるため、大規模な開発に向いています。

しかし、<script>の羅列を単純に置き換えると、動かないことがあります。

読み込まれるファイルで var Test = {}; のように記述した場合、FirefoxではTestを参照できますが、IEでは参照できません。
この関数は、JavaScriptリソースを文字列として取得し、最終的にevalを使って評価しているのですが、FirefoxとIEでevalの挙動が違うためだと思われます。

dojo.requireを使うときは、簡単なクラスを定義する場合でも必ずdojo.declare() を使うことで、IEでも参照できるようになります。

IE7でposition:relativeの要素が重なるバグ

2009.03.03    HTML, javascript, 馬場   タグ: , , , , —    baba   

IE7で、JavaScriptを使って動的に要素を表示・非表示した場合、要素が重なってしまうことがあります。

実験ページ

IE7だと問題が再現し、IE8やFirefoxは再現しません。また、冒頭のDOCTYPE宣言を外してQuarksモードにしても再現しません。
IE7でのみ、Showボタンを押すと、文字が重なってしまうはずです。

不思議なことに、21行目のbackground指定を外すと、再現しません。
また、21行目の<div>開きと22行目の<div>開きの間に「スペース・TAB・改行以外の何か(コメントでも可)」を入れると、再現しません。
22行目の[height:2em] は、hasLayoutがtrueになれば何でもOKです。

まとめると、
・ブロック要素Aがある。
・Aの最初の子要素はブロック要素Bである。
・AはCSSで背景がnone以外に指定されていて、[hasLayout=false]である。
・Bは[position:relative] であり、なおかつ[hasLayout=true]である。

これらの条件を満たす場合、「Aの前にある要素の高さが変わり、AのY座標が変更になっても、BのY座標は再計算されない」というIE7独自のバグと言えそうです。

DebugToolbar等で位置の再計算を行うと、正しい位置に移動します。

おそらく計算順序にバグがあるのだと思います。position:relativeを使うときは気をつけましょう。

古い投稿 »

COPYRIGHT [C] 2009 BEYOND PERSPECTIVE SOLUTIONS LTD. ALL RIGHTS RESERVED.