‘JavaScript’ カテゴリーのアーカイブ

JavaScript:parseInt(“08″)の罠

このエントリをはてなブックマークに追加このエントリをdel.icio.usに追加このエントリをLivedoor Clipに追加このエントリをYahoo!ブックマークに追加このエントリをFC2ブックマークに追加このエントリをNifty Clipに追加このエントリをPOOKMARK. Airlinesに追加このエントリをBuzzurl(バザール)に追加このエントリをChoixに追加このエントリをnewsingに追加

JavaScriptの関数parseIntには、罠が仕掛けられていた。
具体的には、”08″, “09″のような値に対して処理を行うと8進数として捉えてしまうというものだ。
その結果、文字列08, 09はparseIntすると0が返ってきた。

なので、10進数で処理させるためには第二引数で10を指定する必要がある。

// 例 1桁の場合
var a1 = parseInt("8"); // a1 = 8
var b1 = parseInt("8", 10); // b1 = 8

// 例 2桁の場合
var a2 = parseInt("08"); // a2 = 0
var b2 = parseInt("08", 10); // b2 = 8

先頭に0が付くときにしか顕在化しないので、なかなか気付かないものだ。


firebug: consoleがundefinedの場合

このエントリをはてなブックマークに追加このエントリをdel.icio.usに追加このエントリをLivedoor Clipに追加このエントリをYahoo!ブックマークに追加このエントリをFC2ブックマークに追加このエントリをNifty Clipに追加このエントリをPOOKMARK. Airlinesに追加このエントリをBuzzurl(バザール)に追加このエントリをChoixに追加このエントリをnewsingに追加

昨日書いたfirebugでのconsoleオブジェクトを使ったデバッグ方法ですが、firefoxにfirebugが入ってなかったり、IEだとconsoleオブジェクトが存在しないため、JavaScriptエラーになって処理が止まってしまいました…。なんちゅうことだ…。

このままだと、firebugがある場合だけ正常な動作をするアプリになってしまう!リリースするタイミングでconsole系のメソッド使ってるところを全部コメントアウトすればよいのかもしれないけれど、それはそれで面倒だし、なによりまたデバッグが必要になったときに困る!

解決策はないかな~とネットで探してみたら、まあ自分が考えていたような解決策とほぼ一致したので、じゃあそれでやってみるかと。

// consoleオブジェクトが未定義ならば
if(typeof console == 'undefined'){
  // 何も処理しないメソッドを持ったconsoleオブジェクトを定義する
  console = {
    log: function(){},
    debug: function(){},
    info: function(){},
    warn: function(){},
    error: function(){},
    assert: function(){}
  };
}

consoleオブジェクトが持つメソッドはこれらだけではないのだけれど、自分が使ってるメソッドだけとりあえず定義しておけば大丈夫なんじゃなかろうか?
とりあえずはこれでJavaScriptエラーで止まるということはなくなった。


javascript: firebugの使い方 tips

このエントリをはてなブックマークに追加このエントリをdel.icio.usに追加このエントリをLivedoor Clipに追加このエントリをYahoo!ブックマークに追加このエントリをFC2ブックマークに追加このエントリをNifty Clipに追加このエントリをPOOKMARK. Airlinesに追加このエントリをBuzzurl(バザール)に追加このエントリをChoixに追加このエントリをnewsingに追加

JavaScriptの開発で必須であるFirebugですが、自分は使いこなせてなかったことを痛感しました…。AJAXの通信を見張るのと、DOM要素のCSSチェックとかに使ってたので、これで使いこなせてると思ってたけど、console.logとかあったんやなぁ~。consoleオブジェクトの素晴らしさを知ったら、alertとか使わんで済むから助かる~!!

// ログを出すのみ
console.log("test");

// sprintfのように置換して出力もできる!
console.log("Hello, %s", "patorash"); // Hello, patorash

// 以降は、ログを出し、ソースへのリンクも貼る
console.debug("test");
// infoマーク付き
console.info("test");
// warnマーク付き
console.warn("test");
// error扱い
console.error("test");

