OSDN Git Service

cb8dc7e4412da2cbf48a70786bffc9b4dfbd60e4
[pettanr/clientJs.git] / 0.6.x / js / dom / 12_XDomEvent.js
1 /**
2  * use X.Callback
3  * 
4  * http://d.hatena.ne.jp/uupaa/20100430/1272561922
5  * 
6  */
7
8 if( window.addEventListener ){
9         X.Dom.Event = function( e ){
10                 //this._event        = e;
11                 this.type          = e.type;
12                 this.target        = e.target; // xnode
13                 this.currentTarget = e.currentTarget; // xnode
14                 this.relatedTarget = e.relatedTarget; // xnode
15                 this.eventPhase    = e.eventPhase;
16                 
17                 this.clientX       = e.clientX;
18                 this.clientY       = e.clientY;
19                 //this.screenX       = e.screenX;
20                 //this.screenY       = e.screenY;
21                 this.pageX         = e.pageX;
22                 this.pageY         = e.pageY;
23                 this.offsetX       = e.offsetX || e.layerX;
24                 this.offsetY       = e.offsetY || e.layerY;
25                 
26                 this.keyCode       = e.keyCode;
27                 this.altKey        = e.altKey;
28                 this.ctrlKey       = e.ctrlKey;
29                 this.shiftKey      = e.shiftKey;
30                 
31                 // http://www.programming-magic.com/20090127231544/
32                 this.which         = e.which || ( e.button + 1 ); // 左:1, 中:2, 右:3
33                 
34                 // https://developer.mozilla.org/ja/docs/DOM/DOM_event_reference/mousewheel
35                 if( e.wheelDeltaY !== undefined ){
36                         this.wheelDeltaX = e.wheelDeltaX / 12;
37                         this.wheelDeltaY = e.wheelDeltaY / 12;
38                 } else
39                 if( e.wheelDelta !== undefined ){
40                         this.wheelDeltaX = this.wheelDeltaY = e.wheelDelta / 12;
41                 } else
42                 if( e.detail !== undefined ){
43                         this.wheelDeltaX = this.wheelDeltaY = - e.detail * 3;
44                 } else {
45                         this.wheelDeltaX = this.wheelDeltaY = 0;
46                 };
47                 
48                 if( e.constructor === window.TouchEvent ){
49                         // TouchEvent
50                         this.touches        = e.touches;
51                         this.changedTouches = e.changedTouches;
52                         this.targetTouches  = e.targetTouches;
53                         //this.altKey         = e.altKey;
54                         //this.ctrlKey        = e.ctrlKey;
55                         this.metaKey        = e.metaKey;
56                         //this.shiftKey       = e.shiftKey;
57                         //this.type           = e.type;
58                         //this.target         = e.target;
59                 } else
60                 if( e.constructor === window.PointerEvent ){
61                         // PointerEvent;
62                         this.currentPoint  = e.currentPoint;
63                         this.width         = e.width;
64                         this.height        = e.height;
65                         this.timeStamp     = e.timeStamp;
66                         this.hwTimestamp   = e.hwTimestamp;
67                         this.intermediatePoints = e.intermediatePoints;
68                         this.isPrimary     = e.isPrimary;
69                         this.pointerId     = e.pointerId;
70                         this.pointerType   = e.pointerType;
71                         this.pressure      = e.pressure;
72                         this.tiltX         = e.tiltX;
73                         this.tiltY         = e.tiltY;
74                 };
75         };
76 } else {
77         X.Dom.Event = function( e, element ){
78                 var btn;
79                 
80                 //this._event        = e;
81                 this.type          = e.type;
82                 this.target        = e.srcElement; // xnode
83                 this.currentTarget = element; // xnode
84                 this.relatedTarget = e.formElement ? e.formElement : e.toElement; // xnode
85                 this.eventPhase    = e.srcElement === element ? 2: 3;
86                 
87                 this.clientX       = e.clientX;
88                 this.clientY       = e.clientY;
89                 //this.screenX       = e.screenX;
90                 //this.screenY       = e.screenY;
91                 
92                 if( X.Dom._root ){ // uuu...
93                         this.pageX         = e.clientX + X.Dom._root.scrollLeft;
94                         this.pageY         = e.clientY + X.Dom._root.scrollTop;                 
95                 };
96                 
97                 if( X.UA.IE && 5 <= X.UA.IE ){
98                         this.offsetX       = e.offsetX;
99                         this.offsetY       = e.offsetY;                 
100                 };
101                 
102                 this.keyCode       = e.keyCode;
103                 this.altKey        = e.altKey;
104                 this.ctrlKey       = e.ctrlKey;
105                 this.shiftKey      = e.shiftKey;
106                 
107                 // http://www.programming-magic.com/20090127231544/
108                 switch( this.type ){
109                         case 'click'    :
110                         case 'dblclick' :
111                                 this.which = 1;
112                                 break;
113                         case 'contextmenu' :
114                                 this.which = 3;
115                                 break;
116                         default :
117                                 btn = e.button;
118                                 this.which =
119                                         btn & 1 ? 1 :
120                                         btn & 4 ? 2 :
121                                         btn & 2 ? 3 : 0; // 左:1(click:0), 中:4, 右:2
122                 };
123                 this.wheelDeltaX = this.wheelDeltaY = e.wheelDelta / 12;
124         };
125 };
126
127 X.Dom.Event.DOM_PRE_INIT        = 0;
128 X.Dom.Event.DOM_INIT            = 1;
129 X.Dom.Event.XDOM_READY          = 2;
130 X.Dom.Event.VIEW_ACTIVATE       = 3;
131 X.Dom.Event.VIEW_DEACTIVATE     = 4;
132 X.Dom.Event.VIEW_RESIZED        = 5;
133 // before_commit_update
134 X.Dom.Event.COMMIT_UPDATE       = 6;
135 // hash_change
136 // before_unload
137 // X.Dom.Event.LOAD_BEFORE_STOP    = 7;
138 X.Dom.Event.LOAD_ASSET_COMPLETE = 7;
139 X.Dom.Event.LOAD_ASSET_ERROR    = 8;
140
141 X.Dom.Event.ANIME_BEFORE_START  = 9;
142 X.Dom.Event.ANIME_START         = 10;
143 X.Dom.Event.ANIME               = 11;
144 X.Dom.Event.ANIME_END           = 12;
145 X.Dom.Event.ANIME_BEFORE_STOP   = 13; // xnode.stop() のみ、指定時間による停止では呼ばれない
146 X.Dom.Event.ANIME_STOP          = 14;
147 X.Dom.Event._LAST_EVENT         = 14; // ここに書いてあるイベントの最後の値 X.Dom.Event.ANIME_STOP と同じ値
148
149
150 X.Dom.Node.prototype.listen = function( type, arg2, arg3, arg4 /* [ listener || ( context + function ) || function ][ arguments ] */ ){
151         var elm;
152         
153         if( this._xnodeType === 0 || this._xnodeType === 3 || !arg2 ) return this;
154         
155         ( !this._listeners || !this._listeners[ type ] ) && this._addEvent( type );
156         
157         return typeof arg2 === 'function' ?
158                 X.EventDispatcher.prototype.listen.call( this, type, this, arg2, arg3 ) :
159                 X.EventDispatcher.prototype.listen.apply( this, arguments );
160 };
161
162 X.Dom.Node.prototype._addEvent =
163         document.removeEventListener ?
164                 (function( type ){
165                         this._rawNode && this._rawNode.addEventListener( type, this, false );
166                 }) :
167         document.detachEvent ?
168                 (function( type ){
169                         if( !this._rawNode ) return;
170                         this._handleEvent = this._handleEvent || X.Callback.create( this );
171                         this._rawNode.attachEvent( 'on' + type, this._handleEvent );
172                 }) :
173                 (function( type ){
174                         var elm = this._ie4getRawNode();
175                         if( !elm ) return;
176                         this._handleEvent = elm[ 'on' + type ] = this._handleEvent || X.Callback.create( this );
177                 });
178
179
180 X.Dom.Node.prototype.unlisten = function( type /* , arg2, arg3, arg4 */ ){
181         var list = this._listeners,
182                 l    = list && type && list[ type ] && list[ type ].length;
183         
184         X.EventDispatcher.prototype.unlisten.apply( this, arguments );
185         
186         if( type !== undefined && !this._dispatching && l && !list[ type ] ){
187                 this._removeEvent( type );
188         };
189         
190         return this;
191 };
192
193 X.Dom.Node.prototype._removeEvent =
194         document.removeEventListener ?
195                 (function( type ){
196                         var elm = this._ie4getRawNode ? this._ie4getRawNode() : this._rawNode;
197                         if( !elm ) return;
198                         elm.removeEventListener( type, this, false );
199                 }) :
200         document.detachEvent ?
201                 (function( type ){
202                         var elm = this._ie4getRawNode ? this._ie4getRawNode() : this._rawNode;
203                         if( !elm ) return;
204                         elm.detachEvent( 'on' + type, this._handleEvent );
205                         if( !this._listeners ){
206                                 X.Callback._correct( this._handleEvent );
207                                 delete this._handleEvent;
208                         };
209                 }) :
210                 (function( type ){
211                         var elm = this._ie4getRawNode ? this._ie4getRawNode() : this._rawNode;
212                         if( !elm ) return;
213                         elm[ 'on' + type ] = X.emptyFunction;
214                         elm[ 'on' + type ] = '';
215                         if( !this._listeners ){
216                                 X.Callback._correct( this._handleEvent );
217                                 delete this._handleEvent;
218                         };
219                 });
220
221
222 X.Dom.Node.prototype.handleEvent =
223         document.removeEventListener ?
224                 (function( e ){
225                         var ret = X.EventDispatcher.prototype.dispatch.call( this, new X.Dom.Event( e ) );
226
227                         if( ret & X.Callback.STOP_PROPAGATION ){
228                                 e.stopPropagation();
229                         };
230                         if( ret & X.Callback.PREVENT_DEFAULT ){
231                                 e.preventDefault();
232                                 return false;
233                         };
234                 }) :
235                 (function(){
236                         var ret = X.EventDispatcher.prototype.dispatch.call( this, new X.Dom.Event( event, this._rawNode ) );
237
238                         if( ret & X.Callback.STOP_PROPAGATION ){
239                                 event.cancelBubble = true;
240                         };
241                         if( ret & X.Callback.PREVENT_DEFAULT ){
242                                 return event.returnValue = false;
243                         };
244                 });
245
246
247 // イベントの退避、dom が画面から抜かれる場合に実施しておく
248 X.Dom.Node.prototype._migrateEvent = function(){
249         var hash = this._listeners,
250                 type;
251         if( !hash ) return;
252         for( type in hash ){
253                 this._removeEvent( type );
254         };
255 };
256
257 // 退避したイベントの復帰
258 X.Dom.Node.prototype._restoreEvent = function(){
259         var hash = this._listeners,
260                 type;
261         if( !hash ) return;
262         for( type in hash ){
263                 this._addEvent( type );
264         };
265 };
266
267
268
269 /* -----------------------------------------------
270  * Document Ready
271  *  Dean Edwards/Matthias Miller/John Resig
272  */
273 /* for ie9+/Mozilla/Opera9 */
274 if( document.addEventListener ){
275         X.Dom.Node._document.listenOnce( 'DOMContentLoaded', X.Dom._init );
276 } else
277 if( 5 <= X.UA.IE && X.inHead ){
278         // if this script in Head
279         document.write( "<script id=__ie_onload defer src=javascript:void(0)><\/script>" );
280         X.Dom._script = document.getElementById( "__ie_onload" );
281         X.Dom._script.onreadystatechange = function(){
282                 this.readyState === 'complete' && X.Dom._init();
283         };
284 } else
285 if( X.UA.WebKit ){ // sniff
286         X.Timer.add( 10, function(){
287                 if( !X.Dom._init ) return X.Callback.UN_LISTEN;
288                 if( 'loaded|complete'.indexOf( document.readyState ) !== -1 ) return X.Dom._init();
289         });
290 };
291
292 /* for other browsers */
293 X.Dom.Node._window.listenOnce( 'load', X.Dom._init );
294
295 //
296 X.Dom.listenOnce( X.Dom.Event.XDOM_READY, function(e){ console.log( 'X.Dom XDomReady ' + X.Dom.ready ) } );
297
298 X.Dom.listenOnce( X.Dom.Event.VIEW_RESIZED, function(e){ console.log( 'X.Dom VIEW_RESIZED ' + e.w + 'x' + e.h ) } );
299
300
301 /* --------------------------------------
302  *  load
303  */
304 X.Dom.listenOnce( X.Dom.Event.DOM_INIT, function(){
305         
306         Node._html = document.documentElement ? new Node( document.documentElement ) : null;
307         
308         var r    = Node.root = new Node( document.body ),
309                 body = r._rawNode,
310                 createTree, n = 0, s;
311         r.appendTo = r.appendToRoot = r.before = r.after = r.clone = r.remove = r.destroy = r.prevNode = r.nextNode = new Function( 'return this' );
312         
313         if( body.childNodes ){
314                 createTree = function( xnode, elm, skipCleanup ){
315                         var     children = elm.childNodes,
316                                 i = 0,
317                                 l = children.length,
318                                 child, _xnode, text;
319                         for( ; i < children.length; ){
320                                 child = children[ i ];
321                                 switch( child.nodeType ){
322                                         case 1 :
323                                                 if( !xnode._xnodes ) xnode._xnodes = [];
324                                                 xnode._xnodes[ xnode._xnodes.length ] = _xnode = new Node( child );
325                                                 _xnode.parent = xnode;
326                                                 child.childNodes.length && createTree( _xnode, child, skipCleanup || 0 <= X.skipCleanupTagNames.indexOf( child.tagName.toLowerCase() ) );
327                                                 break;
328                                         case 3 :
329                                                 if( skipCleanup || ( ( text = child.data ) && ( text = X.cleanupWhiteSpace( text ) ) !== ' ' ) ){
330                                                         if( !skipCleanup ) child.data = text;
331                                                         if( !xnode._xnodes ) xnode._xnodes = [];
332                                                         xnode._xnodes[ xnode._xnodes.length ] = _xnode = new Node( child );
333                                                         _xnode.parent = xnode;
334                                                         break;                                                  
335                                                 };
336                                         default :
337                                                 elm.removeChild( child );
338                                                 ++n;
339                                                 continue;                                                               
340                                 };
341                                 ++i;
342                         };
343                 };
344                 createTree( r, body );
345         } else
346         if( body.children ){
347                 createTree = function( xnode, children, skipCleanup ){
348                         var i = 0,
349                                 l = children.length,
350                                 j = 0,
351                                 child, _xnode, f, tag, text;
352
353                         xnode._ie4dirtyChildren = true;
354                         for( ; i < l; ++i ){
355                                 child = children[ i ];
356                                 if( child.tagName === '!' ) continue;
357                                 f = false;
358                                 while( j < xnode._xnodes.length ){
359                                         _xnode = xnode._xnodes[ j ];
360                                         _xnode.parent    = xnode;
361                                         _xnode._ie4dirty = true;
362                                         if( _xnode._xnodeType === 1 ){
363                                                 tag = child.tagName.toLowerCase();
364                                                 if( _xnode._tag !== tag ){
365                                                         alert( _xnode._tag + ' !== ' + child.tagName + ' * ' + child.outerHTML );
366                                                 } else {
367                                                         _xnode._rawNode = child;
368                                                         !( _xnode._id = child.getAttribute( 'id' ) ) && child.setAttribute( 'id', ( _xnode._ie4uid = 'ie4uid' + _xnode._uid ) );
369                                                         child.setAttribute( 'UID', '' + _xnode._uid );
370                                                         child.children.length && createTree( _xnode, child.children, skipCleanup || 0 <= X.skipCleanupTagNames.indexOf( tag ) );
371                                                         f = true;
372                                                         ++j;
373                                                         break;
374                                                 };
375                                         } else
376                                         if( _xnode._xnodeType === 3 ){
377                                                 if( !skipCleanup && ( !( text = _xnode._text ) || ( text = X.cleanupWhiteSpace( text ) ) === ' ' ) ){
378                                                         _xnode.remove();
379                                                         ++n;
380                                                         continue;
381                                                 };
382                                                 if( !skipCleanup ) _xnode._text = text;
383                                         };
384                                         ++j;
385                                 };
386                                 if( !f ) alert( '**** ' + child.outerHTML );
387                         };
388                 };
389                 
390                 r._xnodes = [];
391                 Node.skipCreate = true;
392                 r._xnodes.push.apply( r._xnodes, X.Dom.parse( body.innerHTML, true ) );
393                 delete Node.skipCreate;
394                 createTree( r, body.children );
395                 r._ie4reserveUpdate();
396                 //alert(n +  ' ' + body.innerHTML);
397                 r._ie4startUpdate();
398                 //alert(n +  ' ' + body.innerHTML);
399         } else {
400                 
401         };
402         
403         //r.width  = new Function( 'return X.Dom.getSize()[ 0 ]' );
404         //r.height = new Function( 'return X.Dom.getSize()[ 1 ]' );
405         
406         Node._systemNode = r.create( 'div' ).className( 'hidden-sysyem-node' );
407         r._xnodes.splice( r._xnodes.indexOf( Node._systemNode ), 1 ); // hide from api user
408 } );
409
410