本プラグインにさらに手を加えたものを公開しています。Twitterからのトラックバックを簡単に設置できるjQueryプラグインをさらに改造してページネーションにも対応してみた(2011.08.02)

@soraiyのjquery.twitterTrackback.jsを改良してみた。」で公開されているTwitterからのツイートを表示するjQueryプラグインに、さらに手を加えたものを作ったので、ここにおいておきます。

URLを自動取得に

元のスクリプトでは実行時にURLを指定しなくてはいけませんでしたが、これを location.half の値を使って自動取得に変更しました。

下記のように、オプションさえ指定しなければ引数無しで記述可能です。

$('#twitterTrackback').twitterTrackbackList();

removeHash オプションを指定することで、URLに含まれるハッシュを削除することができます。これは、ページ内リンクなどでURLにハッシュが含まれる場合、正しくツイートが取得できない問題を回避するためです。

$('#twitterTrackback').twitterTrackbackList({
    removeHash: true // デフォルトでtrue
});

レンダリング用のコールバック関数を指定できる

callback オプションにコールバック関数を指定することで、自由にHTMLを生成できるようにしました。
このサイトでは下記のような関数を使ってレンダリングしています。

$('#twitterTrackback').twitterTrackbackList({ callback: renderTweets });

function renderTweets(n) {
	return (
		'<li class="tweet' + n + '"><dl>' +
		'<dt><a href="' + this.author.url + '">' + this.author.nick + '</a></dt>' +
		'<dd class="date"><a href="' + this.permalink_url + '">' + this.date_alpha + '</a></dd>' +
		'<dd class="image"><a href="' + this.author.url + '"><img src="' + this.author.photo_url + '" alt="' + this.author.name + '" width="48" /></a></dd>' +
		'<dd class="content">' + this.content.replace(/((http:|https:)\/\/[\x21-\x7e]+)/gi, "<a href='$1'>$1</a>") + '</dd>' +
		'</dl></li>'
	);
}

コールバック関数の this スコープにはツイートの情報が入っていますので、HTMLと組み合わせて自由にデザインが可能です。

除外するユーザーを設定可能に

exclude オプションに除外したいユーザー名を配列で指定することで、そのユーザーからのツイートを非表示にします。
自分のツイートを非表示にする場合なんかに利用できます。

$('#twitterTrackback').twitterTrackbackList({ exclude: [ 'jyokyoku' ] });

ソースコード

こちらのリンクからダウンロードするか、下記ソースコードを保存して利用して下さい。

動作確認は下記環境で行っています。

  • InternetExplorer7
  • Firefox4
  • Opera10
