DEVELOPMENTOR*LEARNING RESOURCE LAB.

ソフトウェア開発現場の視点からソフトウェアと開発者の価値を高める「ホットな何か」をお届けします。(休止)

del.icio.us JSON FeedsはJSONPにも対応してます

2006年11月28日 | Web 2.0

del.icio.us JSON Feedsを使ってブックマークをサムネイル付きで表示する」の続きです。今回は「JSON Post Feeds」のコールバックの仕組み(JSONPともいう)を使ってみました。↓こんな感じです。


View example

見た目や機能は前回のAjaxアプリと同じですが、コールバック関数を指定してJSON Post Feedsを取り込むという違いがあります。

JSON Post Feedsは次のようなscript要素を使って取り込んでいます。このとき「callback」というパラメータにというコールバック関数の名前を指定しています。

<script type="text/javascript"
  src="http://del.icio.us/feeds/json/developmentor?count=20&callback=onPosts"
></script>

このscript要素は次のようなJavaScript要素を出力します。callbackパラメータで指定した「onPosts」という関数を実行します。このとき関数の引数がブックマークのオブジェクトの配列になります。

onPosts([{
  "u": "http://astore.amazon.co.jp/",
  "n": "11月15日から正式版がスタートしました。自由度も上がって使ってみたい気にさせます。",
  "d": "Amazonアソシエイト・プログラム インスタントストア",
  "t": ["amazon", "affiliate"]
  },
  ...
]);

onPostsという関数を用意しておき、引数のブックマークのオブジェクトを使ってWEBページにブックマークのリストを表示しています。リストの表示方法は前回と同じです。

function onPosts(posts) {
  ...
}

今回はあらかじめWEBページにscript要素を埋め込んでいますが、さらにJavaScriptを使ってscript要素を動的生成すれば、よりインタラクティブなAjaxアプリにもなるでしょう。どんどんJSONPという仕組みを活用しましょう。


AOLVS Ajax APIを使ってビデオの主要なデータを表示してみる(の補足)

2006年11月27日 | Web 2.0

AOLVS Ajax APIを使ってビデオの主要なデータを表示してみる」の補足です。

ビデオの主要なデータといいながら「タグ」という重要なデータを紹介し忘れていました。そこで、ビデオに付与されたタグも表示するように改良しました。↓こんな感じです。


View example

見やすいようにタグは文字色をグリーンで表示しています。

Video.tags
ビデオに付与されたタグです。タグをカンマ「,」区切った文字列です。タグがないときはundefinedになります。

del.icio.us JSON Feedsを使ってブックマークをサムネイル付きで表示する

2006年11月26日 | Web 2.0

del.icio.us JSON Feeds」を使ってブックマークをサムネイル付きで表示してみました。↓こんな感じです。


View example

ブックマークのサムネイルは「MozShot」というサービスを使って表示しています。ほかにもサムネイルを生成するサービスはありますが、「MozShot」のサムネイルは、周囲がボヤ~と浮いたような影になるので、そのデザインが気に入って使ってみました。

ブックマークを表示するJavaScriptコードは「JSON Post Feeds」のexampleを改造したものです。

JSON Post Feedsは次のようなscript要素を使って取り込みます。アドレスの「developmentor」はdel.icio.usの「username」に対応しますので、あなたのusernameに置き換えてください。「count」は取り込むブックマークの数を表します。最大は100件までみたい。

<script type="text/javascript"
  src="http://del.icio.us/feeds/json/developmentor?count=20"></script>

このscript要素は次のようなJavaScriptコードを出力します。「Delicious.posts」という配列にブックマークのオブジェクトが新しい順序で格納されます。

if(typeof(Delicious) == 'undefined') 
  Delicious = {}; 
Delicious.posts = [{
  "u": "http://astore.amazon.co.jp/",
  "n": "11月15日から正式版がスタートしました。自由度も上がって使ってみたい気にさせます。",
  "d": "Amazonアソシエイト・プログラム インスタントストア",
  "t": ["amazon", "affiliate"]
  },
  ...
];

ブックマークのオブジェクトは次のプロパティを持ちます。プロパティの文字コードはUTF-8です。ただし、JavaScriptエンコードされていませんので、状況によっては都合が悪いこともあるかもしれません。

