Stackedit/public/res/eventMgr.js

333 lines
13 KiB
JavaScript
Raw Normal View History

2013-07-30 08:46:36 +00:00
define([
"jquery",
"underscore",
"crel",
"utils",
2013-11-07 23:10:38 +00:00
"logger",
2013-07-30 08:46:36 +00:00
"classes/Extension",
"settings",
"text!html/settingsExtensionsAccordion.html",
2013-10-06 14:34:01 +00:00
"extensions/yamlFrontMatterParser",
"extensions/markdownSectionParser",
2013-07-30 08:46:36 +00:00
"extensions/partialRendering",
2013-08-22 00:19:59 +00:00
"extensions/buttonMarkdownSyntax",
2013-07-30 08:46:36 +00:00
"extensions/googleAnalytics",
2014-02-02 21:00:05 +00:00
"extensions/twitter",
2013-07-30 08:46:36 +00:00
"extensions/dialogAbout",
"extensions/dialogManagePublication",
"extensions/dialogManageSynchronization",
2013-12-01 15:43:46 +00:00
"extensions/dialogManageSharing",
2013-07-30 08:46:36 +00:00
"extensions/dialogOpenHarddrive",
2013-08-12 00:10:26 +00:00
"extensions/documentTitle",
2013-07-30 08:46:36 +00:00
"extensions/documentSelector",
2013-08-12 00:10:26 +00:00
"extensions/documentPanel",
2013-08-11 00:52:05 +00:00
"extensions/documentManager",
2013-07-30 08:46:36 +00:00
"extensions/workingIndicator",
"extensions/notifications",
"extensions/markdownExtra",
"extensions/toc",
"extensions/mathJax",
"extensions/emailConverter",
"extensions/scrollLink",
2013-09-12 23:25:25 +00:00
"extensions/buttonFocusMode",
2013-07-30 08:46:36 +00:00
"extensions/buttonSync",
"extensions/buttonPublish",
"extensions/buttonStat",
"extensions/buttonHtmlCode",
"extensions/buttonViewer",
2013-09-03 10:37:59 +00:00
"extensions/welcomeTour",
2013-10-03 01:02:52 +00:00
"extensions/spellCheck",
2013-09-15 01:35:58 +00:00
"extensions/userCustom",
2013-08-30 22:45:29 +00:00
"bootstrap",
"jquery-waitforimages"
2013-11-07 23:10:38 +00:00
], function($, _, crel, utils, logger, Extension, settings, settingsExtensionsAccordionHTML) {
2013-07-30 08:46:36 +00:00
var eventMgr = {};
// Create a list of extensions from module arguments
var extensionList = _.chain(arguments).map(function(argument) {
return argument instanceof Extension && argument;
}).compact().value();
// Configure extensions
2013-11-07 23:10:38 +00:00
var extensionSettings = settings.extensionSettings || {};
2013-07-30 08:46:36 +00:00
_.each(extensionList, function(extension) {
2013-08-21 00:16:10 +00:00
// Set the extension.config attribute from settings or default
// configuration
2013-07-30 08:46:36 +00:00
extension.config = _.extend({}, extension.defaultConfig, extensionSettings[extension.extensionId]);
2013-11-07 23:10:38 +00:00
if(window.viewerMode === true && extension.disableInViewer === true) {
2013-08-21 00:16:10 +00:00
// Skip enabling the extension if we are in the viewer and extension
// doesn't support it
2013-07-31 12:49:05 +00:00
extension.enabled = false;
}
2013-11-07 23:10:38 +00:00
else if(window.lightMode === true && extension.disableInLight === true) {
2013-09-12 23:25:25 +00:00
// Same for light mode
extension.enabled = false;
}
2013-07-31 12:49:05 +00:00
else {
2013-08-21 00:16:10 +00:00
// Enable the extension if it's not optional or it has not been
// disabled by the user
extension.enabled = !extension.isOptional || extension.config.enabled === undefined || extension.config.enabled === true;
2013-07-30 08:46:36 +00:00
}
});
2013-08-21 00:16:10 +00:00
// Returns all listeners with the specified name that are implemented in the
// enabled extensions
2013-07-30 08:46:36 +00:00
function getExtensionListenerList(eventName) {
return _.chain(extensionList).map(function(extension) {
2013-07-31 12:49:05 +00:00
return extension.enabled && extension[eventName];
2013-07-30 08:46:36 +00:00
}).compact().value();
}
2013-08-21 00:16:10 +00:00
// Returns a function that calls every listeners with the specified name
// from all enabled extensions
2013-07-30 08:46:36 +00:00
var eventListenerListMap = {};
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) {
2013-08-21 00:16:10 +00:00
console.error(_.isObject(e) ? e.stack : e);
2013-07-30 08:46:36 +00:00
}
});
};
}
2013-08-21 00:16:10 +00:00
2013-11-17 22:59:03 +00:00
// Declare an event Hook in the eventMgr that we can fire using eventMgr.eventName()
2013-07-30 08:46:36 +00:00
function addEventHook(eventName) {
eventMgr[eventName] = createEventHook(eventName);
}
// Used by external modules (not extensions) to listen to events
eventMgr.addListener = function(eventName, listener) {
try {
eventListenerListMap[eventName].push(listener);
2013-08-21 00:16:10 +00:00
}
catch(e) {
2013-07-30 08:46:36 +00:00
console.error('No event listener called ' + eventName);
}
};
2013-11-17 22:59:03 +00:00
// Call every onInit listeners (enabled extensions only)
2013-07-30 08:46:36 +00:00
createEventHook("onInit")();
// Load/Save extension config from/to settings
2013-11-07 23:10:38 +00:00
eventMgr.onLoadSettings = function() {
2013-07-30 08:46:36 +00:00
logger.log("onLoadSettings");
_.each(extensionList, function(extension) {
2013-12-05 00:25:17 +00:00
var isChecked = !extension.isOptional || extension.config.enabled === undefined || extension.config.enabled === true;
2014-01-21 23:48:42 +00:00
utils.setInputChecked("#input-enable-extension-" + extension.extensionId, isChecked);
// Special case for Markdown Extra and MathJax
if(extension.extensionId == 'markdownExtra') {
utils.setInputChecked("#input-settings-markdown-extra", isChecked);
}
else if(extension.extensionId == 'mathJax') {
utils.setInputChecked("#input-settings-mathjax", isChecked);
}
2013-07-30 08:46:36 +00:00
var onLoadSettingsListener = extension.onLoadSettings;
onLoadSettingsListener && onLoadSettingsListener();
});
};
2013-11-07 23:10:38 +00:00
eventMgr.onSaveSettings = function(newExtensionSettings, event) {
2013-07-30 08:46:36 +00:00
logger.log("onSaveSettings");
_.each(extensionList, function(extension) {
2014-02-02 21:00:05 +00:00
if(window.lightMode === true && extension.disableInLight === true) {
newExtensionSettings[extension.extensionId] = extension.config;
return;
}
2013-07-30 08:46:36 +00:00
var newExtensionConfig = _.extend({}, extension.defaultConfig);
newExtensionConfig.enabled = utils.getInputChecked("#input-enable-extension-" + extension.extensionId);
2014-01-21 23:48:42 +00:00
var isChecked;
// Special case for Markdown Extra and MathJax
if(extension.extensionId == 'markdownExtra') {
isChecked = utils.getInputChecked("#input-settings-markdown-extra");
if(isChecked != extension.enabled) {
newExtensionConfig.enabled = isChecked;
}
}
else if(extension.extensionId == 'mathJax') {
isChecked = utils.getInputChecked("#input-settings-mathjax");
if(isChecked != extension.enabled) {
newExtensionConfig.enabled = isChecked;
}
}
2013-07-30 08:46:36 +00:00
var onSaveSettingsListener = extension.onSaveSettings;
onSaveSettingsListener && onSaveSettingsListener(newExtensionConfig, event);
newExtensionSettings[extension.extensionId] = newExtensionConfig;
});
};
addEventHook("onMessage");
addEventHook("onError");
addEventHook("onOfflineChanged");
2013-08-04 00:53:46 +00:00
addEventHook("onUserActive");
2013-09-15 01:35:58 +00:00
addEventHook("onAsyncRunning");
addEventHook("onPeriodicRun");
2013-07-30 08:46:36 +00:00
// To access modules that are loaded after extensions
addEventHook("onFileMgrCreated");
addEventHook("onSynchronizerCreated");
addEventHook("onPublisherCreated");
addEventHook("onEventMgrCreated");
// Operations on files
addEventHook("onFileCreated");
addEventHook("onFileDeleted");
addEventHook("onFileSelected");
addEventHook("onFileOpen");
addEventHook("onFileClosed");
addEventHook("onContentChanged");
addEventHook("onTitleChanged");
2013-08-21 00:16:10 +00:00
2013-08-12 00:10:26 +00:00
// Operations on folders
addEventHook("onFoldersChanged");
2013-07-30 08:46:36 +00:00
// Sync events
addEventHook("onSyncRunning");
addEventHook("onSyncSuccess");
addEventHook("onSyncImportSuccess");
addEventHook("onSyncExportSuccess");
addEventHook("onSyncRemoved");
// Publish events
addEventHook("onPublishRunning");
addEventHook("onPublishSuccess");
addEventHook("onNewPublishSuccess");
addEventHook("onPublishRemoved");
// Operations on Layout
addEventHook("onLayoutConfigure");
addEventHook("onLayoutCreated");
2013-09-09 00:08:55 +00:00
addEventHook("onLayoutResize");
2013-07-30 08:46:36 +00:00
// Operations on PageDown
2013-09-09 23:32:24 +00:00
addEventHook("onPagedownConfigure");
2013-07-30 08:46:36 +00:00
addEventHook("onSectionsCreated");
addEventHook("onMarkdownTrim");
2013-11-17 22:59:03 +00:00
2013-09-09 23:32:24 +00:00
// Operation on ACE
addEventHook("onAceCreated");
2014-02-02 21:00:05 +00:00
// Refresh twitter buttons
addEventHook("onTweet");
2013-07-30 08:46:36 +00:00
var onPreviewFinished = createEventHook("onPreviewFinished");
var onAsyncPreviewListenerList = getExtensionListenerList("onAsyncPreview");
2013-11-07 23:10:38 +00:00
var previewContentsElt;
var $previewContentsElt;
eventMgr.onAsyncPreview = function() {
2013-07-30 08:46:36 +00:00
logger.log("onAsyncPreview");
logger.log("Conversion time: " + (new Date() - eventMgr.previewStartTime));
2013-09-15 01:35:58 +00:00
function recursiveCall(callbackList) {
var callback = callbackList.length ? callbackList.shift() : function() {
2013-07-30 08:46:36 +00:00
logger.log("Preview time: " + (new Date() - eventMgr.previewStartTime));
_.defer(function() {
var html = "";
_.each(previewContentsElt.children, function(elt) {
html += elt.innerHTML;
});
html = html.replace(/^<div class="se-section-delimiter"><\/div>\n\n/gm, '');
2014-01-21 23:48:42 +00:00
html = html.replace(/ <span class="comment label label-danger">.*<\/span> /g, '');
2013-07-30 08:46:36 +00:00
onPreviewFinished(utils.trim(html));
});
2013-09-15 01:35:58 +00:00
};
callback(function() {
recursiveCall(callbackList);
});
2013-07-30 08:46:36 +00:00
}
2013-09-15 01:35:58 +00:00
recursiveCall(onAsyncPreviewListenerList.concat([function(callback) {
// We assume some images are loading asynchronously after the preview
$previewContentsElt.waitForImages(callback);
}]));
2013-07-30 08:46:36 +00:00
};
var onReady = createEventHook("onReady");
2013-11-07 23:10:38 +00:00
eventMgr.onReady = function() {
2013-07-30 08:46:36 +00:00
previewContentsElt = document.getElementById('preview-contents');
2013-08-22 00:19:59 +00:00
$previewContentsElt = $(previewContentsElt);
2013-08-21 00:16:10 +00:00
2013-11-09 00:09:42 +00:00
// Create a button from an extension listener
var createBtn = function(listener) {
var buttonGrpElt = crel('div', {
class: 'btn-group'
});
var btnElt = listener();
if(_.isString(btnElt)) {
buttonGrpElt.innerHTML = btnElt;
}
else if(_.isElement(btnElt)) {
buttonGrpElt.appendChild(btnElt);
}
return buttonGrpElt;
};
2013-11-07 23:10:38 +00:00
if(window.viewerMode === false) {
2013-07-30 08:46:36 +00:00
// Create accordion in settings dialog
var accordionHtml = _.chain(extensionList).sortBy(function(extension) {
return extension.extensionName.toLowerCase();
}).reduce(function(html, extension) {
2014-01-21 23:48:42 +00:00
return html + (extension.settingsBlock && !(window.lightMode === true && extension.disableInLight === true) ? _.template(settingsExtensionsAccordionHTML, {
2013-07-30 08:46:36 +00:00
extensionId: extension.extensionId,
extensionName: extension.extensionName,
isOptional: extension.isOptional,
settingsBlock: extension.settingsBlock
2013-08-21 00:16:10 +00:00
}) : "");
2013-07-30 08:46:36 +00:00
}, "").value();
2013-08-15 23:17:16 +00:00
document.querySelector('.accordion-extensions').innerHTML = accordionHtml;
2014-01-21 23:48:42 +00:00
2013-07-30 08:46:36 +00:00
// Create extension buttons
logger.log("onCreateButton");
var onCreateButtonListenerList = getExtensionListenerList("onCreateButton");
var extensionButtonsFragment = document.createDocumentFragment();
_.each(onCreateButtonListenerList, function(listener) {
extensionButtonsFragment.appendChild(createBtn(listener));
});
2013-12-01 15:43:46 +00:00
document.querySelector('.extension-buttons').appendChild(extensionButtonsFragment);
2013-07-30 08:46:36 +00:00
2013-09-11 23:26:47 +00:00
// Create extension editor buttons
logger.log("onCreateEditorButton");
var onCreateEditorButtonListenerList = getExtensionListenerList("onCreateEditorButton");
var extensionEditorButtonsFragment = document.createDocumentFragment();
_.each(onCreateEditorButtonListenerList, function(listener) {
extensionEditorButtonsFragment.appendChild(createBtn(listener));
});
var editorButtonsElt = document.querySelector('.extension-editor-buttons');
editorButtonsElt.appendChild(extensionEditorButtonsFragment);
2013-07-30 08:46:36 +00:00
}
2013-09-15 01:35:58 +00:00
// Create extension preview buttons
logger.log("onCreatePreviewButton");
var onCreatePreviewButtonListenerList = getExtensionListenerList("onCreatePreviewButton");
var extensionPreviewButtonsFragment = document.createDocumentFragment();
_.each(onCreatePreviewButtonListenerList, function(listener) {
extensionPreviewButtonsFragment.appendChild(createBtn(listener));
});
var previewButtonsElt = document.querySelector('.extension-preview-buttons');
previewButtonsElt.appendChild(extensionPreviewButtonsFragment);
// A bit of jQuery...
var $previewButtonsElt = $(previewButtonsElt);
var previewButtonsWidth = $previewButtonsElt.width();
$previewButtonsElt.find('.btn-group').each(function() {
var $btnGroupElt = $(this);
// Align dropdown to the left of the screen
$btnGroupElt.find('.dropdown-menu').css({
right: -previewButtonsWidth + $btnGroupElt.width() + $btnGroupElt.position().left
});
});
2013-07-30 08:46:36 +00:00
// Call onReady listeners
onReady();
};
// For extensions that need to call other extensions
eventMgr.onEventMgrCreated(eventMgr);
return eventMgr;
});