<!DOCTYPE html>
<title>クリック・モドキ</title>
<meta name="viewport" content="width=640">
<style>
h1 {
font-size: large;
}
h3 {
margin-bottom : 0;
}
h3 + p {
font-size: small;
color: gray;
margin : 0 2em;
}
em {
color: green;
font-size:x-large;
}
li.focus {
border-bottom : 2px red dotted;
}
</style>
<body>
<h1>
<em>iPod</em> &
<em>iPad</em> &
<em>iPhone</em> で、クリックイベントを有効にする
</h1>
<h3>クリックイベントが発生する状態</h3>
<ul>
<li>document をクリック(タップ)した時
<li>フォームの input要素(button)など
<li>要素のインラインに書いたイベント
</ul>
<h3>クリックイベントの代わりに、touchstart, touchmove, touchend を利用する</h3>
<p>(3つのイベントを組み合わせて、クリックイベントを実現する)
<ul>
<li>touchstart イベントが発生したら、スタート位置を記憶する
<li>touchmove を監視し、現在位置との差が範囲外なら、止める
<li>touchend イベントオブジェクトからは、位置が拾えないので、スタート位置を基準とし、
クリックイベントを発生させる
</ul>
<h3>使い方</h3>
<ul>
<li>
<p>面倒なので略。
</ul>
<script>
document.addEventListener ('click', function (e) {
var n = e.target;
n.className = n.className ? '': 'focus';
}, false);
(function () {
function isAppleMobile () {
return (/iPhone|iPad|iPod/.test (navigator.userAgent));
}
function createObject (arg, args) {
var Func = new Function;
var result;
Func.prototype = arg;
result = new Func;
if (args)
defineProperties.call (result, arg);
return result;
}
function defineProperties (args) {
for (var n in args)
if (args.hasOwnProperty (n))
this[n] = args[n];
}
function reset () {
this.args = createObject (DEF_EVENT_ARG);
}
function configure (parm) {
defineProperties.call (this.args, parm);
}
function fire (target) {
var e = DOC.createEvent ('MouseEvents');
var p = this.args;
e.initMouseEvent ('click', p.bubbles, p.cancelable, VIEW, p.detail,
p.screenX, p.screenY, p.screenX, p.screenY,
p.ctrlKey, p.altKey, p.shiftKey, p.metaKey, p.button, null);
target.dispatchEvent (e);
}
function emu_configure (parm) {
configure.call (Eventer, parm);
}
function isInside (x, y) {
return ((Math.abs (x - this.x) < RANGE) &&
(Math.abs (y - this.y) < RANGE));
}
function emu_handler (event) {
if (this.disabled)
return;
var touch = event.touches;
var eType = event.type;
var x, y;
var t;
if (STATE) {
if (('touchmove' === eType) && (touch = touch[0])) {
x = touch.pageX;
y = touch.pageY;
if ((STATE = isInside.call (POINT, x, y))) {
POINT.x = x;
POINT.y = y;
}
}
else if ('touchend' === eType) {
t = event.target;
if (3 === t.nodeType) {
this.fire (t.parentNode, POINT);
return event.preventDefault ();
}
}
}
else if (('touchstart' === eType) && (1 === touch.length) && (touch = touch[0])) {
POINT.x = touch.pageX;
POINT.y = touch.pageY;
STATE = true;
}
}
function emu_fire (target, point) {
Eventer.configure ({'screenX': point.x, 'screenY': point.y});
Eventer.fire ((3 === target.nodeType) ? target.parentNode: target);
}
if (isAppleMobile ()) {
var DOC = document;
var VIEW = DOC.defaultView;
var RANGE = 10;
var STATE = false;
var POINT = {
'x' : 0,
'y' : 0
};
var DEF_EVENT_ARG = {
'bubbles' : true,
'cancelable' : true,
'detail' : 1,
'screenX' : 0,
'screenY' : 0,
'ctrlKey' : false,
'altKey' : false,
'shiftKey' : false,
'metaKey' : false,
'button' : 0,
};
var Eventer = new Function;
Eventer.args = null;
Eventer.reset = reset;
Eventer.configure = configure;
Eventer.fire = fire;
var Emulator = new Function;
Emulator.disabled = false;
Emulator.configure = emu_configure;
Emulator.handleEvent = emu_handler;
Emulator.fire = emu_fire;
DOC.addEventListener ('touchstart', Emulator, false);
DOC.addEventListener ('touchmove', Emulator, false);
DOC.addEventListener ('touchend', Emulator, false);
Eventer.reset ();
this.ClickEmulator = Emulator;
}
})();
</script>