onpasteはペースト直前に実行される

JavaScriptで右クリックからペーストを選択した時に、それをトリガーにして何かを実行したいとする。たとえば、textareaに文字列を入力すると、入力結果をプレビュー欄に表示させる、というような場合。

ctrl+Vならonkeyupでいい。だけどマウスの右クリックでペーストすると、それではダメだ。キーボードは叩いていないんだからイベントが発生しない。

onmouseupでいけるだろうと思ったが、うまくいかない。少なくともFirefoxでは反応しなかった。

どのボタンでクリックされたか判別する【JavaScript】 – Programming Magicという記事を拝見したところ、Firefoxではマウスの右クリックは拾えないようだ。

ならば、ということでonpasteというイベントを使ってみた。実はこのイベントを使ったのは初めてなんだけど、ペーストした追加部分がプレビューに含まれていない。

調べてみたら、onpasteはペーストする直前のタイミングで処理を行なうらしい。
うーん。としばらく考えたけど、setTimeout関数を使って実現できた。

<textarea name="ta" id="ta" onclick="clear_value(this);" onkeyup="preview();" onpaste="setTimeout(preview,10);">
ここにご記入ください。
</textarea>

<div id="pv"></div>

<script type="text/javascript">
<!--
var flag={"ta":0};
var ta=document.getElementById('ta');
var pv=document.getElementById('pv');

var clear_value=function(elem){
	if(!flag[elem.name]){
		elem.value='';
		flag[elem.name]++;
	}
}

var preview=function(){
	pv.innerHTML=ta.value;
}
// -->
</script>

setTimeoutなし (続けて2回右クリックでペーストするとわかる)


setTimeoutあり (狙いどおりの動作)

クリスマスの運命を占います

名前を入れるとクリスマスの運命を占ってくれるページです。



クリスマスの運命を占います  

字数の違う右寄せ2行の先頭を揃える

レイアウトによっては下のサンプル(これは「手芸部」の最新記事です)の赤文字みたいに
右寄せなんだけど行の始まりを同じ位置にしたい時があります。そういった時の解決方法です。
下のサンプルでは、青文字が普通の右寄せ(text-align:right)、
赤文字が、これから説明するfloat:rightを使っています。

次の2行ですが、普通に右寄せにするとこうなります。

ひと目 ひと目 手を動かして何かを編んでいると、
時間がたつのも忘れ、充実感のある最高に贅沢なひとときが味わえます。

これはスタイルシートならtext-alignで、
スタイルシートがわからなくても、ブログの編集画面で右寄せのマークを押せば簡単に出来ます。

でも、レイアウトによっては下のサンプル(これは「手芸部」の最新記事です)の赤字部分みたいに
右寄せなんだけど行の始まりを同じ位置にしたい時があります。そういった時の解決方法です。

下のサンプルでは、青文字が普通の右寄せ(text-align:right)、
赤文字が、これから説明するfloat:rightを使っています。


手編みするあったかい冬時間。大切なあの人へ。。あったかい冬をおくろう。
Isn’t warm winter presented to the important man?

ポイントは「作り目」と「編み方」と「伏せ止め」だけです!
これだけで、誰でも、簡単にマフラーが編めちゃいます!

自分のために、夢中で編んだり。大切な人のために、大事に編んだり。

ひと目 ひと目 手を動かして何かを編んでいると、
時間がたつのも忘れ、充実感のある最高に贅沢なひとときが味わえます。

何より手編みをしていると、寒い冬の季節でも、
なんだか気持ちがあったかくなってきます。

手編みには、冬の寒さが待ち遠しくなるような、
柔らかで優しいぬくもりがあります。


末尾で合わせる普通の右寄せ

ひと目 ひと目 手を動かして何かを編んでいると、
時間がたつのも忘れ、充実感のある最高に贅沢なひとときが味わえます。

この方法は、以前このブログの記事「枠の中の背景に画像を使いたい! 」で説明していますが、
もう一度書きます。

文章の配置にはスタイルシートのtext-alignを使います。

文字を右に寄せたいときはtext-align:right;と指定します。

文字を左に寄せたいときはtext-align:left;と指定しますが、普通は書かなくて構いません。
通常は指定しなければ自動でtext-align:left;とみなされるからです。

