执行 cordova.js 的入口就以下2行代码:
Js 代码
// 导入cordova |
window.cordova = require('cordova'); |
// 启动处理 |
require('cordova/init'); |
src/cordova.js 事件的处理和回调,外部访问 cordova.js 的入口
其中第一步是加载整个模块系统和外部访问 cordova.js 的入口,基于事件通道提供了整体的事件拦截控制及回调。代码不是很复杂。
源码:
Js 代码
// file: src/cordova.js |
define("cordova", function(require, exports, module) { |
// 调用通道和平台模块 |
var channel = require('cordova/channel'); |
var platform = require('cordova/platform'); |
// 备份document和window的事件监听器 |
var m_document_addEventListener = document.addEventListener; |
var m_document_removeEventListener = document.removeEventListener; |
var m_window_addEventListener = window.addEventListener; |
var m_window_removeEventListener = window.removeEventListener; |
// 保存自定义的document和window的事件监听器 |
var documentEventHandlers = {}, |
windowEventHandlers = {}; |
// 拦截document和window的事件监听器(addEventListener/removeEventListener) |
// 存在自定义的事件监听器的话,使用自定义的;不存在的话调用备份document和window的事件监听器 |
document.addEventListener = function(evt, handler, capture) { |
var e = evt.toLowerCase(); |
if (typeof documentEventHandlers[e] != 'undefined') { |
documentEventHandlers[e].subscribe(handler); |
} else { |
m_document_addEventListener.call(document, evt, handler, capture); |
} |
}; |
window.addEventListener = function(evt, handler, capture) { |
var e = evt.toLowerCase(); |
if (typeof windowEventHandlers[e] != 'undefined') { |
windowEventHandlers[e].subscribe(handler); |
} else { |
m_window_addEventListener.call(window, evt, handler, capture); |
} |
}; |
document.removeEventListener = function(evt, handler, capture) { |
var e = evt.toLowerCase(); |
if (typeof documentEventHandlers[e] != "undefined") { |
documentEventHandlers[e].unsubscribe(handler); |
} else { |
m_document_removeEventListener.call(document, evt, handler, capture); |
} |
}; |
window.removeEventListener = function(evt, handler, capture) { |
var e = evt.toLowerCase(); |
if (typeof windowEventHandlers[e] != "undefined") { |
windowEventHandlers[e].unsubscribe(handler); |
} else { |
m_window_removeEventListener.call(window, evt, handler, capture); |
} |
}; |
// 创建一个指定type的事件。 |
// 参考:https://developer.mozilla.org/en-US/docs/Web/API/document.createEvent#Notes |
function createEvent(type, data) { |
var event = document.createEvent('Events'); |
// 指定事件名、不可冒泡、不可取消 |
event.initEvent(type, false, false); |
// 自定义数据 |
if (data) { |
for (var i in data) { |
if (data.hasOwnProperty(i)) { |
event[i] = data[i]; |
} |
} |
} |
return event; |
} |
// 外部访问cordova.js的入口 |
var cordova = { |
// 模块系统 |
define:define, |
require:require, |
// 版本号和平台名 |
version:CORDOVA_JS_BUILD_LABEL, |
platformId:platform.id, |
// 为了拦截document和window的事件监听器,添加或删除自定义的事件监听器 |
addWindowEventHandler:function(event) { |
return (windowEventHandlers[event] = channel.create(event)); |
}, |
// sticky 是指一旦被调用那么它以后都保持被调用的状态,所定义的监听器会被立即执行。 |
// 比如: deviceready事件只触发一次,以后的所有监听都是立即执行的。 |
addStickyDocumentEventHandler:function(event) { |
return (documentEventHandlers[event] = channel.createSticky(event)); |
}, |
addDocumentEventHandler:function(event) { |
return (documentEventHandlers[event] = channel.create(event)); |
}, |
removeWindowEventHandler:function(event) { |
delete windowEventHandlers[event]; |
}, |
removeDocumentEventHandler:function(event) { |
delete documentEventHandlers[event]; |
}, |
// 获取拦截前的document和window的事件监听器 |
getOriginalHandlers: function() { |
return {'document': {'addEventListener': m_document_addEventListener, 'removeEventListener': m_document_removeEventListener}, |
'window': {'addEventListener': m_window_addEventListener, 'removeEventListener': m_window_removeEventListener}}; |
}, |
// 调用document的事件 |
fireDocumentEvent: function(type, data, bNoDetach) { |
var evt = createEvent(type, data); |
if (typeof documentEventHandlers[type] != 'undefined') { |
// 判断是否需要抛出事件异常 |
if( bNoDetach ) { |
// 通过Channel的fire方法来调用事件(apply) |
documentEventHandlers[type].fire(evt); |
} |
else { |
// setTimeout(callback, 0) 的意思是DOM构成完毕、事件监听器执行完后立即执行 |
setTimeout(function() { |
// 调用加载cordova.js之前定义的那些deviceready事件 |
if (type == 'deviceready') { |
document.dispatchEvent(evt); |
} |
// 通过Channel的fire方法来调用事件(apply) |
documentEventHandlers[type].fire(evt); |
}, 0); |
} |
} else { |
// 直接调用事件 |
document.dispatchEvent(evt); |
} |
}, |
// 调用window的事件 |
fireWindowEvent: function(type, data) { |
var evt = createEvent(type,data); |
if (typeof windowEventHandlers[type] != 'undefined') { |
setTimeout(function() { |
windowEventHandlers[type].fire(evt); |
}, 0); |
} else { |
window.dispatchEvent(evt); |
} |
}, |
// 插件回调相关------------------------------------- |
// 回调ID中间的一个随机数(真正的ID:插件名+随机数) |
callbackId: Math.floor(Math.random() * 2000000000), |
// 回调函数对象,比如success,fail |
callbacks: {}, |
// 回调状态 |
callbackStatus: { |
NO_RESULT: 0, |
OK: 1, |
CLASS_NOT_FOUND_EXCEPTION: 2, |
ILLEGAL_ACCESS_EXCEPTION: 3, |
INSTANTIATION_EXCEPTION: 4, |
MALFORMED_URL_EXCEPTION: 5, |
IO_EXCEPTION: 6, |
INVALID_ACTION: 7, |
JSON_EXCEPTION: 8, |
ERROR: 9 |
}, |
// 以后使用callbackFromNative代替callbackSuccess和callbackError |
callbackSuccess: function(callbackId, args) { |
try { |
cordova.callbackFromNative(callbackId, true, args.status, [args.message], args.keepCallback); |
} catch (e) { |
console.log("Error in error callback: " + callbackId + " = "+e); |
} |
}, |
callbackError: function(callbackId, args) { |
try { |
cordova.callbackFromNative(callbackId, false, args.status, [args.message], args.keepCallback); |
} catch (e) { |
console.log("Error in error callback: " + callbackId + " = "+e); |
} |
}, |
// 调用回调函数 |
callbackFromNative: function(callbackId, success, status, args, keepCallback) { |
var callback = cordova.callbacks[callbackId]; |
// 判断是否定义了回调函数 |
if (callback) { |
if (success && status == cordova.callbackStatus.OK) { |
// 调用success函数 |
callback.success && callback.success.apply(null, args); |
} else if (!success) { |
// 调用fail函数 |
callback.fail && callback.fail.apply(null, args); |
} |
// 如果设置成不再保持回调,删除回调函数对象 |
if (!keepCallback) { |
delete cordova.callbacks[callbackId]; |
} |
} |
}, |
// 没有地方用到! |
// 目的是把你自己的函数在注入到Cordova的生命周期中。 |
addConstructor: function(func) { |
channel.onCordovaReady.subscribe(function() { |
try { |
func(); |
} catch(e) { |
console.log("Failed to run constructor: " + e); |
} |
}); |
} |
}; |
module.exports = cordova; |
}); |