// 条件に合致しない場合だけコンソールログ出力(unittestに使える?)
var test = "test";
console.assert(test == "hoge", "test != 'test'ではない", test);

まだまだ色々できるみたいだけれど、自分が使いそうなのはこれくらいかな。

自分が最も使いそうな使い方。(prototype.jsで)

var ary = $w('php javascript css ruby java');
console.debug(Object.inspect(ary));

mixiアプリ:永続化したJSONデータの取得

このエントリをはてなブックマークに追加このエントリをdel.icio.usに追加このエントリをLivedoor Clipに追加このエントリをYahoo!ブックマークに追加このエントリをFC2ブックマークに追加このエントリをNifty Clipに追加このエントリをPOOKMARK. Airlinesに追加このエントリをBuzzurl(バザール)に追加このエントリをChoixに追加このエントリをnewsingに追加

趣味でmixiアプリの開発を始めてる。mixiアプリで値の永続的に使用するには、外部サーバに値を保存する方法と、mixiのkey-valueストアを利用する方法がある。今回は処理が軽くて通信も少なくて済みそうなkey-valueストアに値を保存する方法を選んだのだが、key-valueストアはいわゆるデータベースではないのでどういう形式で値を持たせるかで悩んだ。今回はJSONで保存してみた。

ところが、いざ値を取得してみると、JSONからオブジェクトに戻すことができなかった!

これはどういうことだ!?と、思って先日楽天ブックスから届いたOpenSocial入門を読んで調べていると、永続化されたJSONデータをそのまま取得するとHTMLエスケープされているらしい。これでは使いにくいので、HTMLエスケープしないように明示してデータを取得させに行く必要がある。

