CKEDITOR.event.implementOn = function (targetObject) {
var eventProto = CKEDITOR.event.prototype;
for (var prop in eventProto) {
if (targetObject[prop] == null)
targetObject[prop] = eventProto[prop];
}
};
CKEDITOR.event.prototype = (function () {
var eventEntry = function (eventName) {
this.name = eventName;
this.listeners = [];
};
eventEntry.prototype = {
// Get the listener index for a specified function.
// Returns -1 if not found.
getListenerIndex: function (listenerFunction) {
for (var i = 0, listeners = this.listeners; i < listeners.length; i++) {
if (listeners[i].fn == listenerFunction)
return i;
}
return -1;
}
};
function getEntry( name ) {
// Get the event entry (create it if needed).
var events = getPrivate( this );
return events[ name ] || ( events[ name ] = new eventEntry( name ) );
}
return {
define: function (name, meta) {...},
on: function (eventName, listenerFunction, scopeObj, listenerData, priority) {...},
once: function (eventName, listenerFunction, scopeObj, listenerData, priority) {...},
capture: function (eventName, listenerFunction, scopeObj, listenerData, priority) {...},
fire: function (eventName, data, editor) {...},
fireOnce: function (eventName, data, editor) {...},
removeListener: function (eventName, listenerFunction) {...},
removeAllListeners: function () {...},
hasListeners: function (eventName) {...},
}
}())
implementOn函数的功能是把CKEDITOR.event.prototype的属性和方法挂载到指定对象上:
CKEDITOR.event.implementOn( CKEDITOR );
CKEDITOR.event.implementOn( CKEDITOR.editor.prototype );
CKEDITOR.event.prototype定义了事件的基本功能:
- define: 定义事件
- on: 添加事件监听
- once: 添加一次性事件监听
- capture: 添加捕获阶段的事件监听
- fire: 触发事件
- fireOnce: 触发一次性事件
- removeListener: 移除事件监听
- removeAllListeners: 移除所有事件监听
- hasListeners: 判断某个事件是否有监听
通过 new eventEntry生成事件实例,通过getEntry方法挂载到指定对象上上,例如在ckeditor的实例中事件是注册在ckeditor._.events上。
fire的具体实现:
fire: ( function() {
// Create the function that marks the event as stopped.
var stopped = 0;
var stopEvent = function() {
stopped = 1;
};
// Create the function that marks the event as canceled.
var canceled = 0;
var cancelEvent = function() {
canceled = 1;
};
return function( eventName, data, editor ) {
// Get the event entry.
var event = getPrivate( this )[ eventName ];
// Save the previous stopped and cancelled states. We may
// be nesting fire() calls.
var previousStopped = stopped,
previousCancelled = canceled;
// Reset the stopped and canceled flags.
stopped = canceled = 0;
if ( event ) {
var listeners = event.listeners;
if ( listeners.length ) {
// As some listeners may remove themselves from the
// event, the original array length is dinamic. So,
// let's make a copy of all listeners, so we are
// sure we'll call all of them.
listeners = listeners.slice( 0 );
var retData;
// Loop through all listeners.
for ( var i = 0; i < listeners.length; i++ ) {
// Call the listener, passing the event data.
if ( event.errorProof ) {
try {
retData = listeners[ i ].call( this, editor, data, stopEvent, cancelEvent );
} catch ( er ) {}
} else {
retData = listeners[ i ].call( this, editor, data, stopEvent, cancelEvent );
}
if ( retData === EVENT_CANCELED )
canceled = 1;
else if ( typeof retData != 'undefined' )
data = retData;
// No further calls is stopped or canceled.
if ( stopped || canceled )
break;
}
}
}
var ret = canceled ? false : ( typeof data == 'undefined' ? true : data );
// Restore the previous stopped and canceled states.
stopped = previousStopped;
canceled = previousCancelled;
return ret;
};
} )
相比eventEmitter的emit,fire多了stopEvent和cancelEvent, 用来手动停止事件监听函数的执行。 fire函数通过闭包存储了stopped和canceled状态,在遍历执行监听函数的时候,把stopEvent和cancelEvent抛给事件监听函数,在监听函数中如果调用了stopEvent或cancelEvent,就会停止该事件后续监听事件的执行。
具体使用:
function first() {
alert("first", Array.from(arguments))
}
function second() {
console.log("second", Array.from(arguments))
}
const myEvent = new CKEDITOR.event();
// 注册事件
myEvent.on("custom", first, null, { extra: "data-first" }, 1);
myEvent.on("custom", second, null, { extra: "data-second" }, 2);
// 触发事件
myEvent.fire("custom", null, { data: "test-data" });
// 移除事件监听
myEvent.removeAllListeners();