(function($) {
	jQuery.fn.twitterTrackbackList = function(options){
		var topsyOtterapi = 'http://otter.topsy.com/trackbacks.js';
		var self = this;
		var tweetHtml = '';

		function renderHtml(n) {
			return (
				'<li class="tweet' + n + '">' +
					'<a href="' + this.author.url + '"><img src="' + this.author.photo_url + '" alt="' + this.author.name + '" width="48" /></a>' +
					'<ul class="section">' +
						'<li class="nick"><a href="' + this.author.url + '">' + this.author.nick + '</a></li>' +
						'<li class="content">' + this.content.replace(/((http:|https:)\/\/[\x21-\x7e]+)/gi, "<a href='$1'>$1</a>") + '</li>' +
						'<li class="date"><a href="' + this.permalink_url + '">' + this.date_alpha + '</a></li>' +
					'</ul>' +
				'</li>'
			);
		}

		options = $.extend({
			url: window.location.href,
			wrapperTag: 'ul',
			removeHash: true,
			callback: renderHtml,
			noTrackback: '<p>Twitterからのトラックバックはありません。</p>',
			exclude: []
		}, options);

		if (options.removeHash) {
			options.url = options.url.replace(/#.+/, '');
		}

		jQuery.ajax({
			type: 'GET',
			url: topsyOtterapi,
			cache: false,
			dataType: 'jsonp',
			data: {
				perpage: '100',
				order: 'date',
				url: options.url
			},
			success: function(trackbackData) {
				if(trackbackData.response.list.length == 0) {
					tweetHtml += options.noTrackback;

				} else {
					jQuery.each(trackbackData.response.list, function(n) {
						for (var i = 0; i < options.exclude.length; i++) {
							if (options.exclude[i] != this.author.nick) {
								tweetHtml += options.callback.call(this, n);
							}
						}
					});

					if (!tweetHtml) {
						tweetHtml = options.noTrackback;

					} else if (options.wrapperTag) {
						tweetHtml = '<' + options.wrapperTag + '>' + tweetHtml + '</' + options.wrapperTag + '>';
					}
				}
				jQuery(self).append(tweetHtml);
			},
			complete: function() {}
		});
	};
})(jQuery);

不具合等があれば、コメントかツイッターで報告下さると有り難いです。

LingoesをGoogleChromeで利用する

非常に便利な右クリック辞書として有名なLingoesですが、GoogleChromeや最新のFirefox4などでは右クリックで単語を翻訳することができなくなってしまいました。
こんな時どうしたらいいかというと、Lingoesには3つの翻訳タイプがあります。

Lingoesの翻訳タイプ

右クリック翻訳

そのままの通り、右クリックしたときに、マウスカーソルの下にある単語を翻訳します。

ハイライト翻訳

文字をドラッグして選択状態にしたときに、その選択状態の単語を翻訳します。

クリップボード翻訳

文字列をクリップボードにコピーしたときに、その単語を翻訳します。

右クリック翻訳以外を利用する事で解決

このうち、GoogleChromeやFirefox4で利用できなくなってしまったのは「右クリック翻訳」です。
その他のハイライト翻訳やクリップボード翻訳はそのまま利用ができるので、そちらを使うことで解決をすることができます。

ショートカットキーで便利に

ちなみに各翻訳機能はタスクバーに表示されているLingoesのアイコンを右クリックするか、ショートカットキーでon/offの切り替えができます。

うかつにクリップボード翻訳をONのままにしておくと、何か文字列をコピーするたびに翻訳ウィンドウが出てしまいちょっとイライラするので、利用するときのみショートカットキーでONにする方法が一番ベターかと思います。

  • 右クリック翻訳 … ALT + G
  • ハイライト翻訳 … ALT + Z
  • クリップボード翻訳 … ALT + B

IEを含めた最近のブラウザでは珍しくなくなったinline-block。
このinline-blockを利用する場合に発生する「隙間」を改善する方法です。

原因は改行コード

下記のようなHTMLを用意しました。
リストタグを使ったインラインブロックを実現しようとしています。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>inline-block test</title>
</head>
<style>
.inline-block li {
	display: inline-block;
	width: 100px;
	height: 100px;
	border: 1px solid #000;
	line-height: 100px;
	text-align: center;
}
</style>
<body>

<ul class="inline-block">
<li>ボックスA</li>
<li>ボックスB</li>
<li>ボックスC</li>
</ul>

</body>
</html>

これを実際にブラウザで表示してみると。

期待していたのと違い、各リストタグの間に2px程度のマージンが空いてしまっています。
これはリストタグとリストタグの間に存在する改行が半角スペースとして表示されてしまっているからです。
その証拠に、下記のように<li>タグの間のスペースを除去してみます。

<ul class="inline-block">
<li>ボックスA</li><li>ボックスB</li><li>ボックスC</li>
</ul>

そうすると、期待通りの表示になりました。

CSSでなんとかなる

この改行コードの問題は、実に簡単なCSSで解決することができます。
インラインブロックを囲むタグ(この場合は<ul>)と、インラインブロックにとして設定するタグ(この場合は<li>)に、下記のようなCSSを適用します。

.inline-block {
	letter-spacing: -.40em; /* 文字間を詰めて隙間を削除する */
}

.inline-block li {
	display: inline-block;
	letter-spacing: normal; /* 文字間を通常に戻す */
	width: 100px;
	height: 100px;
	border: 1px solid #000;
	line-height: 100px;
	text-align: center;
}

たったこれだけで、タグの間に改行があっても正しく表示できるようになります。
使い始めると便利なインラインブロック、無駄な隙間に悩んでいる方は是非お試しあれ。

CakePHPには利用するデータベース定義を複数定義しておける機能がありますが、その使い分けに関するアイデアです。

よくある解決策

よく開発環境と本番環境で自動的にデータベース接続を切り替えられるように、以下のようにDATABASE_CONFIGクラスのコンストラクタを改良したり、AppModelクラスのコンストラクタに現在の環境を判別できるような設定を書いたりするアイデア多く見かけられます。

DATABASE_CONFIGクラスの改良

class DATABASE_CONFIG
{
	public $default = array();

	// 公開用
	public $production = array(
		'driver' => 'mysql',
		'persistent' => false,
		'host' => 'production.mysql.server',
		'login' => 'admin',
		'password' => '****',
		'database' => 'production_database',
		'prefix' => 'prefix_',
		'encoding' => 'utf8'
	);

	// 開発用
	public $development = array(
		'driver' => 'mysql',
		'persistent' => false,
		'host' => 'localhost',
		'login' => 'test',
		'password' => '****',
		'database' => 'development_database',
		'prefix' => 'prefix_',
		'encoding' => 'utf8'
	);

	public function __construct()
	{
		if (env('SERVER_ADDR') !== '127.0.0.1') {
			$this->default = $this->production;

		} else {
			$this->default = $this->development;
		}
	}
}

AppModelの改良

function __construct()
{
	if (env('SERVER_ADDR') == '127.0.0.1') {
		$this->useDbConfig = 'development';
	}  else {
		$this->useDbConfig = 'production';
	}
}

よくある解決策の問題点

よくある解決策では、httpから利用する場合には非常に便利で良いのですが、コンソールから利用する場合、この設定では不都合が発生します。

たとえばschemaコマンドを利用する場合です。
コンソールではREMOTE_ADDRやSERVER_ADDRなどの環境変数が利用できません。
そのため、コンソールで利用する場合はリモートで利用しているのかローカルで利用しているのかを環境変数から判別することができません。

であれば、schemaコマンドを実行する際に -connectionオプションで利用する接続を選択してやれば良いと考えてしまうのですが、CakePHPのコンソールから起動するschemaコマンドは、-connectionオプションで指定されたデータベース接続(指定されなければdefault)とModelのデータベース接続(Model::$useDbConfig)が一致しない場合、そのModelのスキーマを読み込んでくれません。

実行しているファイルのパスを見て判別するような荒技もありますが、実行ファイルのパスが被らない保証も無いので、こちらも確実とはいえません。

シンプルな解決策

ではどうすれば良いか、というと、Configureクラスを利用する方法が一番わかりやすくてベターです。
config/core.php もしくは config/bootstrap.php に下記のように設定します。

Configure::write('database', 'production');

そして、config/database.php のDATABASE_CONFIGクラスを下記のように記述します。

class DATABASE_CONFIG
{
	public $default = array();

	// 公開用
	public $production = array(
		'driver' => 'mysql',
		'persistent' => false,
		'host' => 'production.mysql.server',
		'login' => 'admin',
		'password' => '****',
		'database' => 'production_database',
		'prefix' => 'prefix_',
		'encoding' => 'utf8'
	);

	// 開発用
	public $development = array(
		'driver' => 'mysql',
		'persistent' => false,
		'host' => 'localhost',
		'login' => 'test',
		'password' => '****',
		'database' => 'development_database',
		'prefix' => 'prefix_',
		'encoding' => 'utf8'
	);

	public function __construct()
	{
		$connection = Configure::read('database');
		
		if (!empty($this->{$connection})) {
			$this->default = $this->{$connection};
		}
	}
}

この方法であれば、データベースを切り替えたいときはデバッグモードの切り替えのように設定値を変更するだけで済みますし、ローカルに依存するコードを記述する必要もなくなります。

さらに今後新しいデータベース接続を追加した場合にも、設定値を変更するだけで対応可能なので、今後の拡張性の面でも安心できます。

CakePHP製のCMSである Croogo のソースを眺めていて気付いたんですが、クラス内でstatic修飾子を使っていないインスタンスメソッドを、::演算子を使って静的に呼び出すと、$thisのスコープが呼び出した側のオブジェクトになるという現象に気付きました。

具体的には下記のコードを実行すると、”Test 2″ が表示されます。

class Test1
{
	public function callName()
	{
		echo $this->name;
	}
}

class Test2
{
	public $name = 'Test 2';
	
	public function callMethod()
	{
		Test1::callName();
	}
}

$obj = new Test2();
$obj->callMethod();

ちなみにstatic修飾子を付けると、Fatal errorとなるので、本来であれば推奨されない使い方のような気もします。
これってPHP5の常識なんでしょうか?