// 現在の設定を取得する
var req = opensocial.newDataRequest();
var mySetting = {};
var escapeParams = {};
// ここで、JSONデータをHTMLエスケープしないように指示
escapeParams[opensocial.DataRequest.DataRequestFields.ESCAPE_TYPE] = opensocial.EscapeType.NONE;
req.add(req.newFetchPersonAppDataRequest("VIEWER", ["setting"], escapeParams), 'selfData');
req.send(function(data){
	if(data.hadError()){
		// エラー処理
		var msg = data.getErrorMessage();
		return;
	}else{
		var selfData = data.get('selfData');
		if(selfData.hadError()){
			return;
		}
		var dataAry = selfData.getData()[viewer_id];
		if(dataAry != null){
			// 値が設定済み
			mySetting = gadgets.json.parse(dataAry['setting']);
		}
	}
}

上記のようにしたところ、JSONデータをオブジェクトとして取得することができた。JSONは便利だけれど危険もあるので、HTMLエスケープが自動的に行われるのはいいと思うけれど、OpenSocialアプリ開発を始めたばかりだとはまってしまいそうだったのでメモメモ。

OpenSocial入門 ~ソーシャルアプリケーションの実践開発
OpenSocial入門 ~ソーシャルアプリケーションの実践開発
技術評論社 2009-01-24
売り上げランキング : 8425

おすすめ平均 star
star内容の濃い良書

Amazonで詳しく見る by G-Tools


scriptaculous:inPlaceEditorのonFailureの使い方

このエントリをはてなブックマークに追加このエントリをdel.icio.usに追加このエントリをLivedoor Clipに追加このエントリをYahoo!ブックマークに追加このエントリをFC2ブックマークに追加このエントリをNifty Clipに追加このエントリをPOOKMARK. Airlinesに追加このエントリをBuzzurl(バザール)に追加このエントリをChoixに追加このエントリをnewsingに追加

scriptaculousのinPlaceEditorを久々に使った。
そのときにonFailureの使い方がAjax.Requestとは違ったので、メモ。
2つ目の引数に、ajaxResponseのオブジェクトが来る。

new Ajax.inPlaceEditor(
  ...
  {
    ...,
    onFailure: function(ipe, httpObj){
      alert(httpObj.responseText);
    },
  }
);

WordPress: 自作プラグインでAjaxする正しい方法

このエントリをはてなブックマークに追加このエントリをdel.icio.usに追加このエントリをLivedoor Clipに追加このエントリをYahoo!ブックマークに追加このエントリをFC2ブックマークに追加このエントリをNifty Clipに追加このエントリをPOOKMARK. Airlinesに追加このエントリをBuzzurl(バザール)に追加このエントリをChoixに追加このエントリをnewsingに追加

WordPressの自作プラグインでAjaxする方法で、正しく行う方法がないか探していた。Googleで検索しても、Ajaxを使ってるプラグインの情報がたくさん出てくるばっかりで、作り手に有益な情報を調べるにまでいけなかった。だから、必要なファイルのみを無理矢理require_onceで読み込んでインスタンスを生成してから、やりたい処理を行うという強引な方法を取っていた。しかし、Ajaxしたいところで毎回require_onceをやるのは面倒だし、正しくやる方法があるに違いないと思っていたら、あったよ!やっぱり!

http://wpdocs.sourceforge.jp/AJAX_in_Plugins

上のサイトの例では、javascriptライブラリとしてSACKを使っているが、俺はprototype.js&scriptaculousファンなので、prototype.jsを使ったAjaxで勝負!

まず、プラグイン側でjavascriptファイルを読み込む設定を行う。
プラグインの名前は、hogeとします。

/**
 * /wp-content/plugins/hoge/hoge.php
 *
 * 管理画面でjavascriptを読み込む
 */
add_action('admin_enqueue_scripts', 'hoge_script_admin');
function hoge_script_admin($hook_suffix){
  // 指定したページのみでjsを読み込むために、条件を設定
  // ここではhogeプラグインのカテゴリー管理ページに焦点と絞ったとする
  if (preg_match('/page_hoge_category_list$/', $hook_suffix)) {
    // hoge_category.jsと、prototype.jsを読み込む
    wp_enqueue_script('hoge_category', plugins_url('hoge/js/hoge_category.js'), array('prototype'), '1.0', false);
  }
}

次に、hoge_category.js側に処理を記述する。
関数 update_category_list が呼ばれると、Ajaxでカテゴリーリストを更新する想定です。

function update_category_list(){
  // ajaxurlはWordPressが定義してくれてる
  var params =[];
  // Ajaxアクションを指定
  params.push('action=hoge_get_category');
  // あとは必要なパラメータを設定
  params.push('abc=xyz');
  new Ajax.Updater(
    'category_list', // 更新される領域のID
    ajaxurl,
    {
      method: 'post',
      parameters: params.join('&')
    }
  });
}

最後に、hoge_category.jsから呼ばれるサーバ側の処理を記述する。

// ajaxで呼ばれるアクションを追加する
add_action('wp_ajax_hoge_get_category', 'hoge_get_category');
// 実際に呼ばれるアクションを定義する
function hoge_get_category(){
  $output = '<ul>' . "\n";
  for($i = 1; $i < 10; $i++){
    $output .= '<li>カテゴリーその'. $i .'</li>' . "\n"
  }
  $output .= '</ul>' . "\n";
  echo $output;
}

これで、カテゴリーリストがAjaxで更新されます。


scriptaculousのEffectで仕込んでしまったバグ

このエントリをはてなブックマークに追加このエントリをdel.icio.usに追加このエントリをLivedoor Clipに追加このエントリをYahoo!ブックマークに追加このエントリをFC2ブックマークに追加このエントリをNifty Clipに追加このエントリをPOOKMARK. Airlinesに追加このエントリをBuzzurl(バザール)に追加このエントリをChoixに追加このエントリをnewsingに追加

ソースを全て載せるわけにはいかないが、
scriptaculousを使っていたら、下記のソースのようなことが起きた。

/**
 * エフェクト付きでfoo領域を消して、bar領域を表示する
 */
