-
Notifications
You must be signed in to change notification settings - Fork 21
demo
在写自己的博客系统的时候想要做一个markdown编辑器,参考了csdn的markdown编辑器和一些开源的实现(例如:suMarkdown)之后,感觉还是使用比较成熟的stackedit来定制比较方便。主要还是因为初学JS的缘故,要实现的功能其中好多都要现学,好麻烦……
在开发之前首先有一些预安装的依赖参见stackedit的developer-guide。安装之后启动Nodejs服务器,能够看到和http://stackedit.io相同的页面,这样可以来到stackedit的编辑器。这样我们就可以修改源码并查看效果了。
- 加载流程: stackedit是通过nodejs的express框架来实现路由的,在server.js中我们发现服务器调用app模块来进行路由,编辑器的路径映射到views/editor.html,这之后通过requirejs的管理来加载相应的模块,细节详见代码。
我们从core
开始分析:
core
的功能包括:
- creating the UI Layout, the ACE editor and the PageDown editor,
- loading/saving the settings,
- running periodic tasks,
- detecting the user activity,
- checking the offline status.
###offline
在设置在线状态的时候,core
中使用了setOnline
和setOffline
函数,里面都调用了eventMgr.onOfflineChanged()
函数,代码如下:
core.setOffline = function() {
offlineTime = utils.currentTime;
if(isOffline === false) {
isOffline = true;
eventMgr.onOfflineChanged(true);
}
};
function setOnline() {
if(isOffline === true) {
isOffline = false;
eventMgr.onOfflineChanged(false);
}
}
阅读其他部分代码也可发现这个类型的函数有很多,通过阅读开发者指南我们发现这个类型的函数用来触发相应的事件,下面我们深入eventMgr
来一探究竟。
和以上函数相关的语句:
addEventHook("onOfflineChanged");
function addEventHook(eventName) {
eventMgr[eventName] = createEventHook(eventName);
}
function createEventHook(eventName) {
eventListenerListMap[eventName] = getExtensionListenerList(eventName);
return function() {
logger.log(eventName, arguments);
var eventArguments = arguments;
_.each(eventListenerListMap[eventName], function(listener) {
// Use try/catch in case userCustom listener contains error
try {
listener.apply(null, eventArguments);
}
catch(e) {
console.error(_.isObject(e) ? e.stack : e);
}
});
};
}
function getExtensionListenerList(eventName) {
return _.chain(extensionList).map(function(extension) {
return extension.enabled && extension[eventName];
}).compact().value();
}
var extensionList = _.chain(arguments).map(function(argument) {
return argument instanceof Extension && argument;
}).compact().value();
其中,_.chain()
和map()
都是underscorejs
中的:
_.chain(obj) 返回一个封装的对象. 在封装的对象上调用方法会返回封装的对象本身, 直道 value 方法调用为止.
_.map(list, iteratee, [context]) Alias: collect 通过转换函数(iteratee迭代器)映射列表中的每个值产生价值的新数组。iteratee传递三个参数:value,然后是迭代 index(或 key 愚人码头注:如果list是个JavaScript对象是,这个参数就是key),最后一个是引用指向整个list。
_.map([1, 2, 3], function(num){ return num * 3; }); => [3, 6, 9] _.map({one: 1, two: 2, three: 3}, function(num, key){ return num * 3; }); => [3, 6, 9] _.map(1, 2], [3, 4, .first); => [1, 3] **.each(list, iteratee, [context]) Alias: forEach** 遍历list中的所有元素,按顺序用遍历输出每个元素。如果传递了context参数,则把iteratee绑定到context对象上。每次调用iteratee都会传递三个参数:(element, index, list)。如果list是个JavaScript对象,iteratee的参数是 (value, key, list))。返回list以方便链式调用。(愚人码头注:如果存在原生的forEach方法,Underscore就使用它代替。)
_.each([1, 2, 3], alert); => alerts each number in turn... .each({one: 1, two: 2, three: 3}, alert); => alerts each number value in turn... **.compact(array)** 返回一个除去所有false值的 array副本。 在javascript中, false, null, 0, "", undefined 和 NaN 都是false值.
_.compact([0, 1, false, 2, '', 3]); => [1, 2, 3]
_.each(list, iteratee, [context]) Alias: forEach 遍历list中的所有元素,按顺序用遍历输出每个元素。如果传递了context参数,则把iteratee绑定到context对象上。每次调用iteratee都会传递三个参数:(element, index, list)。如果list是个JavaScript对象,iteratee的参数是 (value, key, list))。返回list以方便链式调用。(愚人码头注:如果存在原生的forEach方法,Underscore就使用它代替。)
_.each([1, 2, 3], alert); => alerts each number in turn... _.each({one: 1, two: 2, three: 3}, alert); => alerts each number value in turn...
这段代码主要的逻辑就是调用eventMgr.onMessage
这类的函数会发送相应的消息,和extensions中的对应的事件的响应函数联系起来,发送消息后即会触发这些函数。
回到offline判断的话题,其实经过测试,由于有
var isOffline = false;
的存在,再加上checkOnline
只有在离线状态才进行检查,如下:
function checkOnline() {
// Try to reconnect if we are offline but we have some networks
if(isOffline === true && navigator.onLine === true && offlineTime + constants.CHECK_ONLINE_PERIOD < utils.currentTime) {
offlineTime = utils.currentTime;
// Try to download anything to test the connection
$.ajax({
url: "//www.google.com/jsapi",
timeout: constants.AJAX_TIMEOUT,
dataType: "script"
}).done(function() {
setOnline();
});
}
}
所以一开始状态一直是在线状态。但是在进行同步的时候就可能改变状态,再加上检测在线的代码中是从google的网站上下载来判断是否在线,和国情不符,于是我们进行了一下修改:
function checkOnline() {
// Try to reconnect if we are offline but we have some networks
if(isOffline === true && navigator.onLine === true && offlineTime + constants.CHECK_ONLINE_PERIOD < utils.currentTime) {
offlineTime = utils.currentTime;
// Try to download anything to test the connection
$.ajax({
url: "//api.github.com/",
timeout: constants.AJAX_TIMEOUT,
dataType: "json"
}).done(function() {
setOnline();
});
}
}
这样就能正确的判断是否在线了。