OSDN Git Service

Version 0.6.76, changed _rawNode to _rawObject.
[pettanr/clientJs.git] / 0.6.x / js / 00_core / 06_XEventDispatcher.js
1 /**\r
2  * X.EventDispatcher\r
3  * \r
4  *  1. as3 の EventDispatcher ライクなクラス。そのまま使ったり、継承したり。コールバック中にイベントを追加したら?削除したら?にも対処している。\r
5  *  2. _rawObject メンバがいる場合、addEventListener, attachEvent, on 等で生のブラウザオブジェクトにリスナを登録する。\r
6  *     window, document, HTMLElement, Image, XHR などが _rawObject\r
7  * \r
8  * use X.Callback\r
9  * \r
10  * https://developer.mozilla.org/ja/docs/Web/API/EventTarget.addEventListener\r
11  * イベント発送中のリスナーの追加\r
12  * EventListener がイベント処理中に EventTarget に追加された場合、それが現在のアクションによって実行されることはありませんが、浮上フェーズのように、後の段階のイベントフローで実行されるかもしれません。\r
13  * \r
14  * https://developer.mozilla.org/ja/docs/Web/API/EventTarget.removeEventListener\r
15  * イベントリスナーが イベントを処理中であるイベントターゲットから削除された場合、現在のアクションによってそのイベントリスナーが実行されることはありません。\r
16  * イベントリスナーは、決して削除された後に実行されることはありません。\r
17  * イベントターゲット上にある現在のどのイベントリスナーも指定していない引数付きの removeEventListener は、何の効果もありません。\r
18  */\r
19 \r
20 X.Event = {\r
21         COMPLETE      : 1,\r
22         SUCCESS       : 2,\r
23         ERROR         : 3,\r
24         PROGRESS      : 4,\r
25         BEFORE_CANCEL : 5,\r
26         CANCELED      : 6,\r
27         TIMEOUT       : 7,\r
28         // INSTANCE_KILLED\r
29         // KILL_INSTANCE_CANCELED\r
30         _LAST_EVENT   : 7\r
31 };\r
32 \r
33 // --- define / local variables ----------------------------\r
34 var x_eventdispatcher_once       = false,\r
35         x_eventdispatcher_needsIndex = false,\r
36         x_eventdispatcher_temp       = {};\r
37 \r
38 if( X.UA.MacIE ){\r
39         x_eventdispatcher_temp.DOM_W3C    = true;\r
40         x_eventdispatcher_temp.EVENT_DOM0 = true;\r
41 } else\r
42 if( X.UA.IE4 ){ // ie4 & iemobi4\r
43         x_eventdispatcher_temp.DOM_IE4    = true;\r
44         x_eventdispatcher_temp.EVENT_DOM0 = true;\r
45 } else\r
46 if( document.getElementById ){\r
47         x_eventdispatcher_temp.DOM_W3C = true;\r
48         if( document.addEventListener ){\r
49                 x_eventdispatcher_temp.EVENT_W3C = true;\r
50         } else\r
51         if( document.attachEvent ){\r
52                 x_eventdispatcher_temp.EVENT_IE = true;\r
53         } else {\r
54                 x_eventdispatcher_temp.EVENT_DOM0 = true;\r
55         };\r
56 } else\r
57 if( document.all ){\r
58         x_eventdispatcher_temp.DOM_IE4    = true;\r
59         x_eventdispatcher_temp.EVENT_DOM0 = true;\r
60 } else\r
61 if( document.layers ){\r
62         \r
63 } else {\r
64         \r
65 };\r
66 \r
67 /**\r
68  * イベントターゲットをラップする場合(widnow, document, Image, XHR 等)、通常は new 時に渡します。参照:コンストラクタ実体 {@link X.EventDispatcher.Constructor}\r
69  * アプリケーション独自のイベントをやり取りしたいだけ、という場合、イベントターゲットは不要です。\r
70  * @constructor\r
71  * @classdesc EventTarget オブジェクトをラップしたり、アプリケーションで独自に定義したイベントを発信するためのクラスです。\r
72  * listen, unlisten, dispatch という addEventListener, removeEventListener, dispatchEvent に対応する関数を持ちます。さらに listening という as3 の hasEventListener に相当する関数を持ちます。\r
73  * as3 の EventDispatcher に相当する機能に加え、イベントターゲットオブジェクト(widnow, document, HTMLElement, XHR 等)が設定されていた場合に、それらへ実際のイベント登録・解除も行います。\r
74  * このイベントの登録・解除はクロスブラウザ対策が施されていて、IE5~8の独自イベントの差異を吸収し、DOM0 に対しても複数のイベントリスナを登録します。\r
75  * さらに、コールバックに対して、this コンテキストや、追加の引数を指定できます。 this コンテキストを指定しなかった場合、EventDispatcher インスタンスがコールバック関数の this になります。 \r
76  * @param {object=} opt_argument \r
77  */\r
78 X.EventDispatcher =\r
79         X.Class.create(\r
80                 'EventDispatcher',\r
81                 {\r
82 \r
83             /**\r
84              * @namespace\r
85              * @memberof X.EventDispatcher\r
86              */\r
87 \r
88                 /**\r
89                  * イベントリスナをイベント名(string)や数値(1~,フレームワーク内で定義)をキーとするArrayで記憶します。\r
90                  * Arrayには、{k:種類,x:コンテキスト(thisObject),f:関数,s:サプリメントする引数の配列} というハッシュ、または関数が蓄えられています。\r
91                  * @private\r
92                  * @type {Object.<(number|string), Array.<(callbackDef|function)>>}\r
93                  */\r
94                         _listeners    : null,\r
95 \r
96                 /**\r
97                  * _rawObject には HTMLElement, window, document, XHR といったイベントターゲットオブジェクトを設定します。\r
98                  * _rawObject が設定されていると on(), off() 時に addEventListener(DOM Level2) や detachEvent(ie5~8), on~(DOM0) 等を操作します。\r
99                  * _rawObject は最初の on() 前に設定しておかないと addEventListener 等が意図したように行われません。\r
100                  * X.Dom.Node では非同期に HTMLElement を生成していて、要素生成以前に on, off を呼び出すことができます。これは適宜に migrateEvent, restoreEvent を呼んで解決しているためです。\r
101                  * @private\r
102                  * @type {Object}\r
103                  */\r
104                         _rawObject      : null,\r
105                         _handleEvent  : null,\r
106                         \r
107                         _dispatching  : 0,     // dispatch 中の unlisten で使用\r
108                         _unlistens    : null,  // dispatch 中の unlisten で使用\r
109                         _reserves     : null,  // dispatch中に unlisten されたイベントリスナ\r
110                         _killReserved : false,\r
111                         \r
112             /**\r
113              * X.EventDispatcher のコンストラクタの実体。\r
114              * @private\r
115              * @this {X.EventDispatcher}\r
116              */\r
117                         Constructor : function( rawObject ){\r
118                                 if( rawObject ){\r
119                                         this._rawObject = rawObject;\r
120                                 };\r
121                         },\r
122 \r
123             /**\r
124              * \r
125              * @this {X.EventDispatcher}\r
126              */\r
127                         on     : x_eventdispatcher_on,\r
128                         listen : x_eventdispatcher_on,\r
129                         \r
130                         listenOnce : function( type, arg1, arg2, arg3 ){\r
131                                 x_eventdispatcher_once = true;\r
132                                 this.listen( type, arg1, arg2, arg3 );\r
133                                 x_eventdispatcher_once = false;\r
134                                 return this;\r
135                         },\r
136                         \r
137                         off      : x_eventdispatcher_off,\r
138                         unlisten : x_eventdispatcher_off,\r
139                         \r
140                         listening : function( type, arg1, arg2, arg3 ){\r
141                                 var list = this._listeners, unlistens, i, f, hash;\r
142                                 if( type === undefined ) return !!list;\r
143                                 if( !list || !( list = list[ type ] ) ) return false;\r
144                                 if( arg1 === undefined ) return true;\r
145                                 \r
146                                 if( arg1.k ){\r
147                                         hash = arg1;\r
148                                 } else {\r
149                                         hash = X.Callback._classifyCallbackArgs( arg1, arg2, arg3, this );\r
150                                 };\r
151                                 \r
152                                 if( ( unlistens = this._unlistens ) && ( unlistens = unlistens[ type ] ) ){\r
153                                         for( i = unlistens.length; i; ){\r
154                                                 f = unlistens[ --i ];\r
155                                                 if( f === hash || ( f.x === hash.x && f.f === hash.f && f.s === hash.s ) ) return false;\r
156                                         };\r
157                                 };\r
158                                 for( i = list.length; i; ){\r
159                                         f = list[ --i ];\r
160                                         if( f === hash || ( f.x === hash.x && f.f === hash.f && f.s === hash.s ) ) return x_eventdispatcher_needsIndex ? i : true;\r
161                                 };\r
162                                 return false;\r
163                         },\r
164                         /*\r
165                          * dispatch 中に dispatch が呼ばれるケースがあるため、\r
166                          * _dispatching では その深さを保存する\r
167                          * _dispatching が 0 のときに unlistens を削除する\r
168                          *\r
169                          */\r
170                         dispatch : function( e ){\r
171                                 // dispatch 中の listen は?\r
172                                 var list  = this._listeners,\r
173                                         ret   = X.Callback.NONE,\r
174                                         type  = e.type,\r
175                                         unlistens, i, l, f, r, sysOnly;\r
176                                 \r
177                                 if( !list ) return ret;\r
178                                 \r
179                                 // 数値, 文字が渡された場合\r
180                                 if( !type ){\r
181                                         type = e;\r
182                                         e = { type : type };\r
183                                 };\r
184                                 e.target = e.target || this;\r
185                                 \r
186                                 if( !( list = list[ type ] ) ) return ret;\r
187                                 \r
188                                 ++this._dispatching;\r
189                                 \r
190                                 // todo:\r
191                                 // type も保存\r
192                                 this._unlistens = this._unlistens || {};\r
193                                 unlistens = this._unlistens[ type ];\r
194                                 \r
195                                 for( i = 0; i < list.length; ++i ){\r
196                                         f = list[ i ];\r
197                                         if( !unlistens ){\r
198                                                 unlistens = this._unlistens[ type ];\r
199                                         };\r
200                                         if( unlistens && unlistens.indexOf( f ) !== -1 ) continue;\r
201                                         \r
202                                         r = X.Callback.NONE;\r
203                                         if( f.k ){\r
204                                                 f.a = [ e ];\r
205                                                 r = X.Callback._proxyCallback( f );\r
206                                         } else {\r
207                                                 r = f.call( this, e );\r
208                                         };\r
209                                         \r
210                                         if( f.once || r & X.Callback.UN_LISTEN ){\r
211                                                 // dispatch 中に unlisten が作られることがある\r
212                                                 if( !unlistens ){\r
213                                                         unlistens = this._unlistens || ( this._unlistens = {} );\r
214                                                         unlistens = unlistens[ type ] || ( unlistens[ type ] = [] );\r
215                                                 };\r
216                                                 unlistens.indexOf( f ) === -1 && ( unlistens[ unlistens.length ] = f );\r
217                                         };\r
218 \r
219                                         if( r & X.Callback.STOP_NOW ){\r
220                                                 sysOnly = true;\r
221                                         };\r
222                                         ret |= r;\r
223                                 };\r
224                                 \r
225                                 if( ( --this._dispatching ) === 0 ){\r
226                                         // dispatch 中に unlisten された要素の削除\r
227                                         unlistens = this._unlistens;\r
228                                         delete this._dispatching;\r
229                                         delete this._unlistens;                                 \r
230                                         \r
231                                         for( type in unlistens ){\r
232                                                 list = unlistens[ type ];\r
233                                                 for( i = list.length; i; ){\r
234                                                         this.unlisten( type, list[ --i ] );\r
235                                                 };\r
236                                                 list.length = 0;\r
237                                                 delete unlistens[ type ];\r
238                                         };\r
239                                         \r
240                                         if( this._killReserved ){\r
241                                                 this.kill();\r
242                                         } else\r
243                                         if( list = this._reserves ){\r
244                                                 for( i = 0, l = list.length; i < l; ++i ){\r
245                                                         f = list[ i ];\r
246                                                         x_eventdispatcher_once = f[ 4 ];\r
247                                                         this.listen( f[ 0 ], f[ 1 ], f[ 2 ], f[ 3 ] );\r
248                                                         x_eventdispatcher_once = false;\r
249                                                         f.length = 0;\r
250                                                 };\r
251                                                 list.length = 0;\r
252                                                 delete this._reserves;\r
253                                         };\r
254                                 };\r
255                                 \r
256                                 return ret;\r
257                         },\r
258                         \r
259                         onKill : function(){\r
260                                 if( this._dispatching ){\r
261                                         this._killReserved = true;\r
262                                         return false;\r
263                                 };\r
264                                 this._listeners && this.unlisten();\r
265                         },\r
266                         \r
267                         asyncDispatch : function( delay, e ){\r
268                                 return X.Timer.add( delay, 1, this, this.dispatch, [ e ] );\r
269                         }\r
270                 }\r
271         );\r
272 \r
273 \r
274 // --- implements ------------------------------------------\r
275 function x_eventdispatcher_on( type, arg1, arg2, arg3 ){\r
276         var list = this._listeners,\r
277                 i, r, f;\r
278         \r
279         if( this._dispatching ){\r
280                 if( !this._reserves ) this._reserves = [];\r
281                 this._reserves[ this._reserves.length ] = [ type, arg1, arg2, arg3, x_eventdispatcher_once ];\r
282                 return this;\r
283         };\r
284         \r
285         if( X.Type.isArray( type ) ){\r
286                 for( i = type.length; i; ){\r
287                         this.listen( type[ --i ], arg1, arg2, arg3 );\r
288                 };\r
289                 return this;\r
290         };\r
291         \r
292         ( !list || !list[ type ] ) && X.Type.isString( type ) && x_eventdispatcher_actualAddEvent( this, type );\r
293         \r
294         if( this.listening( type, arg1, arg2, arg3 ) ) return this;\r
295 \r
296         if( !list ) list = this._listeners = {};\r
297         if( !( list = list[ type ] ) ) list = this._listeners[ type ] = [];\r
298         \r
299         f = X.Callback._classifyCallbackArgs( arg1, arg2, arg3, this );\r
300         list[ list.length ] = f;\r
301         f.once = x_eventdispatcher_once;\r
302         \r
303         return this;\r
304 };\r
305 \r
306 function x_eventdispatcher_off( type, arg1, arg2, arg3 ){\r
307         var list = this._listeners,\r
308                 _list, reserves, unlistens, i, f;\r
309         if( !list ) return this;\r
310         \r
311         if( X.Type.isArray( type ) ){\r
312                 for( i = type.length; i; ){\r
313                         this.unlisten( type[ --i ], arg1, arg2, arg3 );\r
314                 };\r
315                 return this;\r
316         };\r
317         \r
318         if( type === undefined ){\r
319                 // 全て削除\r
320                 for( type in list ){\r
321                         _list = list[ type ];\r
322                         for( i = _list.length; i; ){\r
323                                 this.unlisten( type, _list[ --i ] ); // override されていることがあるので、必ず unlisten を使用\r
324                         };\r
325                         // this.unlisten( type ); これは無茶!\r
326                 };\r
327                 return this;\r
328         } else\r
329         if( arg1 === undefined ){\r
330                 // 同一タイプを全て削除\r
331                 if( _list = list[ type ] ){\r
332                         for( i = _list.length; i; ){\r
333                                 this.unlisten( type, _list[ --i ] ); // override されていることがあるので、必ず unlisten を使用\r
334                         };\r
335                 };\r
336                 return this;\r
337         } else\r
338         if( reserves = this._reserves ){\r
339                 for( i = reserves.length; i; ){\r
340                         f = reserves[ --i ];\r
341                         if( f[ 0 ] === type && f[ 1 ] === arg1 && f[ 2 ] === arg2 && f[ 3 ] === arg3 ){\r
342                                 reserves.splice( i, 1 );\r
343                                 if( !reserves.legth ) delete this._reserves;\r
344                                 return this;\r
345                         };\r
346                 };\r
347         };\r
348         \r
349         x_eventdispatcher_needsIndex = true;\r
350         i = this.listening( type, arg1, arg2, arg3 );\r
351         x_eventdispatcher_needsIndex = false;\r
352         if( i === false ) return this;\r
353 \r
354         f = ( _list = list[ type ] )[ i ];\r
355         if( unlistens = this._unlistens ){\r
356                 ( unlistens = unlistens[ type ] ) ?\r
357                         ( unlistens[ unlistens.length ] = f ) :\r
358                         ( this._unlistens[ type ] = [ f ] );\r
359         } else {\r
360                 delete f.once;\r
361                 // f.kill === X.Callback._kill && f.kill();\r
362                 _list.splice( i, 1 );\r
363                 if( !_list.length ){\r
364                         delete this._listeners[ type ];\r
365                         X.Type.isString( type ) && x_eventdispatcher_actualRemoveEvent( this, type );\r
366                         if( X.isEmptyObject( this._listeners ) ) delete this._listeners;\r
367                 };\r
368         };\r
369         return this;\r
370 };\r
371 \r
372 \r
373 var x_eventdispatcher_actualAddEvent =\r
374         // Days on the Moon DOM Events とブラウザの実装 \r
375         // http://nanto.asablo.jp/blog/2007/03/23/1339502\r
376         // Safari 2 では関数オブジェクトしか EventListener として使えませんが、Safari のナイトリービルドでは handleEvent メソッドを持つオブジェクトも EventListener として使えるようです。\r
377         x_eventdispatcher_temp.EVENT_W3C && ( X.UA.WebKit < 525.13 || X.UA.Opera7 || X.UA.NetFront < 4 ) ? // Safari3-\r
378                 (function( that, type ){\r
379                         var raw = that._rawObject;\r
380                         if( !raw ) return; \r
381                         that._handleEvent = that._handleEvent || X.Callback.create( that, x_eventdispatcher_actualHandleEvent );\r
382                         type = X.Dom.Event.Rename[ type] || type;\r
383                         if( raw.addEventListener ){\r
384                                 raw.addEventListener( type, that._handleEvent, false );\r
385                         } else {\r
386                                 // Safari は Image, Opera7 は window\r
387                                 raw[ 'on' + type ] = that._handleEvent;\r
388                         };\r
389                 }) :\r
390         x_eventdispatcher_temp.EVENT_W3C ?\r
391                 (function( that, type ){\r
392                         if( that._rawObject ){\r
393                                 that._handleEvent = that._handleEvent || X.Callback.create( that, x_eventdispatcher_actualHandleEvent );\r
394                                 that._rawObject.addEventListener( X.Dom.Event.Rename[ type ] || type, that._handleEvent, false );\r
395                         };\r
396                 }) :\r
397         x_eventdispatcher_temp.EVENT_IE ?\r
398                 (function( that, type ){\r
399                         var raw = that._rawObject;\r
400                         if( !raw ) return;\r
401                         type = X.Dom.Event.Rename[ type ] || type;\r
402                         //if( type === 'load' && that._tag && X.Dom.Event._LOAD_FIX_TAGS[ that._tag ] ){\r
403                         //      type = 'readystatechange';\r
404                         //};\r
405                         if( that._isXHR ){\r
406                                 // ie8- の XHR は window.event が更新されないため, eventType 毎に callback を指定する\r
407                                 raw[ 'on' + type ] = X.Callback.create( that, X.EventDispatcher.prototype.dispatch, [ type ] );\r
408                         } else {\r
409                                 that._handleEvent = that._handleEvent || X.Callback.create( that, x_eventdispatcher_actualHandleEvent );\r
410                                 \r
411                                 if( raw.attachEvent ){\r
412                                         raw.attachEvent( 'on' + type, that._handleEvent );\r
413                                 } else {\r
414                                         raw[ 'on' + type ] = that._handleEvent;\r
415                                 };                              \r
416                         };\r
417 \r
418                 }) :\r
419                 (function( that, type ){\r
420                         var raw = that._rawObject || ( that._ie4getRawNode && that._ie4getRawNode() );\r
421                         if( !raw ) return;\r
422                         raw[ 'on' + ( X.Dom.Event.Rename[ type ] || type ) ] = that._handleEvent = that._handleEvent || X.Callback.create( that, x_eventdispatcher_actualHandleEvent );\r
423                 });\r
424 \r
425 \r
426 var x_eventdispatcher_actualRemoveEvent =\r
427         x_eventdispatcher_temp.EVENT_W3C && ( X.UA.WebKit < 525.13 || X.UA.Opera7 || X.UA.NetFront < 4 ) ? // Safari3-\r
428                 (function( that, type ){\r
429                         var raw = that._rawObject;\r
430                         if( !raw ) return;\r
431                         type = X.Dom.Event.Rename[ type ] || type;\r
432                         \r
433                         if( raw.addEventListener ){ // Image\r
434                                 raw.removeEventListener( type, that._handleEvent, false );\r
435                         } else {\r
436                                 raw[ 'on' + type ] = null;\r
437                         };\r
438                         if( !that._listeners ){\r
439                                 X.Callback._correct( that._handleEvent );\r
440                                 delete that._handleEvent;\r
441                         };\r
442                 }) :\r
443         x_eventdispatcher_temp.EVENT_W3C ?\r
444                 (function( that, type ){\r
445                         var raw = that._rawObject;\r
446                         if( !raw ) return;\r
447                         raw.removeEventListener( X.Dom.Event.Rename[ type ] || type, that._handleEvent, false );\r
448                         if( !that._listeners ){\r
449                                 X.Callback._correct( that._handleEvent );\r
450                                 delete that._handleEvent;\r
451                         };\r
452                 }) :\r
453         x_eventdispatcher_temp.EVENT_IE ?\r
454                 (function( that, type ){\r
455                         var raw = that._rawObject;\r
456                         if( !raw ) return;\r
457                         type = X.Dom.Event.Rename[ type ] || type;\r
458                         //if( type === 'load' && that._tag && X.Dom.Event._LOAD_FIX_TAGS[ that._tag ] ){\r
459                         //      type = 'readystatechange';\r
460                         //};\r
461                         if( that._isXHR ){\r
462                                 X.Callback._correct( raw[ 'on' + type ] );\r
463                                 raw[ 'on' + type ] = X.emptyFunction;\r
464                                 raw[ 'on' + type ] = '';\r
465                         } else {\r
466                                 if( raw.attachEvent ){\r
467                                         raw.detachEvent( 'on' + type, that._handleEvent );\r
468                                 } else {\r
469                                         raw[ 'on' + type ] = X.emptyFunction;\r
470                                         raw[ 'on' + type ] = '';\r
471                                 };\r
472                                 \r
473                                 if( !that._listeners ){\r
474                                         X.Callback._correct( that._handleEvent );\r
475                                         delete that._handleEvent;\r
476                                 };                              \r
477                         };\r
478                 }) :\r
479                 (function( that, type ){\r
480                         var raw = that._rawObject || ( that._ie4getRawNode && that._ie4getRawNode() );\r
481                         if( !raw ) return;\r
482                         type = X.Dom.Event.Rename[ type ] || type;\r
483                         raw[ 'on' + type ] = X.emptyFunction;\r
484                         raw[ 'on' + type ] = '';\r
485                         if( !that._listeners ){\r
486                                 X.Callback._correct( that._handleEvent );\r
487                                 delete that._handleEvent;\r
488                         };\r
489                 });\r
490 \r
491 \r
492 // handleEvent を拡張可能にするために、クロージャに移動した\r
493 // Is this in regard to the Safari 1.x preventDefault bug on click/dblclick?\r
494 // https://groups.google.com/forum/#!msg/comp.lang.javascript/uYEuCHjHxnw/yKoHtZJPa1QJ\r
495 var x_eventdispatcher_actualHandleEvent =\r
496         X.UA.IE4 || X.UA.IE5678 ? // ie45678 EVENT_IE & EVENT_DOM0 for ie4\r
497                 (function(){\r
498                         var ret;\r
499                         \r
500                         if( event.type === 'readystatechange' && this._tag && X.Dom.Event._LOAD_FIX_TAGS[ this._tag ] ){\r
501                                 //type = 'readystatechange';\r
502                         };\r
503                         \r
504                         ret = X.EventDispatcher.prototype.dispatch.call( this, new X.Dom.Event( event, this, this._rawObject ) );\r
505 \r
506                         if( ret & X.Callback.STOP_PROPAGATION ){\r
507                                 event.cancelBubble = true;\r
508                         };\r
509                         if( ret & X.Callback.PREVENT_DEFAULT ){\r
510                                 this._tag === 'A' && this._rawObject.blur();\r
511                                 return event.returnValue = false;\r
512                         };\r
513                 }) :\r
514         //X.Dom.EVENT_W3C & EVENT_DOM0\r
515                 (function( e ){\r
516                         var ret = X.EventDispatcher.prototype.dispatch.call( this, new X.Dom.Event( e, this ) );\r
517                         \r
518                         if( ret & X.Callback.STOP_PROPAGATION ){\r
519                                 e.stopPropagation();\r
520                         };\r
521                         if( ret & X.Callback.PREVENT_DEFAULT ){\r
522                                 this._tag === 'A' && this._rawObject.blur();\r
523                                 e.preventDefault();\r
524                                 if( X.UA.WebKit < 525.13 ){ // Safari3-\r
525                                         if( e.type === 'click' || e.type === 'dbclick' ){\r
526                                                 X.Dom._safariPreventDefault = true;\r
527                                         };\r
528                                 };\r
529                                 return false;\r
530                         };\r
531                 });\r
532 \r
533 \r
534 // イベントの退避、dom が画面から抜かれる場合に実施しておく\r
535 X.EventDispatcher.prototype._migrateEvent = function(){\r
536         var hash = this._listeners,\r
537                 type;\r
538         if( !hash ) return;\r
539         for( type in hash ){\r
540                 // 数字イベントの除外\r
541                 '' + parseFloat( type ) !== type && x_eventdispatcher_actualRemoveEvent( this, type );\r
542         };\r
543 };\r
544 \r
545 // 退避したイベントの復帰\r
546 X.EventDispatcher.prototype._restoreEvent = function(){\r
547         var hash = this._listeners,\r
548                 type;\r
549         if( !hash ) return;\r
550         for( type in hash ){\r
551                 // 数字イベントの除外\r
552                 '' + parseFloat( type ) !== type && x_eventdispatcher_actualAddEvent( this, type );\r
553         };\r
554 };\r
555 \r
556 \r
557 console.log( 'X.Core.EventDispatcher' );\r