function foo_blindup(){
  Effect.BlindUp('foo', { // fooが最終的には表示されなくなる
    afterFinish: function(){
      Eeffect.BlindDown('bar');
    }
  });
  $('foo_ul').update(''); // foo領域内のfoo_ul領域内をクリアする
}

/**
 * foo領域が表示されていれば、処理を行う
 */
function foo_exec(){
  if($('foo').visible()){
    // fooが表示されているときの処理
    $('foo_ul').update('<li>test</li>');
  }
  // 他にやりたい処理
}

// fooを消して、barを表示する
foo_blindup();
// fooが表示されていないので、if文内の処理はされないはず!
foo_exec();
// ところが、alertで<li>test</li>が出る。
alert($('foo_ul').innerHTML);

原因を探るべく、以下のように修正

// fooを消して、barを表示する
foo_blindup();
// この時点で、alertの中身は空
alert($('foo_ul').innerHTML);
// あとは変わらずに処理
foo_exec();
// ここでも、alertの中身は空に!!
alert($('foo_ul').innerHTML);

foo_exec()の前にalertを出すと処理をパスし、alertを出さないと処理される…。
なんだこれは???と小一時間悩んだ末に気付いたのが、
BlindUp処理が完了し終わってない間にfoo_exec()がコールされているのでは?ということだった。つまり、alertを出した場合は、alertを出している間にBlindUp処理が終わり、foo_exec()がコールされてもif文内の処理が行われないということだ。なんということだ。

結局、以下のように修正。

/**
 * foo領域が表示されていれば、処理を行う
 */
function foo_exec(){
  if($('foo').visible()){
    // fooが表示されているときの処理
    $('foo_ul').update('<li>test</li>');
  }
  // 他にやりたい処理
}