u
ブックマークのURLです。ブックマークをpostするときのurlに対応します。
d
ブックマークのタイトルです。ブックマークをpostするときのdescriptionに対応します。
n
ブックマークのメモです。ブックマークをpostするときのnotesに対応します。notesを省略したブックマークはこのプロパティを持たずundefinedになります。
t
ブックマークのタグです。ブックマークをpostするときのtagsに対応します。このプロパティは配列です。またtagsを省略したブックマークはこのプロパティを持たずundefinedになります。

JSON Post Feedsはコールバックを使った取り込み(JSONPという仕組み)にも対応しています。JSON Post Feedsのコールバックの使い方は、後日紹介しようと考えています。


Blosxomを使ったBLOGRANGER検索リンクの単純化

2006年11月23日 | blosxom

BlosxomBLOGRANGR 2.0の「BLOGRANGER検索 初号機」へのリンクを簡単に指定できるプラグインを作成してみました。blograngerプラグインといいます。blograngerプラグインはBlosxom 2.0に対応しています。

blograngerプラグインはエントリの中で、次のようにaタグのリンク先を指定できます。

<a href="t:KEYWORD">TEXT</a>
「<a href="t:携帯電話">BLOGRANGER検索</a>」のようにaタグのリンク先に「t:」とキーワードを指定すると、「BLOGRANGER検索」のようにBLOGRANGER検索へのリンクを表示します。そのリンク先は指定したキーワードでブログを検索し、トピックで選ぶタブを使って検索結果を表示します。↓こんな感じです。
<a href="b:KEYWORD">TEXT</a>
「<a href="b:携帯電話">BLOGRANGER検索</a>」のようにaタグのリンク先に「b:」とキーワードを指定すると、「BLOGRANGER検索」のようにBLOGRANGER検索へのリンクを表示します。そのリンク先は指定したキーワードでブログを検索し、ブロガーで選ぶタブを使って検索結果を表示します。↓こんな感じです。
<a href="r:KEYWORD">TEXT</a>
「<a href="r:携帯電話">BLOGRANGER検索</a>」のようにaタグのリンク先に「r:」とキーワードを指定すると、「BLOGRANGER検索」のようにBLOGRANGER検索へのリンクを表示します。そのリンク先は指定したキーワードでブログを検索し、リンク先で選ぶタブで検索結果を表示します。↓こんな感じです。
<a href="o:KEYWORD">TEXT</a>
「<a href="o:携帯電話">BLOGRANGER検索</a>」のようにaタグのリンク先に「o:」とキーワードを指定すると、「BLOGRANGER検索」のようにBLOGRANGER検索へのリンクを表示します。そのリンク先は指定したキーワードでブログ検索を実行し、感想で選ぶタブを使って検索結果を表示します。↓こんな感じです。

BLOGRANGER検索のURLフォーマットは公開されていないので、blograngerプラグインでは、URLを手打ちで試しながら期待する動作をした中で、もっとも簡単で短かったURLフォーマットを採用しました。ですので、今後も同じように動作するかどうかは保証できません。

BLOGRANGER検索のキーワードは「UTF-8」でエンコードする必要があります。そのためblograngerプラグインでは、次のようにキーワードの文字コードをJcodeモジュールを使ってUTF-8に変換しています。

##
sub kanjicode {
  my ($textref, $kanjicode) = @_;
use Jcode;
  &Jcode::convert($textref, $kanjicode);
  return $$textref;
}

変換前のキーワードの文字コードはJcodeモジュールで自動検出しています。文字コードの自動検出やJcodeモジュールといった少し古い仕組みが許容できないときは、この「kanjicodeサブルーチン」を改良して別の仕組みに置き換えてください。またそもそもBlosxomをUTF-8ベースで動かしているならコメントアウトしてもよいでしょう。

blograngerプラグインのダウンロードは↓こちらからどうぞ。


gooブログライターで書きかけの記事を救出する方法

2006年11月21日 | 使えるグッズ

このブログは主に「goo RSSリーダーアプリ版 ブログライター機能」を使って書いているのですが、Windowsの調子が悪くなったとき、書きかけの記事までもが「oh! no!!!!!!」となってしまうことがあります。少し長めの記事だったりするとかなりショックだったりします。

そこで、gooブログライターで書きかけの記事を救出する方法を探してみました。

