まだ重たいCMSをお使いですか?
毎秒 723リクエスト を捌く超高速CMS「adiary

2015/05/14(木)スマホでドラッグ&ドロップのエミュレーション

jQuery UIdynatree を使用していて、ドラッグアンドドロップ操作が必須であるにも関わらずスマホでは何もできないので、汎用的な実装をjQuery pluginで実現しました。

タッチ操作でDnDをエミュレーションする

タッチパネル系イベントは独特らしく、短くタップしたときのみ mousedown や click 等のマウスイベントが発生してくれますが、長く触っているとマウスイベントは発生しないようです。

ですので、以下のように実装しました。

  • touchstart で mousedown を発火。
  • touchmove で mousemove を発火し、mouseleave と mouseenter をエミュレーション。
  • touchend で mouseup を発火。

mouseover, mouseoutも実装はできますが無視しました。jQuery UIが問題なく動く程度には実装しているつもりです。

エミュレーションがonの状態で短くタップすると、mousedown/mouseupイベントが2重に発生する可能性がありますが、解決策がないので保留です。

ソース

修正BSDライセンスとします。jQuery pluginですので適当に読み込ませて次のように使ってください。

$(dom).dndEmulation();

以下のソースは最新でない可能性があります。最新版は、adiaryのサイトからGitHub経由で「js/adiary.js」を参照して該当部のみ抜粋してください。該当部のみ抜粋する限り修正BSDライセンスで扱って構いません。

var TouchDnDTime  = 700;
$.fn.extend({
//////////////////////////////////////////////////////////////////////////////
// Copyright (C)2015 nabe@abk, New BSD License.
//////////////////////////////////////////////////////////////////////////////
dndEmulation: function(){
	var self = this[0];
	if (!self) return;

	// mouseイベント作成
	function make_mouse_event(name, evt, touch) {
		var e = $.Event(name);
		e.altKey   = evt.altKey;
		e.metaKey  = evt.metaKey;
		e.ctrlKey  = evt.ctrlKey;
		e.shiftKey = evt.shiftKey;
		e.clientX = touch.clientX;
		e.clientY = touch.clientY;
		e.screenX = touch.screenX;
		e.screenY = touch.screenY;
		e.pageX   = touch.pageX;
		e.pageY   = touch.pageY;
		e.which   = 1;
		return e;
	}
	// 自分自身を含めた親要素をすべて取得
	function get_par_elements(dom) {
		var ary  = [];
		while(dom) {
			ary.push( dom );
			if (dom == self) break;
			dom = dom.parentNode;
		}
		return ary;
	}

	// クロージャ変数
	var prev;
	var flag;

	// mousedownエミュレーション
	this.bind('touchstart', function(_evt){
		var evt = _evt.originalEvent;
		prev = evt.target;
		var e = make_mouse_event('mousedown', evt, evt.touches[0]);
		$( prev ).trigger(e);
		
		// ある程度時間が経過しないときは処理を無効化する。
		flag = false;
		setTimeout(function(){
			flag=true;
		}, TouchDnDTime)
	});

	// mouseupエミュレーション
	this.bind('touchend', function(_evt){
		var evt = _evt.originalEvent;
		var e = make_mouse_event('mouseup', evt, evt.changedTouches[0]);
		$( evt.target ).trigger(e);
	});

	// ドラッグエミュレーション
	this.bind('touchmove', function(_evt){
		var evt = _evt.originalEvent;

		// 一定時間立たなければ、処理を開始しない
		if (!flag) return;

		var touch = evt.changedTouches[0];
		var dom   = document.elementFromPoint(touch.clientX, touch.clientY);
		var enter = get_par_elements(dom);

		// マウス移動イベント
		var e = make_mouse_event('mousemove', evt, touch);
		$(enter).trigger(e);

		// 要素移動がなければこれで終了
		evt.preventDefault();
		if (dom == prev) return;

		// 要素移動があれば leave と enter イベント生成
		var leave = get_par_elements(prev);

		// 重複要素を除去
		while(leave.length && enter.length
		   && leave[leave.length -1] == enter[enter.length -1]) {
			leave.pop();
			enter.pop();
		}

		// イベント発火
		var e_leave = make_mouse_event('mouseleave', evt, touch);
		var e_enter = make_mouse_event('mouseenter', evt, touch);
		$(leave).trigger( e_leave );
		$(leave).trigger( e_enter );

		// 新しい要素を保存
		prev=dom;
	});
}
//////////////////////////////////////////////////////////////////////////////
});