文字を真ん中に合わせたいときはtext-align:center;と指定します。
下がtext-align:center;のサンプルです。

ひと目 ひと目 手を動かして何かを編んでいると、
時間がたつのも忘れ、充実感のある最高に贅沢なひとときが味わえます。

スタイルシートの書き方は以前の記事「で、スタイルシートはどこに書くのか?」に書いています。
今回はインラインでの書き方だけ説明します。

普段はブログの編集画面に文章を書くだけなので、知らない人もいるかもしれません。
説明すると、HTMLでは<p>から</p>の間に文章を書きます。

自分はそんなことした覚えはない。という方も自分のブログのソースを見るとそうなっています。
それは文字を書いて公開すると、ブログが勝手にHTMLに変換してくれるからです。

この最初の<p>の中にスタイルシートを書き込む事ができます。これがインラインでの記述方法です。具体的には下のように書きます。

<p style="text-align:right;">ひと目 ひと目 手を動かして何かを編んでいると、<br/>時間がたつのも忘れ、充実感のある最高に贅沢なひとときが味わえます。</p>

<pのpの後に半角スペースを1文字入れてからstyle=”text-align:right;”と書きます。その後に>と書いてから文章。文章が終わったら、</p>と書きます。<p>から</p>までが一つの文章です。

<pの後は半角スペースです。全角スペースはエラーです。同じように<から>の間のアルファベットや記号は半角で書きます。ちゃんと書いたのに出来ないというときは、半角で書いているかを確認します。

文中に<br />とあるのは改行の印です。

HTMLでは<br />が出てこない限り改行とみなされません。文章を書いているときに何回Enterキーを押して改行しても、それはHTML上では改行とみなされていません。<p>や</p>と同じようにブログが自動で、Enterキーを押す度に<br />を挿入しているから改行して表示されるだけです。

確認:末尾で合わせる普通の右寄せの書き方

<p style="text-align:right;">ひと目 ひと目 手を動かして何かを編んでいると、<br/>時間がたつのも忘れ、充実感のある最高に贅沢なひとときが味わえます。</p>

行の始まりを左に合わせた右寄せ

ひと目 ひと目 手を動かして何かを編んでいると、
時間がたつのも忘れ、充実感のある最高に贅沢なひとときが味わえます。

全体をまとめて右や左に寄せるに時はfloatを使います。

右寄せにするにはfloat:right;と書きます。
左寄せにしたければfloat:left;と書きますが通常は必要ありません。

またtext-alignの時のcenterのように真ん中合わせはできません。右寄せか、左寄せだけです。

行の始まりを左に合わせた右寄せの具体的なソースは下のようになります。

<p style=”float:right;“>ひと目 ひと目 手を動かして何かを編んでいると、<br/>時間がたつのも忘れ、充実感のある最高に贅沢なひとときが味わえます。</p>

text-alignは指定しなければ、text-align:left;と同じと先ほど書きました。
つまり上のコードは左合わせの、改行した2行の文章を右側に配置ということです。

これで右側に配置されますが、floatを使う場合は気をつけないといけないことがあります。

“字数の違う右寄せ2行の先頭を揃える” の続きを読む

PDOでストアドプロシージャの結果取得

一つ前の記事で書いたように、MySQLのストアドプロシージャを使ったアプリを書いたんですが、
ストアドプロシージャで作ったデータをPHPのPDOでどう取得すればいいのかわからなかったので覚書き。

参考までにつくったのは下のものです。ちなみに「ふっかつのじゅもん」はアクセス誘導のために
別の場所に書いてあったんですが、ここにも書いておきます。「モウイッカイ」です。


ハロウィンの運命






入力したデータをRESTで送って、返却値をJavaScriptで黄色い枠内に書き込んでいます。

送信するデータは以下のとおりです。

  • id : 結果表示場所のid
  • hidden : 送信ボタンの上に追加する表示部分のid
  • type : halloween、xmas、otherのどれかを指定(他でも使いまわすため)
  • name : 入力された名前
  • pass : ふっかつのじゅもん(オプション)

上記パラメータを受信したサーバー側で、JavaScriptを生成。それを送り返して来ます。
その戻ってきたデータを読み込んだブラウザで、スクリプトが作動して結果が表示されます。