※以下の方法は保証外です。自己責任でお願いします。私はいかなる責任も追いません。

書きかけの記事がgooブログライターの記事一覧から消えていても、「下書き保存」していればまだその記事自体は残っているかもしれません。次のディレクトリの中に「entry_############.plist」というファイルがあるので、タイムスタンプ(更新日時ともいう)の新しい順に確認していきます。

C:Documents and Settings<user>Application DatagooRSSReaderweblogs

 この「entry_############.plist」というファイルはXMLファイルです。ですので、メモ帳などのテキストエディタで開けます。運がよければXMLファイルの中から書きかけの記事が見つかるでしょう。

記事が見つかったら、その記事をコピーしてブログライターに貼り付けます。そして、記事の続きを書けばよいでしょう。見つからなかったら諦めるしかないですね。

余談ですが、ということはgooブログライターを使うと、ブログの記事をファイルとして手元にダウンロードできるってことですね。いいかも。


Lyase.View Ajax指向のシンプルテンプレートエンジン(その4)

2006年11月21日 | prototype cast

Lyase.View Ajax指向のシンプルテンプレートエンジン(その3)」まではLyase.Viewの使い方を紹介しました。ここではLyase.Viewをより深く理解するため、Lyase.Viewのソースコードを読みながらその特徴に迫ります。

↓Lyase.Viewがテンプレートの文字列を解析するソースコードです。Lyase.Viewはテンプレートを解析しながら、そのテンプレートをJavaScriptコードに変換するという方法を使っています。

「new Function("context", parsed.join(""))」とあるように、Lyase.Viewは1つのテンプレートの文字列から1つのJavaScript関数を生成します。Functionオブジェクトを使って、動的にJavaScript関数を生成しているのがポイントです。Functionオブジェクトってこういう使い方もあるんですね。詳しくは「Mozilla Developer Center」の「Core JavaScript 1.5 Reference」を見てください。