2015/05/13(水)Lightbox2 にスワイプ対応パッチを充てた

充てたというかパッチしました。作りました。jQueryのみです。

画像をめくるときにタッチパネルのスワイプ操作でも反応するようになっています。特にアニメーションはしません。

jQueryのバグなのか「touchstart」「touchmove」イベントを全く拾わないので、「window.addEventListener」に逃げました。もしもっとスマートな解決方法を見つけたら教えてください。

これを使用しているadiaryもよろしくお願いします

その他の変更点

#lightbox-min-width {
	display:		none;
	width:			300px;
}

と設定すると、横幅が小さすぎる画像を表示するとき、指定したピクセルまでアスペクト比を保持して拡大して表示します。

極端に縦長の画像の場合はアスペクト比を保持できて、画面に収まる範囲内で拡大されます。

2012/08/22(水)input type="text"等の自由リサイズスクリプト

Google ChromeやFirefoxには標準で<textarea>の自由リサイズ機能(マウスでのリサイズ機能)がありますが、input type="text"等のテキストボックスにはその機能がありません。

jQueryで実装してみました。

使い方

以下のCSSとJavaScriptを導入してください。あとは自動的に機能が導入されます。

  • jQueryを先にロードしてください。必要バージョンは分かりません(苦笑)
  • Google ChromeとFirefoxで動作確認しています。
  • CSSの width が掴める部分のサイズになります。
  • CSSの z-index の下3桁(1000で割った余り)がテキストボックスの最小サイズになります。*1
  • CSSの display:none を有効にするとフォームリサイズ機能を無効にできます。
    • テキストボックスの初期サイズの方が小さい場合はそちらが最小サイズになります。
  • IE6,7で動作しましたが、IE8,9では動作しませんでした(動作しないだけで不具合はありません)。
    • 手前にあるspanよりも裏側にあるテキストボックスが優先される謎の仕様のせいです。

続きを読む

2011/05/25(水)enterでフォ-ム内容を送信させない細工

JavaScript

//-----------------------------------------------------------------------------
// ●enterで送信させない
//-----------------------------------------------------------------------------
// Tested : Fx4, GC, IE7/8
function enter_not_submit(evt) {
	evt = evt ? evt : event;
	var e = evt.target || evt.srcElement;
	if (e.tagName != 'INPUT') return true;
	if (evt.keyCode == 13) return false;
	return true;
}

フォーム側

<form action="" method="POST" onkeypress="return enter_not_submit(event);">
	(フォーム内容)
</form>

Formに仕込むだけです。INPUTタグやSubmitボタンの細工は不要。

全INPUT要素を探し出してイベントを登録するハンドラのような無駄な処理も不要。

2010/02/18(木)画像の縦横中央配置 / CSS / クロスブラウザ

画像の縦横中央配置

HTMLのソース。余計な改行やスペースを入れないこと。

<div class="image"><span class="dummy"></span><img src="xxx.png" /></div>

CSS。

div.image {
	border:		1px solid #8ff;

	min-width:	320px;
	width:		320px;
	height:		240px;
	_width:		322px;
	_height:	242px;

	text-align:	center;
	display:	block;
}
div.image span.dummy {
	height:		240px;
	width:		0px;
	vertical-align:	middle;
	display:	inline-block;
}
div.image img {
	max-width:	320px;
	max-height:	240px;
	vertical-align:	middle;

	/* IE6 hack */
	_margin-top:	-1px;
	/* IE6 でアスペクト比保存縮小のためのhack */
	_width:		expression(this.height>240 && this.width*3<this.height*4 ? Math.floor(this.width*240/this.height) : (this.width > 320 ? 320: true ));
	_height:	expression(this.height>240 ? 240: true );
}
*:first-child+html div.image img { /* IE7 hack */
	margin-top:	-1px;
}
  • 画像領域は320*240。
  • モダンブラウザは問題なく表示。
  • IE6は後方互換モード、IE7は標準準拠モード+ie8.js。
  • "margin-top: -1px;"してあげないと画像がなぜか下に1pxずれてしまう。

「span.dummy」を「display: inline-block」するのが縦方向センタリングのポイントです。

IE6で縦横比保存なmax-width, max-height

img {
	max-width:	320px;
	max-height:	240px;
	_width:		expression(this.height>240 && this.width*3<this.height*4 ? Math.floor(this.width*240/this.height) : (this.width > 320 ? 320: true ));
	_height:	expression(this.height>240 ? 240: true );
}

240と320を好みのサイズに変更してください。

OK キャンセル 確認 その他