2013-04-10 18:14:59 +00:00
|
|
|
define(
|
2013-05-12 00:48:25 +00:00
|
|
|
[ "jquery", "mathjax-editing", "bootstrap", "jgrowl", "layout", "Markdown.Editor", "storage", "config",
|
2013-04-26 23:08:13 +00:00
|
|
|
"underscore", "FileSaver", "css_browser_selector" ],
|
2013-05-12 00:48:25 +00:00
|
|
|
function($, mathjaxEditing) {
|
2013-04-02 18:42:47 +00:00
|
|
|
|
|
|
|
var core = {};
|
|
|
|
|
2013-05-18 13:40:16 +00:00
|
|
|
// For convenience
|
2013-04-10 18:14:59 +00:00
|
|
|
core.doNothing = function() {};
|
|
|
|
|
2013-04-02 18:42:47 +00:00
|
|
|
// Time shared by others modules
|
2013-04-10 18:14:59 +00:00
|
|
|
function updateCurrentTime() {
|
2013-04-02 18:42:47 +00:00
|
|
|
core.currentTime = new Date().getTime();
|
2013-04-10 18:14:59 +00:00
|
|
|
}
|
2013-05-18 13:40:16 +00:00
|
|
|
updateCurrentTime();
|
2013-04-02 18:42:47 +00:00
|
|
|
|
2013-04-21 00:07:27 +00:00
|
|
|
// Used for periodic tasks
|
|
|
|
var intervalId = undefined;
|
|
|
|
var periodicCallbacks = [];
|
|
|
|
core.addPeriodicCallback = function(callback) {
|
|
|
|
periodicCallbacks.push(callback);
|
|
|
|
};
|
|
|
|
|
2013-04-10 18:14:59 +00:00
|
|
|
// Used to detect user activity
|
|
|
|
var userReal = false;
|
|
|
|
var userActive = false;
|
|
|
|
var windowUnique = true;
|
|
|
|
var userLastActivity = 0;
|
|
|
|
function setUserActive() {
|
|
|
|
userReal = true;
|
|
|
|
userActive = true;
|
|
|
|
userLastActivity = core.currentTime;
|
|
|
|
};
|
|
|
|
function isUserActive() {
|
|
|
|
if(userActive === true
|
|
|
|
&& core.currentTime - userLastActivity > USER_IDLE_THRESHOLD) {
|
|
|
|
userActive = false;
|
|
|
|
}
|
|
|
|
return userActive && windowUnique;
|
|
|
|
}
|
2013-04-03 22:52:29 +00:00
|
|
|
|
2013-04-10 18:14:59 +00:00
|
|
|
// Used to only have 1 window of the application in the same browser
|
|
|
|
var windowId = undefined;
|
|
|
|
core.checkWindowUnique = function() {
|
|
|
|
if(userReal === false || windowUnique === false) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(windowId === undefined) {
|
2013-04-11 22:38:41 +00:00
|
|
|
windowId = core.randomString();
|
2013-04-10 18:14:59 +00:00
|
|
|
localStorage["frontWindowId"] = windowId;
|
|
|
|
}
|
|
|
|
var frontWindowId = localStorage["frontWindowId"];
|
|
|
|
if(frontWindowId != windowId) {
|
|
|
|
windowUnique = false;
|
2013-04-11 22:38:41 +00:00
|
|
|
if(intervalId !== undefined) {
|
|
|
|
clearInterval(intervalId);
|
|
|
|
}
|
2013-04-10 23:13:31 +00:00
|
|
|
$(".modal").modal("hide");
|
2013-04-10 18:14:59 +00:00
|
|
|
$('#modal-non-unique').modal({
|
|
|
|
backdrop: "static",
|
|
|
|
keyboard: false
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
2013-04-03 22:52:29 +00:00
|
|
|
|
2013-04-10 23:13:31 +00:00
|
|
|
// Useful function for input control
|
|
|
|
function inputError(element, event) {
|
|
|
|
if(event !== undefined) {
|
2013-05-19 18:56:15 +00:00
|
|
|
element.stop(true, true).addClass("error").delay(800).switchClass("error");
|
2013-04-10 23:13:31 +00:00
|
|
|
event.stopPropagation();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
core.getInputValue = function(element, event, validationRegex) {
|
2013-04-03 22:52:29 +00:00
|
|
|
var value = element.val();
|
2013-04-10 23:13:31 +00:00
|
|
|
if (value === undefined) {
|
|
|
|
inputError(element, event);
|
|
|
|
return undefined;
|
2013-04-03 22:52:29 +00:00
|
|
|
}
|
2013-04-10 23:13:31 +00:00
|
|
|
// trim
|
2013-04-22 22:35:29 +00:00
|
|
|
value = core.trim(value);
|
2013-04-10 23:13:31 +00:00
|
|
|
if((value.length === 0)
|
|
|
|
|| (validationRegex !== undefined && !value.match(validationRegex))) {
|
|
|
|
inputError(element, event);
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
return value;
|
|
|
|
};
|
|
|
|
core.getInputIntValue = function(element, event, min, max) {
|
|
|
|
var value = core.getInputValue(element, event);
|
|
|
|
if(value === undefined) {
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
value = parseInt(value);
|
|
|
|
if((value === NaN)
|
|
|
|
|| (min !== undefined && value < min)
|
|
|
|
|| (max !== undefined && value > max)) {
|
|
|
|
inputError(element, event);
|
2013-04-03 22:52:29 +00:00
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
return value;
|
|
|
|
};
|
2013-04-10 23:13:31 +00:00
|
|
|
core.resetModalInputs = function() {
|
2013-05-19 18:56:15 +00:00
|
|
|
$(".modal input[type=text]:not([disabled]), .modal input[type=password]").val("");
|
2013-04-10 23:13:31 +00:00
|
|
|
};
|
2013-04-22 22:35:29 +00:00
|
|
|
core.trim = function(str) {
|
|
|
|
return str.replace(/^\s+|\s+$/g, '');
|
|
|
|
};
|
2013-05-19 18:56:15 +00:00
|
|
|
core.checkUrl = function(url, addSlash) {
|
|
|
|
if(!url) {
|
|
|
|
return url;
|
|
|
|
}
|
2013-04-22 22:35:29 +00:00
|
|
|
if(url.indexOf("http") !== 0) {
|
2013-05-19 18:56:15 +00:00
|
|
|
url = "http://" + url;
|
|
|
|
}
|
|
|
|
if(addSlash && url.indexOf("/", url.length - 1) === -1) {
|
|
|
|
url += "/";
|
2013-04-22 22:35:29 +00:00
|
|
|
}
|
|
|
|
return url;
|
|
|
|
};
|
2013-04-22 23:10:08 +00:00
|
|
|
|
|
|
|
core.saveFile = function(content, filename) {
|
|
|
|
if(saveAs !== undefined) {
|
|
|
|
var blob = new Blob([content], {type: "text/plain;charset=utf-8"});
|
|
|
|
saveAs(blob, filename);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
var uriContent = "data:application/octet-stream;base64,"
|
|
|
|
+ core.encodeBase64(content);
|
|
|
|
window.open(uriContent, 'file');
|
|
|
|
}
|
|
|
|
};
|
2013-04-02 18:42:47 +00:00
|
|
|
|
2013-04-20 00:14:20 +00:00
|
|
|
// Used by asyncRunner
|
2013-04-02 18:42:47 +00:00
|
|
|
core.showWorkingIndicator = function(show) {
|
|
|
|
if (show === false) {
|
2013-04-27 23:16:38 +00:00
|
|
|
$(".working-indicator").removeClass("show");
|
2013-04-03 22:52:29 +00:00
|
|
|
$("body").removeClass("working");
|
2013-04-02 18:42:47 +00:00
|
|
|
} else {
|
2013-04-27 23:16:38 +00:00
|
|
|
$(".working-indicator").addClass("show");
|
2013-04-03 22:52:29 +00:00
|
|
|
$("body").addClass("working");
|
2013-04-02 18:42:47 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// Used to show a notification message
|
|
|
|
core.showMessage = function(msg, iconClass, options) {
|
2013-04-20 00:14:20 +00:00
|
|
|
if(!msg) {
|
|
|
|
return;
|
|
|
|
}
|
2013-04-21 00:07:27 +00:00
|
|
|
var endOfMsg = msg.indexOf("|");
|
|
|
|
if(endOfMsg !== -1) {
|
|
|
|
msg = msg.substring(0, endOfMsg);
|
2013-04-21 00:51:07 +00:00
|
|
|
if(!msg) {
|
|
|
|
return;
|
|
|
|
}
|
2013-04-21 00:07:27 +00:00
|
|
|
}
|
2013-04-02 18:42:47 +00:00
|
|
|
options = options || {};
|
|
|
|
iconClass = iconClass || "icon-info-sign";
|
2013-04-13 18:11:54 +00:00
|
|
|
$.jGrowl("<i class='icon-white " + iconClass + "'></i> " + _.escape(msg), options);
|
2013-04-02 18:42:47 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// Used to show an error message
|
|
|
|
core.showError = function(msg) {
|
|
|
|
core.showMessage(msg, "icon-warning-sign");
|
|
|
|
};
|
|
|
|
|
|
|
|
// Offline management
|
|
|
|
core.isOffline = false;
|
|
|
|
var offlineTime = core.currentTime;
|
|
|
|
var offlineListeners = [];
|
2013-04-21 00:07:27 +00:00
|
|
|
core.addOfflineListener = function(callback) {
|
|
|
|
offlineListeners.push(callback);
|
|
|
|
};
|
2013-04-02 18:42:47 +00:00
|
|
|
core.setOffline = function() {
|
|
|
|
offlineTime = core.currentTime;
|
|
|
|
if(core.isOffline === false) {
|
|
|
|
core.isOffline = true;
|
|
|
|
core.showMessage("You are offline.", "icon-exclamation-sign msg-offline", {
|
|
|
|
sticky : true,
|
|
|
|
close : function() {
|
|
|
|
core.showMessage("You are back online!", "icon-signal");
|
|
|
|
}
|
|
|
|
});
|
|
|
|
for(var i=0; i<offlineListeners.length; i++) {
|
|
|
|
offlineListeners[i]();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
core.setOnline = function() {
|
2013-04-03 22:52:29 +00:00
|
|
|
if(core.isOffline === true) {
|
2013-04-02 18:42:47 +00:00
|
|
|
$(".msg-offline").parents(".jGrowl-notification").trigger(
|
|
|
|
'jGrowl.beforeClose');
|
|
|
|
core.isOffline = false;
|
|
|
|
for(var i=0; i<offlineListeners.length; i++) {
|
|
|
|
offlineListeners[i]();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2013-04-10 18:14:59 +00:00
|
|
|
function checkOnline() {
|
2013-04-02 18:42:47 +00:00
|
|
|
// Try to reconnect if we are offline but we have some network
|
|
|
|
if (core.isOffline === true && navigator.onLine === true
|
|
|
|
&& offlineTime + CHECK_ONLINE_PERIOD < core.currentTime) {
|
|
|
|
offlineTime = core.currentTime;
|
|
|
|
// Try to download anything to test the connection
|
|
|
|
$.ajax({
|
2013-04-05 23:59:59 +00:00
|
|
|
url : "//www.google.com/jsapi",
|
2013-04-02 18:42:47 +00:00
|
|
|
timeout : AJAX_TIMEOUT, dataType : "script"
|
|
|
|
}).done(function() {
|
|
|
|
core.setOnline();
|
|
|
|
});
|
|
|
|
}
|
2013-04-10 18:14:59 +00:00
|
|
|
}
|
2013-04-02 18:42:47 +00:00
|
|
|
|
|
|
|
// Setting management
|
2013-04-11 22:38:41 +00:00
|
|
|
core.settings = {
|
2013-04-20 17:40:05 +00:00
|
|
|
converterType : "markdown-extra-prettify",
|
2013-05-12 23:59:17 +00:00
|
|
|
enableMathJax : true,
|
2013-05-13 23:10:02 +00:00
|
|
|
lazyRendering : true,
|
2013-04-10 23:13:31 +00:00
|
|
|
layoutOrientation : "horizontal",
|
2013-04-26 23:08:13 +00:00
|
|
|
scrollLink : true,
|
2013-04-11 22:38:41 +00:00
|
|
|
editorFontSize : 14,
|
2013-04-29 21:41:10 +00:00
|
|
|
defaultContent: "\n\n\n> Written with [StackEdit](http://benweet.github.io/stackedit/).",
|
|
|
|
commitMsg : "Published by http://benweet.github.io/stackedit",
|
2013-04-14 13:24:29 +00:00
|
|
|
template : ['<!DOCTYPE html>\n',
|
|
|
|
'<html>\n',
|
|
|
|
'<head>\n',
|
|
|
|
'<title><%= documentTitle %></title>\n',
|
|
|
|
'</head>\n',
|
|
|
|
'<body><%= documentHTML %></body>\n',
|
2013-05-19 18:56:15 +00:00
|
|
|
'</html>'].join(""),
|
|
|
|
sshProxy : SSH_PROXY_URL,
|
|
|
|
sshConnectionList : []
|
2013-04-10 23:13:31 +00:00
|
|
|
};
|
|
|
|
|
2013-04-02 18:42:47 +00:00
|
|
|
core.loadSettings = function() {
|
|
|
|
if (localStorage.settings) {
|
2013-04-11 22:38:41 +00:00
|
|
|
$.extend(core.settings, JSON.parse(localStorage.settings));
|
2013-04-02 18:42:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Layout orientation
|
|
|
|
$("input:radio[name=radio-layout-orientation][value="
|
2013-04-11 22:38:41 +00:00
|
|
|
+ core.settings.layoutOrientation + "]").prop("checked", true);
|
2013-04-26 23:08:13 +00:00
|
|
|
// Scroll Link
|
|
|
|
$("#input-settings-scroll-link").prop("checked", core.settings.scrollLink);
|
2013-04-15 16:23:34 +00:00
|
|
|
// Converter type
|
|
|
|
$("#input-settings-converter-type").val(core.settings.converterType);
|
2013-05-12 23:59:17 +00:00
|
|
|
// MathJax
|
|
|
|
$("#input-settings-enable-mathjax").prop("checked", core.settings.enableMathJax);
|
2013-05-13 23:10:02 +00:00
|
|
|
// Lazy rendering
|
|
|
|
$("#input-settings-lazy-rendering").prop("checked", core.settings.lazyRendering);
|
2013-04-10 23:13:31 +00:00
|
|
|
// Editor font size
|
2013-04-11 22:38:41 +00:00
|
|
|
$("#input-settings-editor-font-size").val(core.settings.editorFontSize);
|
2013-04-29 21:41:10 +00:00
|
|
|
// Default content
|
|
|
|
$("#textarea-settings-default-content").val(core.settings.defaultContent);
|
2013-04-11 22:38:41 +00:00
|
|
|
// Commit message
|
|
|
|
$("#input-settings-publish-commit-msg").val(core.settings.commitMsg);
|
2013-04-14 13:24:29 +00:00
|
|
|
// Template
|
|
|
|
$("#textarea-settings-publish-template").val(core.settings.template);
|
2013-05-19 18:56:15 +00:00
|
|
|
// SSH proxy
|
|
|
|
$("#input-settings-ssh-proxy").val(core.settings.sshProxy);
|
2013-04-02 18:42:47 +00:00
|
|
|
};
|
|
|
|
|
2013-04-10 23:13:31 +00:00
|
|
|
core.saveSettings = function(event) {
|
|
|
|
var newSettings = {};
|
|
|
|
|
2013-04-02 18:42:47 +00:00
|
|
|
// Layout orientation
|
2013-04-10 23:13:31 +00:00
|
|
|
newSettings.layoutOrientation = $(
|
2013-04-02 18:42:47 +00:00
|
|
|
"input:radio[name=radio-layout-orientation]:checked").prop("value");
|
2013-04-15 16:23:34 +00:00
|
|
|
// Converter type
|
|
|
|
newSettings.converterType = $("#input-settings-converter-type").val();
|
2013-05-12 23:59:17 +00:00
|
|
|
// MathJax
|
|
|
|
newSettings.enableMathJax = $("#input-settings-enable-mathjax").prop("checked");
|
2013-04-26 23:08:13 +00:00
|
|
|
// Scroll Link
|
|
|
|
newSettings.scrollLink = $("#input-settings-scroll-link").prop("checked");
|
2013-05-13 23:10:02 +00:00
|
|
|
// Lazy Rendering
|
|
|
|
newSettings.lazyRendering = $("#input-settings-lazy-rendering").prop("checked");
|
2013-04-10 23:13:31 +00:00
|
|
|
// Editor font size
|
2013-04-11 22:38:41 +00:00
|
|
|
newSettings.editorFontSize = core.getInputIntValue($("#input-settings-editor-font-size"), event, 1, 99);
|
2013-04-29 21:41:10 +00:00
|
|
|
// Default content
|
|
|
|
newSettings.defaultContent = $("#textarea-settings-default-content").val();
|
2013-04-11 22:38:41 +00:00
|
|
|
// Commit message
|
|
|
|
newSettings.commitMsg = core.getInputValue($("#input-settings-publish-commit-msg"), event);
|
2013-04-14 13:24:29 +00:00
|
|
|
// Template
|
|
|
|
newSettings.template = core.getInputValue($("#textarea-settings-publish-template"), event);
|
2013-05-19 18:56:15 +00:00
|
|
|
// SSH proxy
|
|
|
|
newSettings.sshProxy = core.checkUrl(core.getInputValue($("#input-settings-ssh-proxy"), event), true);
|
2013-04-14 13:24:29 +00:00
|
|
|
|
2013-04-10 23:13:31 +00:00
|
|
|
if(!event.isPropagationStopped()) {
|
2013-05-19 18:56:15 +00:00
|
|
|
$.extend(core.settings, newSettings);
|
2013-04-10 23:13:31 +00:00
|
|
|
localStorage.settings = JSON.stringify(newSettings);
|
|
|
|
}
|
2013-04-02 18:42:47 +00:00
|
|
|
};
|
2013-04-14 13:24:29 +00:00
|
|
|
|
2013-04-26 23:08:13 +00:00
|
|
|
// Used by Scroll Link feature
|
|
|
|
var mdSectionList = [];
|
|
|
|
var htmlSectionList = [];
|
|
|
|
function pxToFloat(px) {
|
|
|
|
return parseFloat(px.substring(0, px.length-2));
|
|
|
|
}
|
|
|
|
var buildSections = _.debounce(function() {
|
|
|
|
|
|
|
|
// Try to find Markdown sections by looking for titles
|
|
|
|
var editorElt = $("#wmd-input");
|
|
|
|
mdSectionList = [];
|
|
|
|
// This textarea is used to measure sections height
|
|
|
|
var textareaElt = $("#md-section-helper");
|
|
|
|
// It has to be the same width than wmd-input
|
|
|
|
textareaElt.width(editorElt.width());
|
|
|
|
// Consider wmd-input top padding
|
|
|
|
var padding = pxToFloat(editorElt.css('padding-top'));
|
|
|
|
var offset = 0, mdSectionOffset = 0;
|
|
|
|
function addMdSection(sectionText) {
|
|
|
|
var sectionHeight = padding;
|
2013-04-27 23:16:38 +00:00
|
|
|
if(sectionText !== undefined) {
|
2013-04-26 23:08:13 +00:00
|
|
|
textareaElt.val(sectionText);
|
|
|
|
sectionHeight += textareaElt.prop('scrollHeight');
|
|
|
|
}
|
|
|
|
var newSectionOffset = mdSectionOffset + sectionHeight;
|
|
|
|
mdSectionList.push({
|
|
|
|
startOffset: mdSectionOffset,
|
|
|
|
endOffset: newSectionOffset,
|
|
|
|
height: sectionHeight
|
|
|
|
});
|
|
|
|
mdSectionOffset = newSectionOffset;
|
|
|
|
padding = 0;
|
|
|
|
}
|
|
|
|
// Create MD sections by finding title patterns (excluding gfm blocs)
|
|
|
|
var text = editorElt.val() + "\n\n";
|
|
|
|
text.replace(/^```.*\n[\s\S]*?\n```|(^.+[ \t]*\n=+[ \t]*\n+|^.+[ \t]*\n-+[ \t]*\n+|^\#{1,6}[ \t]*.+?[ \t]*\#*\n+)/gm,
|
|
|
|
function(match, title, matchOffset) {
|
|
|
|
if(title) {
|
|
|
|
// We just found a title which means end of the previous section
|
|
|
|
// Exclude last \n of the section
|
2013-04-27 23:16:38 +00:00
|
|
|
var sectionText = undefined;
|
|
|
|
if(matchOffset > offset) {
|
|
|
|
sectionText = text.substring(offset, matchOffset-1);
|
|
|
|
}
|
|
|
|
addMdSection(sectionText);
|
2013-04-26 23:08:13 +00:00
|
|
|
offset = matchOffset;
|
|
|
|
}
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
);
|
|
|
|
// Last section
|
|
|
|
// Consider wmd-input bottom padding and exclude \n\n previously added
|
|
|
|
padding += pxToFloat(editorElt.css('padding-bottom'));
|
|
|
|
addMdSection(text.substring(offset, text.length-2));
|
|
|
|
|
|
|
|
// Try to find corresponding sections in the preview
|
|
|
|
var previewElt = $("#wmd-preview");
|
|
|
|
htmlSectionList = [];
|
|
|
|
var htmlSectionOffset = 0;
|
|
|
|
var previewScrollTop = previewElt.scrollTop();
|
|
|
|
// Each title element is a section separator
|
|
|
|
previewElt.children("h1,h2,h3,h4,h5,h6").each(function() {
|
|
|
|
// Consider div scroll position and header element top margin
|
|
|
|
var newSectionOffset = $(this).position().top + previewScrollTop + pxToFloat($(this).css('margin-top'));
|
|
|
|
htmlSectionList.push({
|
|
|
|
startOffset: htmlSectionOffset,
|
|
|
|
endOffset: newSectionOffset,
|
|
|
|
height: newSectionOffset - htmlSectionOffset
|
|
|
|
});
|
|
|
|
htmlSectionOffset = newSectionOffset;
|
|
|
|
});
|
|
|
|
// Last section
|
|
|
|
var scrollHeight = previewElt.prop('scrollHeight');
|
|
|
|
htmlSectionList.push({
|
|
|
|
startOffset: htmlSectionOffset,
|
|
|
|
endOffset: scrollHeight,
|
|
|
|
height: scrollHeight - htmlSectionOffset
|
|
|
|
});
|
|
|
|
|
|
|
|
// apply Scroll Link
|
2013-04-27 12:25:02 +00:00
|
|
|
lastEditorScrollTop = -9;
|
2013-05-13 23:10:02 +00:00
|
|
|
skipScrollLink = false;
|
2013-04-26 23:08:13 +00:00
|
|
|
scrollLink();
|
2013-04-27 23:16:38 +00:00
|
|
|
}, 500);
|
2013-04-26 23:08:13 +00:00
|
|
|
|
2013-04-27 23:16:38 +00:00
|
|
|
// -9 is less than -5
|
2013-04-27 12:25:02 +00:00
|
|
|
var lastEditorScrollTop = -9;
|
|
|
|
var lastPreviewScrollTop = -9;
|
2013-05-13 23:10:02 +00:00
|
|
|
var skipScrollLink = false;
|
2013-04-26 23:08:13 +00:00
|
|
|
var scrollLink = _.debounce(function() {
|
2013-05-13 23:10:02 +00:00
|
|
|
if(skipScrollLink === true || mdSectionList.length === 0 || mdSectionList.length !== htmlSectionList.length) {
|
2013-04-26 23:08:13 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
var editorElt = $("#wmd-input");
|
|
|
|
var editorScrollTop = editorElt.scrollTop();
|
|
|
|
var previewElt = $("#wmd-preview");
|
|
|
|
var previewScrollTop = previewElt.scrollTop();
|
2013-05-13 23:10:02 +00:00
|
|
|
function animate(srcScrollTop, srcSectionList, destElt, destSectionList, lastDestScrollTop, callback) {
|
2013-04-26 23:08:13 +00:00
|
|
|
// Find the section corresponding to the offset
|
|
|
|
var sectionIndex = undefined;
|
|
|
|
var srcSection = _.find(srcSectionList, function(section, index) {
|
|
|
|
sectionIndex = index;
|
|
|
|
return srcScrollTop < section.endOffset;
|
|
|
|
});
|
|
|
|
if(srcSection === undefined) {
|
|
|
|
// Something wrong in the algorithm...
|
2013-04-27 23:16:38 +00:00
|
|
|
return -9;
|
2013-04-26 23:08:13 +00:00
|
|
|
}
|
|
|
|
var posInSection = (srcScrollTop - srcSection.startOffset) / srcSection.height;
|
|
|
|
var destSection = destSectionList[sectionIndex];
|
|
|
|
var destScrollTop = destSection.startOffset + destSection.height * posInSection;
|
2013-04-27 23:16:38 +00:00
|
|
|
destScrollTop = _.min([destScrollTop, destElt.prop('scrollHeight') - destElt.outerHeight()]);
|
2013-05-13 23:10:02 +00:00
|
|
|
if(Math.abs(destScrollTop - lastDestScrollTop) < 5) {
|
|
|
|
// Skip the animation in case it's not necessary
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
destElt.animate({scrollTop: destScrollTop}, 600, function() {
|
|
|
|
callback(destScrollTop);
|
|
|
|
});
|
2013-04-26 23:08:13 +00:00
|
|
|
}
|
|
|
|
if(Math.abs(editorScrollTop - lastEditorScrollTop) > 5) {
|
2013-05-10 10:50:23 +00:00
|
|
|
lastEditorScrollTop = editorScrollTop;
|
2013-05-13 23:10:02 +00:00
|
|
|
animate(editorScrollTop, mdSectionList, previewElt, htmlSectionList, lastPreviewScrollTop, function(destScrollTop) {
|
|
|
|
lastPreviewScrollTop = destScrollTop;
|
2013-05-10 10:50:23 +00:00
|
|
|
});
|
2013-04-26 23:08:13 +00:00
|
|
|
}
|
|
|
|
else if(Math.abs(previewScrollTop - lastPreviewScrollTop) > 5) {
|
2013-05-10 10:50:23 +00:00
|
|
|
lastPreviewScrollTop = previewScrollTop;
|
2013-05-13 23:10:02 +00:00
|
|
|
animate(previewScrollTop, htmlSectionList, editorElt, mdSectionList, lastEditorScrollTop, function(destScrollTop) {
|
|
|
|
lastEditorScrollTop = destScrollTop;
|
2013-05-10 10:50:23 +00:00
|
|
|
});
|
2013-04-26 23:08:13 +00:00
|
|
|
}
|
2013-05-10 10:50:23 +00:00
|
|
|
}, 600);
|
2013-04-26 23:08:13 +00:00
|
|
|
|
2013-04-02 18:42:47 +00:00
|
|
|
// Create the layout
|
2013-04-27 12:25:02 +00:00
|
|
|
var layout = undefined;
|
2013-04-02 18:42:47 +00:00
|
|
|
core.createLayout = function() {
|
2013-04-30 23:02:19 +00:00
|
|
|
if(viewerMode === true) {
|
|
|
|
return;
|
|
|
|
}
|
2013-04-02 18:42:47 +00:00
|
|
|
var layoutGlobalConfig = {
|
|
|
|
closable : true,
|
|
|
|
resizable : false,
|
|
|
|
slidable : false,
|
|
|
|
livePaneResizing : true,
|
|
|
|
enableCursorHotkey : false,
|
|
|
|
spacing_open : 15,
|
|
|
|
spacing_closed : 15,
|
|
|
|
togglerLength_open : 90,
|
|
|
|
togglerLength_closed : 90,
|
2013-04-30 23:02:19 +00:00
|
|
|
stateManagement__enabled : false,
|
|
|
|
center__minWidth : 200,
|
|
|
|
center__minHeight : 200
|
2013-04-02 18:42:47 +00:00
|
|
|
};
|
2013-04-26 23:08:13 +00:00
|
|
|
if(core.settings.scrollLink === true) {
|
|
|
|
layoutGlobalConfig.onresize = buildSections;
|
|
|
|
}
|
2013-04-11 22:38:41 +00:00
|
|
|
if (core.settings.layoutOrientation == "horizontal") {
|
2013-04-02 18:42:47 +00:00
|
|
|
$(".ui-layout-south").remove();
|
|
|
|
$(".ui-layout-east").addClass("well").prop("id", "wmd-preview");
|
|
|
|
layout = $('body').layout(
|
|
|
|
$.extend(layoutGlobalConfig, {
|
|
|
|
east__resizable : true,
|
|
|
|
east__size : .5,
|
|
|
|
east__minSize : 200
|
|
|
|
})
|
|
|
|
);
|
2013-04-11 22:38:41 +00:00
|
|
|
} else if (core.settings.layoutOrientation == "vertical") {
|
2013-04-02 18:42:47 +00:00
|
|
|
$(".ui-layout-east").remove();
|
|
|
|
$(".ui-layout-south").addClass("well").prop("id", "wmd-preview");
|
|
|
|
layout = $('body').layout(
|
|
|
|
$.extend(layoutGlobalConfig, {
|
|
|
|
south__resizable : true,
|
|
|
|
south__size : .5,
|
|
|
|
south__minSize : 200
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
$(".ui-layout-toggler-north").addClass("btn").append(
|
|
|
|
$("<b>").addClass("caret"));
|
|
|
|
$(".ui-layout-toggler-south").addClass("btn").append(
|
|
|
|
$("<b>").addClass("caret"));
|
|
|
|
$(".ui-layout-toggler-east").addClass("btn").append(
|
|
|
|
$("<b>").addClass("caret"));
|
|
|
|
$("#navbar").click(function() {
|
|
|
|
layout.allowOverflow('north');
|
|
|
|
});
|
2013-04-26 23:08:13 +00:00
|
|
|
|
|
|
|
// ScrollLink
|
|
|
|
if(core.settings.scrollLink === true) {
|
|
|
|
$("#wmd-input, #wmd-preview").scroll(scrollLink);
|
|
|
|
}
|
2013-04-02 18:42:47 +00:00
|
|
|
};
|
2013-04-27 12:25:02 +00:00
|
|
|
core.layoutRefresh = function() {
|
|
|
|
if(layout !== undefined) {
|
|
|
|
// Use defer to make sure UI has been updated
|
|
|
|
_.defer(layout.resizeAll);
|
|
|
|
}
|
|
|
|
};
|
2013-04-26 23:08:13 +00:00
|
|
|
|
2013-04-02 18:42:47 +00:00
|
|
|
// Create the PageDown editor
|
2013-04-04 22:13:48 +00:00
|
|
|
var insertLinkCallback = undefined;
|
2013-04-02 18:42:47 +00:00
|
|
|
core.createEditor = function(onTextChange) {
|
2013-05-16 00:19:58 +00:00
|
|
|
var firstChange = true;
|
2013-05-13 23:10:02 +00:00
|
|
|
skipScrollLink = true;
|
|
|
|
lastPreviewScrollTop = -9;
|
|
|
|
$("#wmd-input, #wmd-preview").scrollTop(0);
|
2013-04-02 18:42:47 +00:00
|
|
|
$("#wmd-button-bar").empty();
|
2013-04-27 00:15:21 +00:00
|
|
|
var converter = new Markdown.Converter();
|
2013-04-15 16:19:47 +00:00
|
|
|
if(core.settings.converterType.indexOf("markdown-extra") === 0) {
|
2013-04-21 18:41:10 +00:00
|
|
|
// Markdown extra customized converter
|
2013-04-15 16:19:47 +00:00
|
|
|
var options = {};
|
|
|
|
if(core.settings.converterType == "markdown-extra-prettify") {
|
|
|
|
options.highlighter = "prettify";
|
|
|
|
}
|
|
|
|
Markdown.Extra.init(converter, options);
|
|
|
|
}
|
2013-04-30 23:02:19 +00:00
|
|
|
// Convert email addresses (not managed by pagedown)
|
|
|
|
converter.hooks.chain("postConversion", function(text) {
|
|
|
|
return text.replace(/<(mailto\:)?([^\s>]+@[^\s>]+\.\S+?)>/g, function(match, mailto, email) {
|
|
|
|
return '<a href="mailto:' + email + '">' + email + '</a>';
|
|
|
|
});
|
|
|
|
});
|
2013-04-02 18:42:47 +00:00
|
|
|
var editor = new Markdown.Editor(converter);
|
2013-05-12 00:48:25 +00:00
|
|
|
// Prettify
|
|
|
|
if(core.settings.converterType == "markdown-extra-prettify") {
|
|
|
|
editor.hooks.chain("onPreviewRefresh", prettyPrint);
|
|
|
|
}
|
2013-05-13 23:10:02 +00:00
|
|
|
var previewRefreshFinished = function() {
|
2013-05-12 23:59:17 +00:00
|
|
|
if(viewerMode === false && core.settings.scrollLink === true) {
|
2013-05-13 23:10:02 +00:00
|
|
|
function updateScrollLinkSections() {
|
|
|
|
// Modify scroll position of the preview not the editor
|
2013-04-27 23:16:38 +00:00
|
|
|
lastEditorScrollTop = -9;
|
|
|
|
buildSections();
|
2013-05-13 23:10:02 +00:00
|
|
|
// Preview may change if images are loading
|
|
|
|
$("#wmd-preview img").load(function() {
|
|
|
|
lastEditorScrollTop = -9;
|
|
|
|
buildSections();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
// MathJax may have change the scroll position. Restore it
|
|
|
|
$("#wmd-preview").scrollTop(lastPreviewScrollTop);
|
|
|
|
_.defer(updateScrollLinkSections);
|
2013-05-12 23:59:17 +00:00
|
|
|
}
|
2013-05-13 23:10:02 +00:00
|
|
|
};
|
2013-05-12 23:59:17 +00:00
|
|
|
// MathJax
|
|
|
|
if(core.settings.enableMathJax === true) {
|
2013-05-13 23:10:02 +00:00
|
|
|
mathjaxEditing.prepareWmdForMathJax(editor, [["$", "$"], ["\\\\(", "\\\\)"]], function() {
|
|
|
|
skipScrollLink = true;
|
|
|
|
}, previewRefreshFinished);
|
2013-05-12 23:59:17 +00:00
|
|
|
}
|
|
|
|
else {
|
2013-05-13 23:10:02 +00:00
|
|
|
editor.hooks.chain("onPreviewRefresh", previewRefreshFinished);
|
2013-04-26 23:08:13 +00:00
|
|
|
}
|
2013-04-21 18:41:10 +00:00
|
|
|
// Custom insert link dialog
|
2013-04-04 22:13:48 +00:00
|
|
|
editor.hooks.set("insertLinkDialog", function (callback) {
|
|
|
|
insertLinkCallback = callback;
|
2013-04-10 23:13:31 +00:00
|
|
|
core.resetModalInputs();
|
|
|
|
$("#modal-insert-link").modal();
|
2013-05-13 23:10:02 +00:00
|
|
|
_.defer(function() {
|
|
|
|
$("#input-insert-link").focus();
|
|
|
|
});
|
2013-04-04 22:13:48 +00:00
|
|
|
return true;
|
|
|
|
});
|
2013-04-21 18:41:10 +00:00
|
|
|
// Custom insert image dialog
|
2013-04-04 22:13:48 +00:00
|
|
|
editor.hooks.set("insertImageDialog", function (callback) {
|
|
|
|
insertLinkCallback = callback;
|
2013-04-10 23:13:31 +00:00
|
|
|
core.resetModalInputs();
|
|
|
|
$("#modal-insert-image").modal();
|
2013-05-13 23:10:02 +00:00
|
|
|
_.defer(function() {
|
|
|
|
$("#input-insert-image").focus();
|
|
|
|
});
|
2013-04-04 22:13:48 +00:00
|
|
|
return true;
|
|
|
|
});
|
|
|
|
|
2013-05-13 23:10:02 +00:00
|
|
|
var previewWrapper = function(makePreview) {
|
2013-05-16 00:19:58 +00:00
|
|
|
return function() {
|
|
|
|
if(firstChange !== true) {
|
|
|
|
onTextChange();
|
|
|
|
}
|
|
|
|
makePreview();
|
|
|
|
};
|
2013-05-13 23:10:02 +00:00
|
|
|
};
|
|
|
|
if(core.settings.lazyRendering === true) {
|
|
|
|
previewWrapper = function(makePreview) {
|
2013-05-14 23:05:02 +00:00
|
|
|
var debouncedMakePreview = _.debounce(makePreview, 500);
|
|
|
|
return function() {
|
|
|
|
if(firstChange === true) {
|
|
|
|
makePreview();
|
|
|
|
}
|
|
|
|
else {
|
2013-05-16 00:19:58 +00:00
|
|
|
onTextChange();
|
2013-05-14 23:05:02 +00:00
|
|
|
debouncedMakePreview();
|
|
|
|
}
|
|
|
|
};
|
2013-05-13 23:10:02 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
editor.run(previewWrapper);
|
2013-04-02 18:42:47 +00:00
|
|
|
firstChange = false;
|
|
|
|
|
2013-04-21 18:41:10 +00:00
|
|
|
// Hide default buttons
|
2013-04-02 18:42:47 +00:00
|
|
|
$(".wmd-button-row").addClass("btn-group").find("li:not(.wmd-spacer)")
|
|
|
|
.addClass("btn").css("left", 0).find("span").hide();
|
2013-04-21 18:41:10 +00:00
|
|
|
|
|
|
|
// Add customized buttons
|
2013-04-02 18:42:47 +00:00
|
|
|
$("#wmd-bold-button").append($("<i>").addClass("icon-bold"));
|
|
|
|
$("#wmd-italic-button").append($("<i>").addClass("icon-italic"));
|
|
|
|
$("#wmd-link-button").append($("<i>").addClass("icon-globe"));
|
|
|
|
$("#wmd-quote-button").append($("<i>").addClass("icon-indent-left"));
|
|
|
|
$("#wmd-code-button").append($("<i>").addClass("icon-code"));
|
|
|
|
$("#wmd-image-button").append($("<i>").addClass("icon-picture"));
|
|
|
|
$("#wmd-olist-button").append($("<i>").addClass("icon-numbered-list"));
|
|
|
|
$("#wmd-ulist-button").append($("<i>").addClass("icon-list"));
|
|
|
|
$("#wmd-heading-button").append($("<i>").addClass("icon-text-height"));
|
|
|
|
$("#wmd-hr-button").append($("<i>").addClass("icon-hr"));
|
|
|
|
$("#wmd-undo-button").append($("<i>").addClass("icon-undo"));
|
|
|
|
$("#wmd-redo-button").append($("<i>").addClass("icon-share-alt"));
|
|
|
|
};
|
|
|
|
|
|
|
|
// Base64 conversion
|
|
|
|
core.encodeBase64 = function(str) {
|
|
|
|
if (str.length === 0) {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
// UTF-8 to byte array
|
|
|
|
var bytes = [], offset = 0, length, char;
|
|
|
|
|
|
|
|
str = encodeURI(str);
|
|
|
|
length = str.length;
|
|
|
|
|
|
|
|
while (offset < length) {
|
|
|
|
char = str[offset];
|
|
|
|
offset += 1;
|
|
|
|
|
|
|
|
if ('%' !== char) {
|
|
|
|
bytes.push(char.charCodeAt(0));
|
|
|
|
} else {
|
|
|
|
char = str[offset] + str[offset + 1];
|
|
|
|
bytes.push(parseInt(char, 16));
|
|
|
|
offset += 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// byte array to base64
|
|
|
|
var padchar = '=';
|
|
|
|
var alpha = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
|
|
|
|
|
|
|
var i, b10;
|
|
|
|
var x = [];
|
|
|
|
|
|
|
|
var imax = bytes.length - bytes.length % 3;
|
|
|
|
|
|
|
|
for (i = 0; i < imax; i += 3) {
|
|
|
|
b10 = (bytes[i] << 16) | (bytes[i+1] << 8) | bytes[i+2];
|
|
|
|
x.push(alpha.charAt(b10 >> 18));
|
|
|
|
x.push(alpha.charAt((b10 >> 12) & 0x3F));
|
|
|
|
x.push(alpha.charAt((b10 >> 6) & 0x3f));
|
|
|
|
x.push(alpha.charAt(b10 & 0x3f));
|
|
|
|
}
|
|
|
|
switch (bytes.length - imax) {
|
|
|
|
case 1:
|
|
|
|
b10 = bytes[i] << 16;
|
|
|
|
x.push(alpha.charAt(b10 >> 18) + alpha.charAt((b10 >> 12) & 0x3F) +
|
|
|
|
padchar + padchar);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
b10 = (bytes[i] << 16) | (bytes[i+1] << 8);
|
|
|
|
x.push(alpha.charAt(b10 >> 18) + alpha.charAt((b10 >> 12) & 0x3F) +
|
|
|
|
alpha.charAt((b10 >> 6) & 0x3f) + padchar);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return x.join('');
|
|
|
|
};
|
|
|
|
|
2013-04-09 07:58:06 +00:00
|
|
|
// CRC32 algorithm
|
|
|
|
var mHash = [ 0, 1996959894, 3993919788, 2567524794, 124634137,
|
|
|
|
1886057615, 3915621685, 2657392035, 249268274, 2044508324,
|
|
|
|
3772115230, 2547177864, 162941995, 2125561021, 3887607047,
|
|
|
|
2428444049, 498536548, 1789927666, 4089016648, 2227061214,
|
|
|
|
450548861, 1843258603, 4107580753, 2211677639, 325883990,
|
|
|
|
1684777152, 4251122042, 2321926636, 335633487, 1661365465,
|
|
|
|
4195302755, 2366115317, 997073096, 1281953886, 3579855332,
|
|
|
|
2724688242, 1006888145, 1258607687, 3524101629, 2768942443,
|
|
|
|
901097722, 1119000684, 3686517206, 2898065728, 853044451,
|
|
|
|
1172266101, 3705015759, 2882616665, 651767980, 1373503546,
|
|
|
|
3369554304, 3218104598, 565507253, 1454621731, 3485111705,
|
|
|
|
3099436303, 671266974, 1594198024, 3322730930, 2970347812,
|
|
|
|
795835527, 1483230225, 3244367275, 3060149565, 1994146192,
|
|
|
|
31158534, 2563907772, 4023717930, 1907459465, 112637215,
|
|
|
|
2680153253, 3904427059, 2013776290, 251722036, 2517215374,
|
|
|
|
3775830040, 2137656763, 141376813, 2439277719, 3865271297,
|
|
|
|
1802195444, 476864866, 2238001368, 4066508878, 1812370925,
|
|
|
|
453092731, 2181625025, 4111451223, 1706088902, 314042704,
|
|
|
|
2344532202, 4240017532, 1658658271, 366619977, 2362670323,
|
|
|
|
4224994405, 1303535960, 984961486, 2747007092, 3569037538,
|
|
|
|
1256170817, 1037604311, 2765210733, 3554079995, 1131014506,
|
|
|
|
879679996, 2909243462, 3663771856, 1141124467, 855842277,
|
|
|
|
2852801631, 3708648649, 1342533948, 654459306, 3188396048,
|
|
|
|
3373015174, 1466479909, 544179635, 3110523913, 3462522015,
|
|
|
|
1591671054, 702138776, 2966460450, 3352799412, 1504918807,
|
|
|
|
783551873, 3082640443, 3233442989, 3988292384, 2596254646,
|
|
|
|
62317068, 1957810842, 3939845945, 2647816111, 81470997, 1943803523,
|
|
|
|
3814918930, 2489596804, 225274430, 2053790376, 3826175755,
|
|
|
|
2466906013, 167816743, 2097651377, 4027552580, 2265490386,
|
|
|
|
503444072, 1762050814, 4150417245, 2154129355, 426522225,
|
|
|
|
1852507879, 4275313526, 2312317920, 282753626, 1742555852,
|
|
|
|
4189708143, 2394877945, 397917763, 1622183637, 3604390888,
|
|
|
|
2714866558, 953729732, 1340076626, 3518719985, 2797360999,
|
|
|
|
1068828381, 1219638859, 3624741850, 2936675148, 906185462,
|
|
|
|
1090812512, 3747672003, 2825379669, 829329135, 1181335161,
|
|
|
|
3412177804, 3160834842, 628085408, 1382605366, 3423369109,
|
|
|
|
3138078467, 570562233, 1426400815, 3317316542, 2998733608,
|
|
|
|
733239954, 1555261956, 3268935591, 3050360625, 752459403,
|
|
|
|
1541320221, 2607071920, 3965973030, 1969922972, 40735498,
|
|
|
|
2617837225, 3943577151, 1913087877, 83908371, 2512341634,
|
|
|
|
3803740692, 2075208622, 213261112, 2463272603, 3855990285,
|
|
|
|
2094854071, 198958881, 2262029012, 4057260610, 1759359992,
|
|
|
|
534414190, 2176718541, 4139329115, 1873836001, 414664567,
|
|
|
|
2282248934, 4279200368, 1711684554, 285281116, 2405801727,
|
|
|
|
4167216745, 1634467795, 376229701, 2685067896, 3608007406,
|
|
|
|
1308918612, 956543938, 2808555105, 3495958263, 1231636301,
|
|
|
|
1047427035, 2932959818, 3654703836, 1088359270, 936918000,
|
|
|
|
2847714899, 3736837829, 1202900863, 817233897, 3183342108,
|
|
|
|
3401237130, 1404277552, 615818150, 3134207493, 3453421203,
|
|
|
|
1423857449, 601450431, 3009837614, 3294710456, 1567103746,
|
|
|
|
711928724, 3020668471, 3272380065, 1510334235, 755167117 ];
|
|
|
|
core.crc32 = function(str) {
|
|
|
|
var n = 0, crc = -1;
|
|
|
|
for ( var i = 0; i < str.length; i++) {
|
|
|
|
n = (crc ^ str.charCodeAt(i)) & 0xFF;
|
|
|
|
crc = (crc >>> 8) ^ mHash[n];
|
|
|
|
}
|
|
|
|
crc = crc ^ (-1);
|
|
|
|
if (crc < 0) {
|
|
|
|
crc = 0xFFFFFFFF + crc + 1;
|
|
|
|
}
|
|
|
|
return crc.toString(16);
|
|
|
|
};
|
|
|
|
|
2013-04-11 22:38:41 +00:00
|
|
|
// Generates a random string
|
|
|
|
core.randomString = function() {
|
2013-04-13 18:11:54 +00:00
|
|
|
return _.random(4294967296).toString(36);
|
2013-04-11 22:38:41 +00:00
|
|
|
};
|
2013-05-04 00:05:58 +00:00
|
|
|
|
|
|
|
// Access a URL parameter
|
|
|
|
core.getURLParameter = function(name) {
|
|
|
|
var regex = new RegExp(name + "=(.+?)(&|$)");
|
|
|
|
try {
|
|
|
|
return decodeURIComponent(regex.exec(location.search)[1]);
|
|
|
|
} catch (e) {
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-04-11 22:38:41 +00:00
|
|
|
// Create an centered popup window
|
2013-04-10 23:13:31 +00:00
|
|
|
core.popupWindow = function(url, title, w, h) {
|
|
|
|
var left = (screen.width / 2) - (w / 2);
|
|
|
|
var top = (screen.height / 2) - (h / 2);
|
|
|
|
return window
|
|
|
|
.open(
|
|
|
|
url,
|
|
|
|
title,
|
|
|
|
'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=no, copyhistory=no, width='
|
|
|
|
+ w
|
|
|
|
+ ', height='
|
|
|
|
+ h
|
|
|
|
+ ', top='
|
|
|
|
+ top
|
|
|
|
+ ', left='
|
|
|
|
+ left);
|
|
|
|
};
|
2013-04-11 22:38:41 +00:00
|
|
|
|
2013-04-22 01:04:12 +00:00
|
|
|
// Keep a reference to the fileManager
|
|
|
|
core.setFileManager = function(fileManager) {
|
|
|
|
core.fileManager = fileManager;
|
|
|
|
runReadyCallbacks();
|
|
|
|
};
|
|
|
|
|
|
|
|
// onReady event callbacks
|
|
|
|
var readyCallbacks = [];
|
|
|
|
core.onReady = function(callback) {
|
|
|
|
readyCallbacks.push(callback);
|
|
|
|
runReadyCallbacks();
|
|
|
|
};
|
|
|
|
var documentLoaded = false;
|
|
|
|
function runReadyCallbacks() {
|
|
|
|
if(documentLoaded === true && core.fileManager !== undefined) {
|
|
|
|
_.each(readyCallbacks, function(callback) {
|
|
|
|
callback();
|
|
|
|
});
|
|
|
|
readyCallbacks = [];
|
|
|
|
}
|
|
|
|
}
|
2013-04-21 00:07:27 +00:00
|
|
|
$(function() {
|
2013-04-22 01:04:12 +00:00
|
|
|
documentLoaded = true;
|
|
|
|
runReadyCallbacks();
|
|
|
|
});
|
2013-04-21 18:41:10 +00:00
|
|
|
|
2013-04-22 01:04:12 +00:00
|
|
|
core.onReady(function() {
|
2013-04-02 18:42:47 +00:00
|
|
|
// jGrowl configuration
|
|
|
|
$.jGrowl.defaults.life = 5000;
|
|
|
|
$.jGrowl.defaults.closer = false;
|
|
|
|
$.jGrowl.defaults.closeTemplate = '';
|
|
|
|
$.jGrowl.defaults.position = 'bottom-right';
|
|
|
|
|
|
|
|
// listen to online/offline events
|
|
|
|
$(window).on('offline', core.setOffline);
|
|
|
|
$(window).on('online', core.setOnline);
|
|
|
|
if (navigator.onLine === false) {
|
|
|
|
core.setOffline();
|
|
|
|
}
|
|
|
|
|
2013-04-10 18:14:59 +00:00
|
|
|
// Detect user activity
|
|
|
|
$(document).mousemove(setUserActive).keypress(setUserActive);
|
|
|
|
|
2013-04-02 18:42:47 +00:00
|
|
|
// Avoid dropdown to close when clicking on submenu
|
2013-04-21 18:41:10 +00:00
|
|
|
$(".dropdown-submenu > a").click(function(e) {
|
2013-04-02 18:42:47 +00:00
|
|
|
e.stopPropagation();
|
|
|
|
});
|
|
|
|
|
2013-04-04 22:13:48 +00:00
|
|
|
// Click events on "insert link" and "insert image" dialog buttons
|
|
|
|
$(".action-insert-link").click(function(e) {
|
|
|
|
var value = core.getInputValue($("#input-insert-link"), e);
|
|
|
|
if(value !== undefined) {
|
|
|
|
insertLinkCallback(value);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
$(".action-insert-image").click(function(e) {
|
|
|
|
var value = core.getInputValue($("#input-insert-image"), e);
|
|
|
|
if(value !== undefined) {
|
|
|
|
insertLinkCallback(value);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
$(".action-close-insert-link").click(function(e) {
|
|
|
|
insertLinkCallback(null);
|
|
|
|
});
|
2013-04-21 18:41:10 +00:00
|
|
|
|
|
|
|
// Settings loading/saving
|
|
|
|
core.loadSettings();
|
|
|
|
$(".action-load-settings").click(function() {
|
|
|
|
core.loadSettings();
|
|
|
|
});
|
|
|
|
|
|
|
|
$(".action-apply-settings").click(function(e) {
|
|
|
|
core.saveSettings(e);
|
|
|
|
if(!e.isPropagationStopped()) {
|
|
|
|
window.location.reload();
|
|
|
|
}
|
|
|
|
});
|
2013-04-04 22:13:48 +00:00
|
|
|
|
2013-04-28 01:13:17 +00:00
|
|
|
$(".action-default-settings").click(function() {
|
|
|
|
localStorage.removeItem("settings");
|
|
|
|
window.location.reload();
|
|
|
|
});
|
|
|
|
|
|
|
|
$(".action-app-reset").click(function() {
|
|
|
|
localStorage.clear();
|
|
|
|
window.location.reload();
|
|
|
|
});
|
|
|
|
|
2013-04-21 18:41:10 +00:00
|
|
|
// UI layout
|
2013-04-02 18:42:47 +00:00
|
|
|
$("#menu-bar, .ui-layout-center, .ui-layout-east, .ui-layout-south").removeClass("hide");
|
2013-04-11 22:38:41 +00:00
|
|
|
core.createLayout();
|
2013-04-21 18:41:10 +00:00
|
|
|
|
|
|
|
// Editor's textarea
|
2013-04-26 23:08:13 +00:00
|
|
|
$("#wmd-input, #md-section-helper").css({
|
2013-04-21 18:41:10 +00:00
|
|
|
// Apply editor font size
|
2013-04-11 22:38:41 +00:00
|
|
|
"font-size": core.settings.editorFontSize + "px",
|
|
|
|
"line-height": Math.round(core.settings.editorFontSize * (20/14)) + "px"
|
2013-04-26 23:08:13 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
// Manage tab key
|
|
|
|
$("#wmd-input").keydown(function(e) {
|
2013-04-21 16:27:52 +00:00
|
|
|
if(e.keyCode === 9) {
|
|
|
|
var value = $(this).val();
|
|
|
|
var start = this.selectionStart;
|
|
|
|
var end = this.selectionEnd;
|
|
|
|
// IE8 does not support selection attributes
|
|
|
|
if(start === undefined || end === undefined) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
$(this).val(value.substring(0, start) + "\t" + value.substring(end));
|
|
|
|
this.selectionStart = this.selectionEnd = start + 1;
|
|
|
|
e.preventDefault();
|
|
|
|
}
|
2013-04-10 23:13:31 +00:00
|
|
|
});
|
2013-04-02 18:42:47 +00:00
|
|
|
|
2013-04-26 23:08:13 +00:00
|
|
|
// Tooltips
|
|
|
|
$(".tooltip-scroll-link").tooltip({
|
|
|
|
html: true,
|
|
|
|
container: '#modal-settings',
|
|
|
|
placement: 'right',
|
|
|
|
title: ['Scroll Link is a feature that binds together editor and preview scrollbars. ',
|
|
|
|
'It allows you to keep an eye on the preview while scrolling the editor and vice versa. ',
|
|
|
|
'<br><br>',
|
|
|
|
'The mapping between Markdown and HTML is based on the position of the title elements (h1, h2, ...) in the page. ',
|
|
|
|
'Therefore, if your document does not contain any title, the mapping will be linear and consequently less efficient.',
|
|
|
|
].join("")
|
|
|
|
});
|
2013-05-13 23:10:02 +00:00
|
|
|
$(".tooltip-lazy-rendering").tooltip({
|
|
|
|
container: '#modal-settings',
|
|
|
|
placement: 'right',
|
|
|
|
title: 'Disable preview rendering while typing in order to offload CPU. Refresh preview after 500 ms of inactivity.'
|
|
|
|
});
|
2013-04-29 21:41:10 +00:00
|
|
|
$(".tooltip-default-content").tooltip({
|
|
|
|
html: true,
|
|
|
|
container: '#modal-settings',
|
|
|
|
placement: 'right',
|
|
|
|
title: 'Thanks for supporting StackEdit by adding a backlink in your documents!'
|
|
|
|
});
|
2013-04-26 23:08:13 +00:00
|
|
|
$(".tooltip-template").tooltip({
|
|
|
|
html: true,
|
|
|
|
container: '#modal-settings',
|
|
|
|
placement: 'right',
|
|
|
|
trigger: 'manual',
|
|
|
|
title: ['Available variables:<br>',
|
|
|
|
'<ul><li><b>documentTitle</b>: document title</li>',
|
|
|
|
'<li><b>documentMarkdown</b>: document in Markdown format</li>',
|
|
|
|
'<li><b>documentHTML</b>: document in HTML format</li>',
|
|
|
|
'<li><b>publishAttributes</b>: attributes of the publish location (undefined when using "Save")</li></ul>',
|
|
|
|
'Examples:<br>',
|
|
|
|
_.escape('<title><%= documentTitle %></title>'),
|
|
|
|
'<br>',
|
|
|
|
_.escape('<div><%- documentHTML %></div>'),
|
|
|
|
'<br>',
|
|
|
|
_.escape('<% if(publishAttributes.provider == "github") print(documentMarkdown); %>'),
|
|
|
|
'<br><br><a target="_blank" href="http://underscorejs.org/#template">More info</a>',
|
|
|
|
].join("")
|
|
|
|
}).click(function(e) {
|
|
|
|
$(this).tooltip('show');
|
|
|
|
e.stopPropagation();
|
|
|
|
});
|
|
|
|
|
|
|
|
$(document).click(function(e) {
|
|
|
|
$(".tooltip-template").tooltip('hide');
|
|
|
|
});
|
|
|
|
|
2013-04-21 18:41:10 +00:00
|
|
|
// Reset inputs
|
2013-04-10 23:13:31 +00:00
|
|
|
$(".action-reset-input").click(function() {
|
|
|
|
core.resetModalInputs();
|
2013-04-02 18:42:47 +00:00
|
|
|
});
|
2013-04-10 18:14:59 +00:00
|
|
|
|
|
|
|
// Do periodic tasks
|
2013-04-11 22:38:41 +00:00
|
|
|
intervalId = window.setInterval(function() {
|
2013-04-10 18:14:59 +00:00
|
|
|
updateCurrentTime();
|
|
|
|
core.checkWindowUnique();
|
2013-05-04 00:05:58 +00:00
|
|
|
if(isUserActive() === true || viewerMode === true) {
|
2013-04-21 00:07:27 +00:00
|
|
|
_.each(periodicCallbacks, function(callback) {
|
|
|
|
callback();
|
|
|
|
});
|
|
|
|
checkOnline();
|
2013-04-10 18:14:59 +00:00
|
|
|
}
|
|
|
|
}, 1000);
|
2013-04-21 00:07:27 +00:00
|
|
|
});
|
2013-04-02 18:42:47 +00:00
|
|
|
|
|
|
|
return core;
|
|
|
|
});
|
|
|
|
|