Lyase.View = {
  _cache : {},
  parse : function(template, id) {
    var self = Lyase.View,parsed = ["var __out=[],render = Lyase.View.render;"]
    var tokens = template.split("<%");
    for(var i = 0, l = tokens.length; i<l; i++) {
      var token = tokens[i];
      if(token.indexOf("%>") == -1){
        parsed.push(self._string(token));
        continue;
      }
      var parts = token.split("%>");
      parsed.push(self[(parts[0].charAt(0) == "=")?"_value":"_code"](parts[0]));
      parsed.push(self._string(parts[1]));
    }
    parsed.push("return __out.join('');");
    var templateFunc = new Function("context", parsed.join(""));
    if(id) self._cache[id] = templateFunc;
    return templateFunc;
  },

テンプレートの文字列から生成したFunctionオブジェクトは、テンプレートの識別子に関連付けてキャッシュしています。「using innerHTML(ページ中の要素として)」のときは要素IDを、「using a template file(外部ファイルとして)」のときはファイルパスを識別子に使います。そのため、同じテンプレートを繰り返し使ったとしても、テンプレートを解析するのは1度だけです。ただし例外があり、「using text(JavaScriptの文字列として)」のときはキャッシュされません。

  render : function(options, values) {
    var self = Lyase.View, template, id;
    if(options.text) return self.parse(options.text, null)(values);
    if(options.element) var element = $(options.element);
    id = (options.file) ? options.file : element.id;
    if(self._cache[id]) return self._cache[id](values);
    if(options.element) {
      template = self._elementTemplate(element);
    }else {
      template = (new Ajax.Request(options.file,{asynchronous : false})).transport.responseText;
    }
    return self.parse(template, id)(values);
  },

「using a template file(外部ファイルとして)」のときはAjax.Request(prototype.js)を使って、テンプレートを外部ファイルから取得しますが、そのときHTTPサーバ側でエラーが発生しても、そのエラーレスポンスの内容をテンプレートして解釈しています。この振る舞いが許容できないときは、1例として次のようにソースコードを改良してエラーが発生したときの振る舞いを追加するとよいでしょう。

  var request = new Ajax.Request(options.file, {asynchronous : false}).transport;
  template = request.status!=200
    ? '...'
    : request.responseText;

Lyase.Viewの紹介は今回(その4)でおしまいです。


digital personaの指紋認証ログオン用のアカウントを編集する方法

2006年11月20日 | del.icio.us

 WEBサイトのアカウントパスワードを変更したとき、デスクトップ側の指紋認証ログオンパスワードを変更する手順を忘れてしまい、イライラすることがあるので、この機会に手順をメモしておきます。

Microsoft Fingerprint Reader [DG2-00003] Microsoft Fingerprint Reader [DG2-00003]

Microsoft Wireless IntelliMouse Explorer with Fingerprint Reader [DG3-00005] SONY USM128F 指紋認証ソフト付き POCKET BIT 128MB Microsoft Optical Desktop with Fingerprint Reader eプライスシリーズ ウイルスキラー 2005 (スリムパッケージ版) アイ,ロボット 特別編

by G-Tools

はじめにパスワードを変更するWEBサイトを開きます。するとブラウザの右上に指紋認証ログオンのアイコンが現れるので、このアイコンをクリックします。指紋認証ログオン用のアカウントの編集は、このアイコンしか入口がないようなので、ついつい忘れてしまうのです。

すると、次のようなダイアログが表示されるので、指紋認証します。

すると、指紋認証ログオン用のアカウントが編集できます。


del.icio.usのブックマークをgooブログに投稿する方法

2006年11月18日 | Web 2.0

del.icio.usの「daily blog posting」を使ってgooブログにブックマークを自動投稿する方法を紹介します。

はじめにgooブログの「ブログライター機能」を有効にします。gooブログの編集画面から「個人情報」を開きます。↓こんな感じです。

その中に「ブログライター機能(XML-RPC)」の項目がありますので「使用する」を選択します。さらにパスワードを指定します。このパスワードは「daily blog posting」を設定するときに使います。

次にdel.icio.usの「daily blog posting」を設定します。del.icio.usのsettingsから「daily blog posting」を開きます。↓こんな感じです。

「add a new thingy」を選択し、あなたのgooブログに情報に合わせて、次のように設定します。

job_name
何か好きな名前を付けます。私は「blog.goo.ne.jp/developmentor」というgooブログのアドレスを指定しました。
out_name
goo IDを指定します。私は「developmentor」を指定しました。
out_pass
gooブログの「ブログライター機能(XML-RPC)」のパスワードを指定します。上で指定したパスワードです。goo IDのパスワードではありません。
out_url
http://blog.goo.ne.jp/xmlrpc.php」を指定します。固定です。
out_time
ブックマークを投稿する時刻0~23を指定します。私は「15」を指定しました。日本は標準時間で+9の差がありますので、「15」だとちょうど0時を指定したことになります。↓換算表を使ってください。
0 9時
1 10時
2 11時
3 12時
4 13時
5 14時
6 15時
7 16時
8 17時
9 18時
10 19時
11 20時
12 21時
13 22時
14 23時
15 0時
16 1時
17 2時
18 3時
19 4時
20 5時
21 6時
22 7時
23 8時
out_blog_id
「1」を指定します。固定です。
out_cat_id
ブックマークを投稿するカテゴリIDを指定します。あなたのgooブログの何れかのカテゴリIDを指定します。私は「40e2265ec82cf7ede36bced6896f3cf9」を指定しました。カテゴリIDはあなたのgooブログのメニューからカテゴリを選択することで調べられます。カテゴリを選択した後、ブラウザのアドレスバーに注目してください。そのアドレスが「http://blog.goo.ne.jp/developmentor/c/40e2265ec82cf7ede36bced6896f3cf9」であれば、カテゴリIDは「40e2265ec82cf7ede36bced6896f3cf9」になります。

これで完了です。

指定した時刻になると、gooブログに最近1日のブックマークが自動投稿されます。こんな感じです。指定した時刻ぴったりには投稿されません。15分から30分ほど遅くなるようです。なお、最近1日のブックマークがないときは投稿されません。

最後にgooブログの「daily blog posting」を設定するにあたり、次のブログがとても参考になりました。ありがとうございます。


レジャースポットの定義をファイルに移動してデータとページを分離する

2006年11月17日 | Web 2.0

Googleマップの吹き出しをタブ形式で表示する」の中で、東京近郊レジャースポット案内というAjaxアプリを作りましたが、さらにレジャースポットの定義を別のファイルに移動し、データとWEBページを分離してみました。↓こんな感じです。


View example

WEBページのJavaScriptコードにあったレジャースポットの定義を…

var spots = [
  // {lat: 緯度, lng: 経度, url: ブックマークURL}
  {lat: 35.660347, lng: 139.729121, url: [
    'http://ranger.labs.goo.ne.jp/rpc/partsview.php?key=1510',
    'http://ranger.labs.goo.ne.jp/rpc/partsview.php?key=1789'
  ]}, // 六本木ヒルズ
    …途中、省略…
];

次のように、WEBページとは別のテキストファイルに移動してアップロードします。ここではファイル名を「googlemapsjson.txt」としました。

 googlemapsjson.txt

[
  {lat: 35.660347, lng: 139.729121, url: [
    'http://ranger.labs.goo.ne.jp/rpc/partsview.php?key=1510', 
    'http://ranger.labs.goo.ne.jp/rpc/partsview.php?key=1789' 
  ]}, 
  {lat: 35.665246, lng: 139.712319, url: [
    'http://ranger.labs.goo.ne.jp/rpc/partsview.php?key=1556', 
    'http://ranger.labs.goo.ne.jp/rpc/partsview.php?key=1790' 
  ]}, 
  {lat: 35.634017, lng: 139.878595, url: 'http://ranger.labs.goo.ne.jp/rpc/partsview.php?key=1557'}, 
  {lat: 35.705646, lng: 139.751887, url: [
    'http://ranger.labs.goo.ne.jp/rpc/partsview.php?key=1569', 
    'http://ranger.labs.goo.ne.jp/rpc/partsview.php?key=1791' 
  ]}, 
  {lat: 35.639511, lng: 139.760170, url: 'http://ranger.labs.goo.ne.jp/rpc/partsview.php?key=1570'}, 
  {lat: 35.673770, lng: 139.762745, url: 'http://ranger.labs.goo.ne.jp/rpc/partsview.php?key=1577'}, 
  {lat: 35.707127, lng: 139.753046, url: 'http://ranger.labs.goo.ne.jp/rpc/partsview.php?key=1578'}, 
  {lat: 35.664915, lng: 139.762487, url: 'http://ranger.labs.goo.ne.jp/rpc/partsview.php?key=1579'}, 
  {lat: 35.621966, lng: 139.750750, url: 'http://ranger.labs.goo.ne.jp/rpc/partsview.php?key=1580'}, 
  {lat: 35.654995, lng: 139.796476, url: 'http://ranger.labs.goo.ne.jp/rpc/partsview.php?key=1581'}, 
  {lat: 35.664897, lng: 139.766908, url: 'http://ranger.labs.goo.ne.jp/rpc/partsview.php?key=1586'}, 
  {lat: 35.658639, lng: 139.745407, url: 'http://ranger.labs.goo.ne.jp/rpc/partsview.php?key=1587'}, 
  {lat: 35.689492, lng: 139.691699, url: 'http://ranger.labs.goo.ne.jp/rpc/partsview.php?key=1588'}, 
  {lat: 35.672428, lng: 139.755728, url: 'http://ranger.labs.goo.ne.jp/rpc/partsview.php?key=1589'}, 
  {lat: 35.676368, lng: 139.699359, url: 'http://ranger.labs.goo.ne.jp/rpc/partsview.php?key=1590'}  
]

WEBページのロードが完了したタイミングで、レジャースポットの定義をAjax.Request(prototype.js)を使って取得します。

function load() {
  var map = new GMap2(document.getElementById('map'));
  map.addControl(new GSmallMapControl());
  map.addControl(new GMapTypeControl());
  map.addControl(new GOverviewMapControl());
  map.setCenter(new GLatLng(35.686302, 139.74575), 12);

Ajax.Requestの引数には前述の「googlemapsjson.txt」を指定します。そして、その「googlemapsjson.txt」を取得して、その取得したテキストをJavaScriptとして評価します。また失敗したときは、エラーメッセージを表示して終了します。

  var request = new Ajax.Request('googlemapsjson.txt', {
    method: 'get', asynchronous : false
  }).transport;
  if (request.status!=200)
    return alert(request.status+' '+request.statusText);
  var spots = eval('('+request.responseText+')');

以降は今までどおり、レジャースポットの定義にしたがって地図上にマーカーを配置していきます。

  for (var i=0; i<spots.length; i++)
    map.addOverlay(createMarker(spots[i]));
}