// fooを消して、barを表示する
Effect.BlindUp('foo', { // fooが最終的には表示されなくなる
    afterFinish: function(){
      $('foo_ul').update(''); // foo領域内のfoo_ul領域内をクリアする
      Eeffect.BlindDown('bar');
      foo_exec();  // afterFinish後なので、foo領域はdisplay:none;になっている
    }
}

prototype.jsすげー!

このエントリをはてなブックマークに追加このエントリをdel.icio.usに追加このエントリをLivedoor Clipに追加このエントリをYahoo!ブックマークに追加このエントリをFC2ブックマークに追加このエントリをNifty Clipに追加このエントリをPOOKMARK. Airlinesに追加このエントリをBuzzurl(バザール)に追加このエントリをChoixに追加このエントリをnewsingに追加

Prototype & script.aculo.us JavaScriptライブラリによるAjaxアプリケーション開発
Prototype & script.aculo.us JavaScriptライブラリによるAjaxアプリケーション開発 栗山 淳(監訳)

おすすめ平均
stars寄り道せずにこれで決まり
starsprototypeはもはや言語?
starsJavaScriptデファクトスタンダードライブラリのバイブル的1冊。
stars作者の独断

Amazonで詳しく見る by G-Tools

仕事でバリバリ使っています。prototype.js。
prototype.jsを使うとRubyチックにコーディングできる!でも俺Ruby使いじゃないし!
そんな俺でもこのprototype.jsのコーディングのしやすさにはマジ惚れる。

最初、この本を買ったときは、prototype.jsとscriptaculousの使い方がボチボチわかればいいやーという程度の期待感であったが、読めば読むほどというか、使えば使うほど、実はすげーじゃないか!?ということが判明。いやそれは俺が気付いてなかっただけなのかもしれないけれどもさ。

まだよくわかってない部分も多々あるけれど(bindとか…)、
とりあえずprototype.jsを使い始めるには、この本が一番オススメだと思います!
ただし、プログラマー向けだということは確実ですけどね!!


javascript:display: none;で動画オブジェクト消失

このエントリをはてなブックマークに追加このエントリをdel.icio.usに追加このエントリをLivedoor Clipに追加このエントリをYahoo!ブックマークに追加このエントリをFC2ブックマークに追加このエントリをNifty Clipに追加このエントリをPOOKMARK. Airlinesに追加このエントリをBuzzurl(バザール)に追加このエントリをChoixに追加このエントリをnewsingに追加

YouTubeの動画を読み込んだ領域を含むdivタグのスタイルをdisplay: none;にした後に、display: ”;で復帰させてからプレイヤーのloadVideoByIdメソッドを実行したら、firebugで、「そんなメソッドは定義されてないよ!」と怒られてしまった…。

原因はおそらく、display: none;にしたからだろう。display: none;にするメソッドを実行したら、再生中の動画も自動的にストップしたので、objectも消滅したことになるだろうか?(ソース上は存在するのだが…)

真っ先に考えたのは、display: none;にするのではなく、画面から見えない場所に飛ばしてしまうこと。つまり、left: -9999px;とかだ。
一応、ググッてみると、やっぱり同じようなことをしている人がいた。

http://blog.livedoor.jp/bkpg/archives/446185.html

現状、left: -9999px;にしておいて、再生するときに、$(“hoge”).removeAttribute(“style”);にして、元の位置に戻すようにした。とりあえずこれでいいのではないかな?と。まぁあんまりスマートではないけど…。つーかdisplay: none;でオブジェクトが消失しないでほしかった…。


javascript: YouTube APIでハマったこと

このエントリをはてなブックマークに追加このエントリをdel.icio.usに追加このエントリをLivedoor Clipに追加このエントリをYahoo!ブックマークに追加このエントリをFC2ブックマークに追加このエントリをNifty Clipに追加このエントリをPOOKMARK. Airlinesに追加このエントリをBuzzurl(バザール)に追加このエントリをChoixに追加このエントリをnewsingに追加

社内案件で、YouTube APIを使ったWebアプリを作ってるんだけど、
そのときにハマッたのでメモ。以下は失敗した例。

// 前提として、prototype.jsを使ってる
var Player = Class.create({
  player: '',
  create_player: function(video_id){
    var params = {allowScritpAccess: "always"};
    var atts = {id: "myytplayer"};
    swfobject.embedSWF("http://www.youtube.com/v/"+ video_id +"&amp;enablejsapi=1&amp;playerapiid=ytplayer&amp;autoplay=1&amp;rel=0&amp;showsearch=0&amp;showinfo=0", "ytapi_player", "460", "382", "8", null, null, params, atts);
    this.player = $("myytplayer");
    this.player.addEventListener("onStateChange", "player_check_state", false);
  }
});

function player_check_state(new_state){
  // 状態がかわったときの処理なんだけど、まったく呼ばれる気配なし…
}

var Test_Player = new Player();

原因は、swfobject.embedSWFメソッドを呼んですぐにプレイヤーをplayerメンバ変数に代入していたから。これだと、まだプレイヤーが生成されていなくて、エラーを引き起こしてしまう。

// 修正版
var Player = Class.create({
  player: '',
  create_player: function(video_id){
    var params = {allowScritpAccess: "always"};
    var atts = {id: "myytplayer"};
    swfobject.embedSWF("http://www.youtube.com/v/"+ video_id +"&amp;enablejsapi=1&amp;playerapiid=ytplayer&amp;autoplay=1&amp;rel=0&amp;showsearch=0&amp;showinfo=0", "ytapi_player", "460", "382", "8", null, null, params, atts);
  }
});

// プレイヤーの準備が出来たら呼ばれるコールバック関数
function onYouTubePlayerReady(playerId){
  Test_Player.player = $("myytplayer");
  Test_Player.player.addEventListener("onStateChange", "player_check_state", false);
}

function player_check_state(new_state){
  // 状態がかわったときの処理
  // 呼ばれた
}

var Test_Player = new Player();

ちゃんと、プレイヤーの領域上にプレイヤーの準備が出来てからでないと、
イベントが設定できないので要注意ですな。


Get Adobe Flash playerPlugin by wpburn.com wordpress themes