jQuery event.js 1回
event.js 1回目のメモを公開しますー遅れてすんません。 毎度おなじみ@ryuoneさんの記事はこちら →jQuery event.js 読書会 1回目に参加しました。
では1行目から バージョンは1.6.1です。
(function( jQuery ) {
// hasOwnPropertyへのエイリアス
var hasOwn = Object.prototype.hasOwnProperty,
rnamespaces = /\.(.*)$/,
// \.でドット
// ()でキャプチャグループ
// .は任意の文字
// *は0回以上の繰り返し
// $は(.*)で最後の意味
rformElems = /^(?:textarea|input|select)$/i,
// ^(ハット)は最初の意味
// (?:)は非キャプチャグループ textarea もしくは input もしくは select
// 上記で終わる
// iフラグは大文字と小文字を区別しない
rperiod = /\./g,
// \.でドット
// g 繰り返しマッチ (メソッドによって異なる)
rspaces = / /g,
// 空白
rescape = /[^\w\s.|`]/g,
// \w 英数字
// \s空白文字
// .は任意の一文字
// `は単なる文字
// [^]は~以外という意味 \w\s.|`以外という意味
// マッチしたものの先頭に\をつける
fcleanup = function( nm ) {
return nm.replace(rescape, "\\$&");
};
// String.replace()は第2引数に関数を渡したりもできる!
//===================
// $について
//===================
// $1 = 第1キャプチャグループ
// $2 = 第2キャプチャグループ
// $3,$4 ...
// $0 検索対象すべて
// $& マッチしたすべて
/*
* A number of helper functions used for managing events.
* Many of the ideas behind this code originated from
* Dean Edwards' addEvent library.
*/
jQuery.event = {
// Bind an event to an element
// Original by Dean Edwards
// "jQuery.fn.bind()やjQuery.fn.one()"などから呼ばれる。
// イベントの登録
add: function( elem, types, handler, data ) {
// 第2引数のtypesはイベントのタイプ ( click,mouseover など )
// 第3引数のhandlerはコールバック関数
// テキストもしくはコメントであれば何もしない
if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
return;
}
// 第3引数handlerがfalseの場合
if ( handler === false ) {
// returnFalseは601行目で定義
// handler()とするとfalseを返す
handler = returnFalse;
// handlerがない場合 ここから
} else if ( !handler ) {
// Fixes bug #7229. Fix recommended by jdalton
return;
}
// handlerがない場合 ここまで
var handleObjIn, handleObj;
// handlerがhandlerプロパティを持っていれば
// (handlerがhandlerプロパティを持つときってどんなときやろ)
if ( handler.handler ) {
handleObjIn = handler;
// handler.handlerをhandlerにする
handler = handleObjIn.handler;
}
// Make sure that the function being executed has a unique ID
// guidを持っていなければユニークキーを追加する
if ( !handler.guid ) {
handler.guid = jQuery.guid++;
}
// Init the element's event structure
// jQuery._dataはdata.jsで定義
// jQuery.data()の内部利用版
// 引数が1つの場合はelemのdataを取ってくる
var elemData = jQuery._data( elem );
// If no elemData is found then we must be trying to bind to one of the
// banned noData elements
//dataが利用出来なかった場合
if ( !elemData ) {
return;
}
var events = elemData.events,
eventHandle = elemData.handle;
if ( !events ) {
elemData.events = events = {};
}
// elemDataそのものがない
// handleがないなどの場合定義
if ( !eventHandle ) {
elemData.handle = eventHandle = function( e ) {
// Discard the second event of a jQuery.event.trigger() and
// when an event is called after a page has unloaded
return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ?
jQuery.event.handle.apply( eventHandle.elem, arguments ) :
undefined;
};
}
// Add elem as a property of the handle function
// This is to prevent a memory leak with non-native events in IE.
eventHandle.elem = elem;
// Handle multiple events separated by a space
// jQuery(...).bind("mouseover mouseout", fn);
// イベントの種類
types = types.split(" ");
var type, i = 0, namespaces;
// イベントの数だけまわす
// $().bind("myEvent myEvent2",function(){});
// とかすると2回
while ( (type = types[ i++ ]) ) {
handleObj = handleObjIn ?
jQuery.extend({}, handleObjIn) :
{ handler: handler, data: data };
// 1回目は絶対後方
// handleObj = { handler: handler, data: data };
// Namespaced event handlers
// 名前空間の処理
if ( type.indexOf(".") > -1 ) {
// shift.click
namespaces = type.split(".");
type = namespaces.shift();
// shiftは先頭の値を得る。
// sliceで新しく配列を作ってソートして"."でつなぐ
handleObj.namespace = namespaces.slice(0).sort().join(".");
} else {
// typeに名前空間がなければ
namespaces = [];
handleObj.namespace = "";
}
handleObj.type = type;
// 初めて定義された場合とか
if ( !handleObj.guid ) {
handleObj.guid = handler.guid;
}
// Get the current list of functions bound to this event
var handlers = events[ type ],
// special はここで宣言。
// jQuery.event.special 519行目
// specialのプロパティのイベントであれば値を入れる。なければからのobj
// プロパティは
// beforeunload, focusin, focusout, live, mouseenter
// mouseleave, ready
special = jQuery.event.special[ type ] || {};
// Init the event handler queue
// 初めてイベントを登録する場合
if ( !handlers ) {
handlers = events[ type ] = [];
// Check for a special event handler
// Only use addEventListener/attachEvent if the special
// events handler returns false
// special.setupは
// special.add.setupとかbeforeunload.setupとか
// setupが出来ない状態
// 詳しくは519行目 specialオブジェクトを参照
if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
// Bind the global event handler to the element
if ( elem.addEventListener ) {
elem.addEventListener( type, eventHandle, false );
} else if ( elem.attachEvent ) {
elem.attachEvent( "on" + type, eventHandle );
}
}
}
// addがあるspecialのプロパティ
if ( special.add ) {
special.add.call( elem, handleObj );
if ( !handleObj.handler.guid ) {
handleObj.handler.guid = handler.guid;
}
}
// Add the function to the element's handler list
handlers.push( handleObj );
// Keep track of which events have been used, for event optimization
// 144行目 からのオブジェクト
jQuery.event.global[ type ] = true;
}
// Nullify elem to prevent memory leaks in IE
elem = null;
},
// ↑↑addメソッドここまで↑↑
global: {},
// Detach an event or set of events from an element
// 消してるだけ
remove: function( elem, types, handler, pos ) {
// don't do events on text and comment nodes
// テキストかコメントであればなにもしない
if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
return;
}
if ( handler === false ) {
handler = returnFalse;
}
// 見やすいように改行にします。
var ret,
type,
fn,
j,
i = 0,
all,
namespaces,
namespace,
special,
eventType,
handleObj,
origType,
// あとで確認
elemData = jQuery.hasData( elem ) && jQuery._data( elem ),
events = elemData && elemData.events;
if ( !elemData || !events ) {
return;
}
// types is actually an event object here
// undefinedのプロパティを評価しようとしたら例外が発生するため
if ( types && types.type ) {
handler = types.handler;
types = types.type;
}
// Unbind all events for the element
//typesがない場合、ドットから始まる場合はもう一度呼びなおす
if ( !types || typeof types === "string" && types.charAt(0) === "." ) {
types = types || "";
for ( type in events ) {
jQuery.event.remove( elem, type + types );
}
return;
}
// Handle multiple events separated by a space
// jQuery(...).unbind("mouseover mouseout", fn);
types = types.split(" ");
while ( (type = types[ i++ ]) ) {
origType = type;
handleObj = null;
all = type.indexOf(".") < 0;
namespaces = [];
// typeにドットが含まれていれば
if ( !all ) {
// Namespaced event handlers
namespaces = type.split(".");
type = namespaces.shift();
// namespaceの正規表現を作ってる
// こんんあやりかたあるんですねぇ
namespace = new RegExp("(^|\\.)" +
jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)");
}
eventType = events[ type ];
if ( !eventType ) {
// 次の処理へ
continue;
}
if ( !handler ) {
for ( j = 0; j < eventType.length; j++ ) {
handleObj = eventType[ j ];
if ( all || namespace.test( handleObj.namespace ) ) {
jQuery.event.remove( elem, origType, handleObj.handler, j );
eventType.splice( j--, 1 );
}
}
continue;
}
// 消すための条件を一致させていくための処理
special = jQuery.event.special[ type ] || {};
// pos 数字
// eventType.lengthは毎回評価
for ( j = pos || 0; j < eventType.length; j++ ) {
handleObj = eventType[ j ];
if ( handler.guid === handleObj.guid ) {
// remove the given handler for the given type
if ( all || namespace.test( handleObj.namespace ) ) {
if ( pos == null ) {
// 後置なので0-1
// 鉛筆削り
eventType.splice( j--, 1 );
}
if ( special.remove ) {
special.remove.call( elem, handleObj );
}
}
// position指定したらもういいので1回だけで終了
if ( pos != null ) {
break;
}
}
}
// remove generic event handler if no more handlers exist
if ( eventType.length === 0 || pos != null && eventType.length === 1 ) {
// teardown は
// ここで消す
if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
jQuery.removeEvent( elem, type, elemData.handle );
}
ret = null;
delete events[ type ];
}
}
// typeを全部見ていって消していく
// Remove the expando if it's no longer used
if ( jQuery.isEmptyObject( events ) ) {
var handle = elemData.handle;
if ( handle ) {
handle.elem = null;
}
delete elemData.events;
delete elemData.handle;
if ( jQuery.isEmptyObject( elemData ) ) {
jQuery.removeData( elem, undefined, true );
}
}
},