iPod & iPad & iPhoneで、クリックイベントを発火させて、それを使えるようにする! その3
考えるほどに、また無駄に長くなってしまいます。^^;
「シングルトン」、あ〜簡易版、簡易版、簡易版。(毎度の事ながら、思考はどっちに向いているのだろう?(涙))
マウスイベントもオブジェクトにしました。
<!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); //_________________________________ //つまらないコードから。(シングルトン) // Singleton function createSingleton () { var stock_object = []; var stock_option = []; function getIndex (obj) { return stock_object.indexOf (obj); } return { 'contains' : (function (/*obj*/) { for (var i = 0, obj; obj = arguments[i++]; ) if (-1 < getIndex (obj)) return true; return false; }), 'add' : (function (obj, option) { if (! this.contains (obj)) { stock_object.push (obj); stock_option.push (option); } }), 'remove' : (function remove (/*obj*/) { var i, idx; for (i, obj; obj = arguments[i++]; ) { idx = getIndex (obj); if (-1 < idx) { stock_object.splice (idx, 1); stock_option.splice (idx, 1); } } }), 'length' : (function () { return stock_object.length; }), 'getOption' : (function (obj) { var idx = getIndex (obj); return (-1 < idx) ? stock_option[idx]: null; }), 'replaceOption' : (function (obj, option) { var idx = getIndex (obj); if (-1 === idx) return false; stock_option[idx] = option; return true; }) }; } //################# (function () { // createMouseEvent var defMouseState = { 'type' : null, 'canBubble' : true, 'cancelable' : true, 'view' : null, 'detail' : 1, 'screenX' : 0, 'screenY' : 0, 'clientX' : 0, 'clientY' : 0, 'ctrlKey' : false, 'altKey' : false, 'shiftKey' : false, 'metaKey' : false, 'button' : 0, 'relatedTarget' : null } function MouseEventArguments (arg) { this.arg = arg; } function cloneObject (obj) { var result = {}; for (var i in obj) if (obj.hasOwnProperty (i)) result[i] = obj[i]; return result; } function replaceObject (obj) { for (var i in obj) if (obj.hasOwnProperty (i)) if (this.hasOwnProperty (i)) this[i] = obj[i]; } function create (arg) { var obj = new MouseEventArguments; var state = { }; var view; var doc; obj.configure = (function (o) { if (o) replaceObject.call (state, o) }); obj.reset = (function () { state = cloneObject (defMouseState) this.configure (arg); }); obj.fire = (function (target) { if (target && state.type) { var doc = (9 === target.nodeType) ? target : target.ownerDocument; var view = doc.defaultView; var evt = doc.createEvent ('MouseEvents'); evt.initMouseEvent ( state.type, state.canBubble, state.cancelable, state.view, state.detail, state.screenX, state.screenY, state.clientX, state.clientY, state.ctrlKey, state.altKey, state.shiftKey, state.metaKey, state.button, state.relatedTarget ); target.dispatchEvent (evt); } }); obj.reset (); return obj; } this.createMouseEvent = create; })(); (function () { //_________________________________ function Emulator (range, disabled) { this.range = range; this.disabled = disabled; } var handler = (function () { var state = false; var point = { 'x' : 0, 'y' : 0 }; return function (event) { if (this.disabled) return; var touch = event.touches; var eType = event.type; var range = this.range; if (state) { if (('touchmove' === eType) && (touch = touch[0])) { if ((Math.abs (touch.pageX - point.x) < range) || (Math.abs (touch.pageY - point.y) < range)) { state = false; } else { point.x = touch.pageX; point.y = touch.pageY; } } else if ('touchend' === eType) { this.fire (event.target, point); event.preventDefault (); } } else if (('touchstart' === eType) && (1 === touch.length) && (touch = touch[0])) { point.x = touch.pageX; point.y = touch.pageY; state = true; } }; })(); // クリック・エミュレータ初期化 function create (view, range, disabled) { if (! /iPhone|iPad|iPod/.test (navigator.userAgent)) // 簡易機種チェック return null; var doc = view ? view.document: document; var evt = createMouseEvent (doc); var emu; if (singleton.contains (doc)) { return singleton.getOption (doc); } emu = new Emulator (range || 10, !!disabled); emu.fire = (function (target, point) { var doc = target.ownerDocument; if (3 === target.nodeType) target = target.parentNode; evt.configure ({ 'type' : 'click', 'view' : doc.defaultView, 'screenX' : point.x, 'screenY' : point.y, 'clientX' : point.x, 'clientY' : point.y, 'relatedTarget' : doc.body }); evt.fire (target); }); singleton.add (doc, emu); doc.addEventListener ('touchstart', emu, false); doc.addEventListener ('touchmove', emu, false); doc.addEventListener ('touchend', emu, false); return emu; } Emulator.prototype.handleEvent = handler; var singleton = createSingleton (); this.ClickEmulator = create; })(); ClickEmulator (); </script>
その4
確かに、view を保存するようにする意味は無いですね
<!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 () { if (! /iPhone|iPad|iPod/.test (navigator.userAgent)) // 簡易機種チェック return null; var doc = document; var view = doc.defaultView; var Eventer = (function () { // object の複製 function cloneObject (obj) { var result = { }, i; for (i in obj) if (obj.hasOwnProperty (i)) result[i] = obj[i]; return result; } var object = { 'defArguments' : { // document.createEvent の default の 引数 'type' : null, 'canBubble' : true, 'cancelable' : true, 'view' : view, 'detail' : 1, 'screenX' : 0, 'screenY' : 0, 'clientX' : 0, 'clientY' : 0, 'ctrlKey' : false, 'altKey' : false, 'shiftKey' : false, 'metaKey' : false, 'button' : 0, 'relatedTarget' : doc }, 'arguments' : { }, // (a) 実際に利用される引数 'reset' : // 引数を default に戻す (function () { this.arguments = cloneObject (this.defArguments); }), 'configure' : // 引数(a)を置き換える (function (obj) { for (var i in obj) if (obj.hasOwnProperty (i)) // obj に含まれるものだけ if (this.arguments.hasOwnProperty (i)) this.arguments[i] = obj[i]; }), 'fire': (function (target) { var arg = this.arguments; if (target && arg.type) { var evt = doc.createEvent ('MouseEvents'); evt.initMouseEvent ( arg.type, arg.canBubble, arg.cancelable, arg.view, arg.detail, arg.screenX, arg.screenY, arg.clientX, arg.clientY, arg.ctrlKey, arg.altKey, arg.shiftKey, arg.metaKey, arg.button, arg.relatedTarget ); target.dispatchEvent (evt); arg.type = null; } }) } object.reset (); return object; })(); var Emulator = (function () { var state = false; var point = { 'x' : 0, 'y' : 0 }; var object = { 'range' : 10, 'disabled' : false, 'configure' : (function (parm) { Eventer.configure (parm); }), 'handleEvent' : (function (event) { if (this.disabled) return; var touch = event.touches; var eType = event.type; if (state) { if (('touchmove' === eType) && (touch = touch[0])) { if ((Math.abs (touch.pageX - point.x) < this.range) || (Math.abs (touch.pageY - point.y) < this.range)) { state = false; } else { point.x = touch.pageX; point.y = touch.pageY; } } else if ('touchend' === eType) { this.fire (event.target, point); event.preventDefault (); } } else if (('touchstart' === eType) && (1 === touch.length) && (touch = touch[0])) { point.x = touch.pageX; point.y = touch.pageY; state = true; } }), 'fire' : (function fire (target, point) { if (3 === target.nodeType) target = target.parentNode; this.configure ({ 'type' : 'click', 'screenX' : point.x, 'screenY' : point.y, 'clientX' : point.x, 'clientY' : point.y, }); Eventer.fire (target); }) }; return object; })(); //___________________ doc.addEventListener ('touchstart', Emulator, false); doc.addEventListener ('touchmove', Emulator, false); doc.addEventListener ('touchend', Emulator, false); this.ClickEmulator = Emulator; })(); </script>