サーバー側のPHPソースですが、パラメーター取得方法とエラー処理、それから生成されるJavaScriptに関しては、今回のテーマと違うので省略します。

プロシージャの仕様は以下のとおりです。

fortune(OUT _string VARCHAR(2048), IN _user VARCHAR(128), IN _type VARCHAR(128), IN _pass VARCHAR(1024));

コマンドで使うときは以下のカンジです。

call fortune(@str, “username”, “halloween”, “password”);
SELECT @str;

以下、PDOでストアドプロシージャのデータを取得する部分のソースです。

ちなみにコメントアウトしてある3行ですが、環境によって必要であったり、なかったりします。
実際に設置したのはCORESERVERですが、CORESERVERでは、ないと文字化けしますのでコメントアウトは外して有効にしてあります。ただ、ローカルのLinux mintにaptで構築した環境では不要でした。

$host="localhost";
$dbname="xxxxxxxxxxxxx";
$username="xxxxxxxxxxxxx";
$password="xxxxxxxxxxxxx";

$base="var pos=document.getElementById('%s');以下省略";

try{
	$pdo=new PDO("mysql:host=$host;dbname=$dbname",$username,$password);

	//以下の3行は環境によっては必要
	//$pdo->query("SET character_set_client=utf8");
	//$pdo->query("SET character_set_connection=utf8");
	//$pdo->query("SET character_set_results=utf8");

	$stmt=$pdo->prepare("call fortune(@str,?,?,?)");

	$stmt->bindValue(1,$name,PDO::PARAM_STR);
	$stmt->bindValue(2,$type,PDO::PARAM_STR);
	$stmt->bindValue(3,$pass,PDO::PARAM_STR);

 	$stmt->execute();

	header("Content-type: text/javascript; charset=UTF-8");
	printf($base,$id,$pdo->query('SELECT @str')->fetchColumn());
}catch(PDOException $e){
	header("HTTP/1.1 500 Internal Server Error");
}

$pdo=null;

prepareを使って処理するということがわかれば簡単なのですが、そこにたどり着くまで苦労しました。

bindValueの第3引数には、第2引数の型を指定します。
今回はたまたま文字列型だけでしたが、PHPのマニュアルページに色々な型が書いてあります。

MySQLのストアドプロシージャでIF文のインデントはNGぽい

ハロウィンの運命」というアプリを作ってみたんだけど
MySQLのストアドプロシージャ記述でハマりました。

どこが間違っているのかどうしてもわからずにいろいろやってみたんだけど、
ずっとエラーが解消されない。大雑把に書くとかんなかんじ。

ちなみに、ひとつ目のSELECTとふたつ目のSELECTは対象のテーブルが違います。
最初のSELECTでパラメーターの確認をして、正しければ本来の処理を行なうという内容です。

delimiter //
CREATE PROCEDURE fortune(OUT _s VARCHAR(2048), IN _u VARCHAR(128))
BEGIN
IF (SELECT COUNT(*) FROM fortune_type WHERE name=_u) = 0 THEN
	SELECT '"type" パラメーターが間違っています' INTO _s;
ELSE
	IF (SELECT COUNT(*) FROM fortune_name WHERE name=_u) = 1 THEN
		DELETE FROM fortune_saved WHERE name=_u;
	END IF;
(中略)
END IF;
END;
//
delimiter ;

これを、ブロックごとに分けて登録してみるとすんなりOKになる。
どうも文法的には間違っていないっぽい。

IF文のネストがあったので、そこを字下げしてたんだけど
試しにと思って、インデントを削除してみたらすんなり入った。

IFの前にはインデントをつけたらいけないみたいです。

これだとOKになる。

delimiter //
CREATE PROCEDURE fortune(OUT _s VARCHAR(2048), IN _u VARCHAR(128))
BEGIN
IF (SELECT COUNT(*) FROM fortune_type WHERE name=_u) = 0 THEN
	SELECT '"type" パラメーターが間違っています' INTO _s;
ELSE
IF (SELECT COUNT(*) FROM fortune_name WHERE name=_u) = 1 THEN
	DELETE FROM fortune_saved WHERE name=_u;
END IF;
(中略)
END IF;
END;
//
delimiter ;