364 lines
14 KiB
JavaScript
364 lines
14 KiB
JavaScript
new function($) {
|
|
$.fn.setCursorPosition = function(pos) {
|
|
if ($(this).get(0).setSelectionRange) {
|
|
$(this).get(0).setSelectionRange(pos, pos);
|
|
} else if ($(this).get(0).createTextRange) {
|
|
var range = $(this).get(0).createTextRange();
|
|
range.collapse(true);
|
|
range.moveEnd('character', pos);
|
|
range.moveStart('character', pos);
|
|
range.select();
|
|
}
|
|
$(this).focus();
|
|
}
|
|
$.fn.tabHandler = function() {
|
|
$(this).keydown(function(e) {
|
|
if(e.keyCode === 9) { // tab was pressed
|
|
// get caret position/selection
|
|
var start = this.selectionStart;
|
|
var end = this.selectionEnd;
|
|
|
|
var $this = $(this);
|
|
var value = $this.val();
|
|
|
|
// set textarea value to: text before caret + four spaces + text after caret
|
|
$this.val(value.substring(0, start)
|
|
+ " "
|
|
+ value.substring(end));
|
|
|
|
// put caret at right position again (add four for the spaces)
|
|
this.selectionStart = this.selectionEnd = start + 4;
|
|
|
|
// prevent the focus lose
|
|
e.preventDefault();
|
|
}
|
|
});
|
|
}
|
|
}(jQuery);
|
|
|
|
// full screen api
|
|
/*
|
|
(function() {
|
|
var
|
|
fullScreenApi = {
|
|
supportsFullScreen: false,
|
|
isFullScreen: function() { return false; },
|
|
requestFullScreen: function() {},
|
|
cancelFullScreen: function() {},
|
|
fullScreenEventName: '',
|
|
prefix: ''
|
|
},
|
|
browserPrefixes = 'webkit moz o ms khtml'.split(' ');
|
|
|
|
// check for native support
|
|
if (typeof document.cancelFullScreen != 'undefined') {
|
|
fullScreenApi.supportsFullScreen = true;
|
|
} else {
|
|
// check for fullscreen support by vendor prefix
|
|
for (var i = 0, il = browserPrefixes.length; i < il; i++ ) {
|
|
fullScreenApi.prefix = browserPrefixes[i];
|
|
|
|
if (typeof document[fullScreenApi.prefix + 'CancelFullScreen' ] != 'undefined' ) {
|
|
fullScreenApi.supportsFullScreen = true;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// update methods to do something useful
|
|
if (fullScreenApi.supportsFullScreen) {
|
|
fullScreenApi.fullScreenEventName = fullScreenApi.prefix + 'fullscreenchange';
|
|
|
|
fullScreenApi.isFullScreen = function() {
|
|
switch (this.prefix) {
|
|
case '':
|
|
return document.fullScreen;
|
|
case 'webkit':
|
|
return document.webkitIsFullScreen;
|
|
default:
|
|
return document[this.prefix + 'FullScreen'];
|
|
}
|
|
}
|
|
fullScreenApi.requestFullScreen = function(el) {
|
|
return (this.prefix === '') ? el.requestFullScreen() : el[this.prefix + 'RequestFullScreen']();
|
|
}
|
|
fullScreenApi.cancelFullScreen = function(el) {
|
|
return (this.prefix === '') ? document.cancelFullScreen() : document[this.prefix + 'CancelFullScreen']();
|
|
}
|
|
}
|
|
|
|
// jQuery plugin
|
|
if (typeof jQuery != 'undefined') {
|
|
jQuery.fn.requestFullScreen = function() {
|
|
|
|
return this.each(function() {
|
|
if (fullScreenApi.supportsFullScreen) {
|
|
fullScreenApi.requestFullScreen(this);
|
|
}
|
|
});
|
|
};
|
|
}
|
|
// export api
|
|
window.fullScreenApi = fullScreenApi;
|
|
})();
|
|
|
|
*/
|
|
|
|
(function () {
|
|
// handle Tab keystroke
|
|
$('#wmd-input').tabHandler();
|
|
|
|
var converter1 = Markdown.getSanitizingConverter();
|
|
Converter = converter1;
|
|
|
|
// tell the converter to use Markdown Extra for tables, fenced_code_gfm, def_list
|
|
Markdown.Extra.init(converter1, {extensions: ["tables", "fenced_code_gfm", "def_list"], highlighter: "prettify"});
|
|
|
|
// To handle LaTeX expressions, to avoid the expression fail to work because of markdown syntax. inspired by stackeditor
|
|
// This will handle $$LaTeX expression$$ only, so that $LaTeX expression$ could fail to handle either.
|
|
bindMathJaxHooks(converter1);
|
|
|
|
// 弹框显示markdown语法
|
|
var markdownHelp = function () {
|
|
window.open("http://www.leanote.com/blog/view/531b263bdfeb2c0ea9000002");
|
|
return;
|
|
}
|
|
var options = {
|
|
helpButton: { handler: markdownHelp },
|
|
strings: Markdown.local.zh
|
|
};
|
|
|
|
var editor1 = new Markdown.Editor(converter1, null, options);
|
|
MarkdownEditor = editor1;
|
|
|
|
var scrollLink = getScrollLink();
|
|
ScrollLink = scrollLink;
|
|
scrollLink.onLayoutCreated();
|
|
|
|
editor1.hooks.chain("onPreviewRefresh", function () {
|
|
$("#left-column pre").addClass("prettyprint linenums");
|
|
prettyPrint();
|
|
|
|
// Call onPreviewFinished callbacks when all async preview are finished, make sure sync actions have been ABOVE the line below.
|
|
var counter = 0;
|
|
var nbAsyncPreviewCallback = 2; // 1 for waitForImages below and 1 for MathJax below, they are both time consuming task, if only they are both done, begin to caculate md section and scroll bar.
|
|
function tryFinished() {
|
|
if(++counter === nbAsyncPreviewCallback) {
|
|
scrollLink.onPreviewFinished();
|
|
}
|
|
}
|
|
// We assume images are loading in the preview
|
|
$("#wmd-preview").waitForImages(tryFinished);
|
|
// TODO: could we cache the result to speed up ? This action is slow, especially, when there are multiple LaTeX expression on the page, google solution.
|
|
if(typeof MathJax != "undefined") {
|
|
MathJax.Hub.Queue(["Typeset",MathJax.Hub,"wmd-preview"]);
|
|
MathJax.Hub.Queue(tryFinished);
|
|
} else {
|
|
scrollLink.onPreviewFinished();
|
|
}
|
|
});
|
|
scrollLink.onEditorConfigure(editor1);
|
|
|
|
function popupEditorDialog(title, body, imageClass, placeholder) {
|
|
$('#editorDialog').find('.modal-body input').val("");
|
|
$('#editorDialog').find('.modal-body input').attr("placeholder", placeholder);
|
|
$('#editorDialog').find('#editorDialog-title').text(title);
|
|
$('#editorDialog').find('.modal-body p').text(body);
|
|
$('#editorDialog').find('.modal-body i').removeClass().addClass(imageClass);
|
|
$('#editorDialog').modal({keyboard : true});
|
|
}
|
|
|
|
// Custom insert link dialog
|
|
editor1.hooks.set("insertLinkDialog", function(callback) {
|
|
popupEditorDialog('链接', '请输入链接地址', 'fa fa-link', 'http://example.com/ "可选标题"');
|
|
editorDialogCallback = callback;
|
|
return true; // tell the editor that we'll take care of getting the link url
|
|
});
|
|
|
|
// Custom insert image dialog
|
|
var editorDialogCallback = null;
|
|
editor1.hooks.set("insertImageDialog", function(callback) {
|
|
popupEditorDialog('图片', '请输入图片地址', 'fa fa-picture-o', 'http://example.com/images/diagram.jpg "可选标题"');
|
|
editorDialogCallback = callback;
|
|
return true; // tell the editor that we'll take care of getting the image url
|
|
});
|
|
|
|
$('#editorDialog').on('hidden.bs.modal', function(){
|
|
if (editorDialogCallback) {
|
|
var url = $('#editorDialog-confirm').data('url');
|
|
if (url) {
|
|
$('#editorDialog-confirm').removeData('url');
|
|
editorDialogCallback(url);
|
|
} else {
|
|
editorDialogCallback(null);
|
|
}
|
|
}
|
|
});
|
|
|
|
$('#editorDialog-confirm').click(function(event) {
|
|
var url = $('#editorDialog').find('.modal-body input').val();
|
|
if (url) {
|
|
$(this).data('url', url);
|
|
}
|
|
$('#editorDialog').modal('hide');
|
|
});
|
|
|
|
$('#editorDialog').on('shown.bs.modal', function(){
|
|
$('#editorDialog').find('.modal-body input').focus();
|
|
});
|
|
|
|
|
|
// Make preview if it's inactive in 500ms to reduce the calls in onPreviewRefresh chains above and cpu cost.
|
|
documentContent = undefined;
|
|
var previewWrapper;
|
|
previewWrapper = function(makePreview) {
|
|
var debouncedMakePreview = _.debounce(makePreview, 500);
|
|
return function() {
|
|
if(documentContent === undefined) {
|
|
makePreview();
|
|
documentContent = '';
|
|
} else {
|
|
debouncedMakePreview();
|
|
}
|
|
};
|
|
};
|
|
|
|
$(window).resize(function() {
|
|
scrollLink.buildSections();
|
|
});
|
|
|
|
// 渲染编辑器
|
|
mainHandler();
|
|
|
|
function mainHandler(data) {
|
|
var article = null;
|
|
var cursorPosition = 0;
|
|
|
|
// start editor.
|
|
editor1.run(previewWrapper);
|
|
|
|
// Load awesome font to button
|
|
$('#wmd-bold-button > span').addClass('fa fa-bold');
|
|
$('#wmd-italic-button > span').addClass('fa fa-italic');
|
|
$('#wmd-link-button > span').addClass('fa fa-link');
|
|
$('#wmd-quote-button > span').addClass('fa fa-quote-left');
|
|
$('#wmd-code-button > span').addClass('fa fa-code');
|
|
$('#wmd-image-button > span').addClass('fa fa-picture-o');
|
|
$('#wmd-olist-button > span').addClass('fa fa-list-ol');
|
|
$('#wmd-ulist-button > span').addClass('fa fa-list-ul');
|
|
$('#wmd-heading-button > span').addClass('fa fa-list-alt');
|
|
$('#wmd-hr-button > span').addClass('fa fa-minus');
|
|
$('#wmd-undo-button > span').addClass('fa fa-undo');
|
|
$('#wmd-redo-button > span').addClass('fa fa-repeat');
|
|
|
|
$('#wmd-help-button > span').addClass('fa fa-question-circle');
|
|
|
|
function buttonBinding(rowClassName, spanClassName) {
|
|
// change color when hovering.
|
|
$(rowClassName).hover(function() {
|
|
$(spanClassName).animate({color: '#F9F9F5'}, 400);
|
|
},
|
|
function() {
|
|
$(spanClassName).animate({color: '#BBBBBB'}, 400);
|
|
});
|
|
|
|
// enlarge the icon when hovering.
|
|
$(spanClassName).hover(function() {
|
|
$(this).addClass('icon-large');
|
|
},
|
|
function() {
|
|
$(this).removeClass('icon-large');
|
|
});
|
|
}
|
|
buttonBinding('.wmd-button-row', '.wmd-button > span');
|
|
buttonBinding('.preview-button-row', '.preview-button > span');
|
|
|
|
function getCurrentMode() {
|
|
var currentMode = {isFullEditor: false, isFullReader: false, isEditorReader: false};
|
|
return currentMode;
|
|
}
|
|
|
|
/* ============================= Handle customized shortcut key binding. ========================================= */
|
|
browserType = {
|
|
isIE: /msie/.test(window.navigator.userAgent.toLowerCase()),
|
|
isIE_5or6: /msie 6/.test(window.navigator.userAgent.toLowerCase()) || /msie 5/.test(window.navigator.userAgent.toLowerCase()),
|
|
isOpera: /opera/.test(window.navigator.userAgent.toLowerCase()),
|
|
isFirefox: /firefox/.test(window.navigator.userAgent.toLowerCase()),
|
|
isChrome: /(chrome|chromium)/.test(window.navigator.userAgent.toLowerCase())
|
|
};
|
|
|
|
var keyEvent = 'keydown';
|
|
if (browserType.isOpera || browserType.isFirefox) {
|
|
keyEvent = 'keypress';
|
|
}
|
|
|
|
$(document).on(keyEvent, function(key) {
|
|
// Check to see if we have a button key and, if so execute the callback.
|
|
if ((key.ctrlKey || key.metaKey) && !key.shiftKey) {
|
|
|
|
var currentMode = getCurrentMode();
|
|
|
|
var keyCode = key.charCode || key.keyCode;
|
|
var keyCodeStr = String.fromCharCode(keyCode).toLowerCase();
|
|
|
|
switch (keyCodeStr) {
|
|
/*
|
|
case "m":
|
|
if (!key.altKey) { // 'ctrl + m' for switching normal/full editor
|
|
if (currentMode.isEditorReader) {
|
|
switchFullEditorMode();
|
|
} else if (currentMode.isFullEditor) {
|
|
switchNormalModeFromFullEditorMode();
|
|
}
|
|
} else { // 'ctrl + alt + m' for switching normal/full reader
|
|
if (currentMode.isEditorReader) {
|
|
switchFullReaderMode();
|
|
} else if (currentMode.isFullReader) {
|
|
switchNormalModeFromFullReaderMode();
|
|
}
|
|
}
|
|
break;
|
|
case "j":
|
|
if (key.altKey) { // 'ctrl + alt + j' for switching site theme.
|
|
switchSiteTheme();
|
|
break;
|
|
}
|
|
case "h":
|
|
if (key.altKey) { // 'ctrl + alt + h' for markdown help.
|
|
markdownHelp();
|
|
break;
|
|
}
|
|
case "n":
|
|
if (key.altKey) { // 'ctrl + alt + n' for markdown help.
|
|
clearAndNewFile();
|
|
break;
|
|
}
|
|
*/
|
|
default:
|
|
return;
|
|
}
|
|
|
|
if (key.preventDefault) {
|
|
key.preventDefault();
|
|
}
|
|
|
|
if (window.event) {
|
|
window.event.returnValue = false;
|
|
}
|
|
}
|
|
});
|
|
|
|
// Switch mode if there is.
|
|
var currentMode = getCurrentMode();
|
|
if (currentMode.isFullEditor) {
|
|
$('#wmd-input').setCursorPosition(cursorPosition);
|
|
switchFullEditorMode();
|
|
} else if (currentMode.isFullReader) { // Don't set focus on '#wmd-input', otherwise, when first time press pagedown key on full reader page, Firefox can't scroll.
|
|
switchFullReaderMode();
|
|
} else { // normal mode
|
|
$('#wmd-input').setCursorPosition(cursorPosition);
|
|
}
|
|
} // mainHander
|
|
})();
|