New pre editor

This commit is contained in:
benweet 2014-03-16 02:13:42 +00:00
parent 296f24eaa5
commit 5584980c58
15 changed files with 1218 additions and 30 deletions

View File

@ -0,0 +1,418 @@
/* jshint -W084, -W099 */
define([
'jquery',
'eventMgr',
'prism-core',
'libs/prism-markdown'
], function ($, eventMgr, Prism) {
var undoManager;
eventMgr.addListener('onPagedownConfigure', function (pagedownEditor) {
// Undo manager does exist at the moment
setTimeout(function () {
undoManager = pagedownEditor.undoManager;
}, 0);
});
String.prototype.splice = function (i, remove, add) {
remove = +remove || 0;
add = add || '';
return this.slice(0, i) + add + this.slice(i + remove);
};
function PreEditor(preElt) {
var preEditor = this;
preEditor.selectionStart = 0;
preEditor.selectionEnd = 0;
preEditor.scrollTop = 0;
preEditor.$preContentElt = $('<div contenteditable class="pre-content language-md">');
preElt.appendChild(preEditor.$preContentElt[0]);
preEditor.highlight = function () {
setTimeout(function () {
preEditor.selectionStart = preElt.selectionStart;
preEditor.selectionEnd = preElt.selectionEnd;
var startDate = Date.now();
Prism.highlightElement(preEditor.$preContentElt[0], false, function () {
console.log(Date.now() - startDate);
preElt.setSelectionRange(preEditor.selectionStart, preEditor.selectionEnd);
});
}, 0);
};
preElt.focus = function () {
preEditor.$preContentElt.focus();
this.setSelectionRange(preEditor.selectionStart, preEditor.selectionEnd);
preElt.scrollTop = preEditor.scrollTop;
};
preEditor.$preContentElt.focus(function () {
preElt.focused = true;
});
preEditor.$preContentElt.blur(function () {
preElt.focused = false;
});
Object.defineProperty(preElt, 'value', {
get: function () {
return this.textContent;
},
set: function (value) {
//return preEditor.$preContentElt.text(value);
var currentValue = this.textContent;
// Find the first modified char
var startIndex = 0;
var startIndexMax = Math.min(currentValue.length, value.length);
while (startIndex < startIndexMax) {
if (currentValue.charCodeAt(startIndex) !== value.charCodeAt(startIndex)) {
break;
}
startIndex++;
}
if (startIndex === startIndexMax) {
return preEditor.$preContentElt.text(value);
}
// Find the last modified char
var endIndex = 1;
var endIndexMax = Math.min(currentValue.length - startIndex, value.length - startIndex);
while (endIndex <= endIndexMax) {
if (currentValue.charCodeAt(currentValue.length - endIndex) !== value.charCodeAt(value.length - endIndex)) {
break;
}
endIndex++;
}
var replacementText = value.substring(startIndex, value.length - endIndex + 1);
endIndex = currentValue.length - endIndex + 1;
var range = createRange(preElt, startIndex, endIndex);
range.deleteContents();
range.insertNode(document.createTextNode(replacementText));
}
});
Object.defineProperty(preElt, 'selectionStart', {
get: function () {
var selection = window.getSelection();
if (selection.rangeCount) {
var range = selection.getRangeAt(0),
element = range.startContainer,
container = element,
offset = range.startOffset;
if (!(this.compareDocumentPosition(element) & 0x10)) {
return 0;
}
do {
while (element = element.previousSibling) {
if (element.textContent) {
offset += element.textContent.length;
}
}
element = container = container.parentNode;
} while (element && element != this);
return offset;
} else {
return 0;
}
},
set: function (value) {
preElt.setSelectionRange(value, preEditor.selectionEnd);
},
enumerable: true,
configurable: true
});
Object.defineProperty(preElt, 'selectionEnd', {
get: function () {
var selection = window.getSelection();
if (selection.rangeCount) {
return this.selectionStart + (selection.getRangeAt(0) + '').length;
} else {
return 0;
}
},
set: function (value) {
preElt.setSelectionRange(preEditor.selectionStart, value);
},
enumerable: true,
configurable: true
});
function findOffset(root, ss) {
if (!root) {
return null;
}
var offset = 0,
element = root,
container;
do {
container = element;
element = element.firstChild;
if (element) {
do {
var len = element.textContent.length;
if (offset <= ss && offset + len > ss) {
break;
}
offset += len;
} while (element = element.nextSibling);
}
if (!element) {
// It's the container's lastChild
break;
}
} while (element && element.hasChildNodes() && element.nodeType != 3);
if (element) {
return {
element: element,
offset: ss - offset
};
} else if (container) {
element = container;
while (element && element.lastChild) {
element = element.lastChild;
}
if (element.nodeType === 3) {
return {
element: element,
offset: element.textContent.length
};
} else {
return {
element: element,
offset: 0
};
}
}
return {
element: root,
offset: 0,
error: true
};
}
function createRange(root, ss, se) {
var range = document.createRange(),
offset = findOffset(root, ss);
range.setStart(offset.element, offset.offset);
if (se && se != ss) {
offset = findOffset(root, se);
}
range.setEnd(offset.element, offset.offset);
return range;
}
preElt.setSelectionRange = function (ss, se) {
preEditor.selectionStart = ss;
preEditor.selectionEnd = se;
var range = createRange(this, ss, se);
var selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
};
var action = function (action, options) {
options = options || {};
var text = preElt.value,
ss = options.start || preEditor.selectionStart,
se = options.end || preEditor.selectionEnd,
state = {
ss: ss,
se: se,
before: text.slice(0, ss),
after: text.slice(se),
selection: text.slice(ss, se)
};
actions[action](state, options);
preElt.value = state.before + state.selection + state.after;
preElt.setSelectionRange(state.ss, state.se);
preElt.dispatchEvent(new window.Event('input'));
};
var actions = {
indent: function (state, options) {
var lf = state.before.lastIndexOf('\n') + 1;
undoManager && undoManager.setMode("typing");
if (options.inverse) {
if (/\s/.test(state.before.charAt(lf))) {
state.before = state.before.splice(lf, 1);
state.ss--;
state.se--;
}
state.selection = state.selection.replace(/^[ \t]/gm, '');
} else if (state.selection) {
state.before = state.before.splice(lf, 0, '\t');
state.selection = state.selection.replace(/\r?\n(?=[\s\S])/g, '\n\t');
state.ss++;
state.se++;
} else {
state.before += '\t';
state.ss++;
state.se++;
return;
}
state.se = state.ss + state.selection.length;
},
newline: function (state) {
var lf = state.before.lastIndexOf('\n') + 1;
var indent = (state.before.slice(lf).match(/^\s+/) || [''])[0];
undoManager && undoManager.setMode("newlines");
state.before += '\n' + indent;
state.selection = '';
state.ss += indent.length + 1;
state.se = state.ss;
},
comment: function (state) {
var textAction;
var open = '<!--',
close = '-->';
var start = state.before.lastIndexOf(open),
end = state.after.indexOf(close),
closeBefore = state.before.lastIndexOf(close),
openAfter = state.after.indexOf(start);
undoManager && undoManager.setMode("typing");
if (start > -1 && end > -1 && (start > closeBefore || closeBefore === -1) && (end < openAfter || openAfter === -1)) {
// Uncomment
state.before = state.before.splice(start, open.length);
state.after = state.after.splice(end, close.length);
textAction = [{
add: '',
del: open,
start: start
}, {
add: '',
del: close,
start: state.before.length + state.selection.length + end
}];
state.ss -= open.length;
state.se -= open.length;
return textAction;
} else {
// Comment
if (state.selection) {
// Comment selection
state.selection = open + state.selection + close;
textAction = [{
add: open,
del: '',
start: state.ss
}, {
add: close,
del: '',
start: open.length + state.se
}];
} else {
// Comment whole line
start = state.before.lastIndexOf('\n') + 1;
end = state.after.indexOf('\n');
if (end === -1) {
end = state.after.length;
}
while (/\s/.test(state.before.charAt(start))) {
start++;
}
state.before = state.before.splice(start, 0, open);
state.after = state.after.splice(end, 0, close);
textAction = [{
add: open,
del: '',
start: start
}, {
add: close,
del: '',
start: state.before.length + end
}];
}
state.ss += open.length;
state.se += open.length;
return textAction;
}
}
};
preEditor.$preContentElt.on('keydown', function (evt) {
var cmdOrCtrl = evt.metaKey || evt.ctrlKey;
switch (evt.keyCode) {
case 9: // Tab
if (!cmdOrCtrl) {
action('indent', {
inverse: evt.shiftKey
});
return false;
}
break;
case 13:
action('newline');
return false;
case 191:
if (cmdOrCtrl && !evt.altKey) {
action('comment', {
lang: this.id
});
return false;
}
break;
}
});
}
return PreEditor;
});

View File

@ -0,0 +1,183 @@
define(['jquery'], function($) {
function PreEditor(preElt) {
this.selectionStart = 0;
this.selectionEnd = 0;
this.scrollTop = 0;
this.$preContentElt = $('<div contenteditable class="pre-content">');
preElt.appendChild(this.$preContentElt[0]);
preElt.focus = function() {
this.$preContentElt.focus();
this.setSelectionRange(this.selectionStart, this.selectionEnd);
preElt.scrollTop = this.scrollTop;
};
this.$preContentElt.focus(function() {
preElt.focused = true;
});
this.$preContentElt.blur(function() {
preElt.focused = false;
});
Object.defineProperty(preElt, 'value', {
get: function() {
return this.$preContentElt.text();
},
set: function(value) {
this.$preContentElt.text(value);
}
});
Object.defineProperty(preElt, 'value', {
get: function() {
return this.$preContentElt.text();
},
set: function(value) {
this.$preContentElt.text(value);
}
});
Object.defineProperty(preElt, 'selectionStart', {
get: function() {
var selection = window.getSelection();
if(selection.rangeCount) {
var range = selection.getRangeAt(0),
element = range.startContainer,
container = element,
offset = range.startOffset;
if(!(this.compareDocumentPosition(element) & 0x10)) {
return 0;
}
do {
while(element = element.previousSibling) {
if(element.textContent) {
offset += element.textContent.length;
}
}
element = container = container.parentNode;
} while(element && element != this);
return offset;
}
else {
return 0;
}
},
set: function(value) {
preElt.setSelectionRange(value, this.selectionEnd);
},
enumerable: true,
configurable: true
});
Object.defineProperty(preElt, 'selectionEnd', {
get: function() {
var selection = window.getSelection();
if(selection.rangeCount) {
return this.selectionStart + (selection.getRangeAt(0) + '').length;
}
else {
return 0;
}
},
set: function(value) {
preElt.setSelectionRange(this.selectionStart, value);
},
enumerable: true,
configurable: true
});
preElt.setSelectionRange = function(ss, se) {
this.selectionStart = ss;
this.selectionEnd = se;
function findOffset(root, ss) {
if(!root) {
return null;
}
var offset = 0,
element = root,
container;
do {
container = element;
element = element.firstChild;
if(element) {
do {
var len = element.textContent.length;
if(offset <= ss && offset + len > ss) {
break;
}
offset += len;
} while(element = element.nextSibling);
}
if(!element) {
// It's the container's lastChild
break;
}
} while(element && element.hasChildNodes() && element.nodeType != 3);
if(element) {
return {
element: element,
offset: ss - offset
};
}
else if(container) {
element = container;
while(element && element.lastChild) {
element = element.lastChild;
}
if(element.nodeType === 3) {
return {
element: element,
offset: element.textContent.length
};
}
else {
return {
element: element,
offset: 0
};
}
}
return {
element: root,
offset: 0,
error: true
};
}
var range = document.createRange(),
offset = findOffset(this, ss);
range.setStart(offset.element, offset.offset);
if(se && se != ss) {
offset = findOffset(this, se);
}
range.setEnd(offset.element, offset.offset);
var selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
};
}
return PreEditor;
});

View File

@ -14,7 +14,7 @@ define([], function() {
constants.DEFAULT_FILE_TITLE = "Title";
constants.DEFAULT_FOLDER_NAME = "New folder";
constants.GDRIVE_DEFAULT_FILE_TITLE = "New Markdown document";
constants.EDITOR_DEFAULT_PADDING = 15;
constants.EDITOR_DEFAULT_PADDING = 30;
constants.CHECK_ONLINE_PERIOD = 120000;
constants.AJAX_TIMEOUT = 30000;
constants.ASYNC_TASK_DEFAULT_TIMEOUT = 60000;

View File

@ -4,6 +4,7 @@ define([
"underscore",
"crel",
"ace",
"classes/PreEditor",
"constants",
"utils",
"storage",
@ -25,7 +26,7 @@ define([
'ace/ext/spellcheck',
'ace/ext/searchbox'
], function($, _, crel, ace, constants, utils, storage, settings, eventMgr, shortcutMgr, mousetrap, bodyIndexHTML, bodyViewerHTML, settingsTemplateTooltipHTML, settingsUserCustomExtensionTooltipHTML) {
], function($, _, crel, ace, PreEditor, constants, utils, storage, settings, eventMgr, shortcutMgr, mousetrap, bodyIndexHTML, bodyViewerHTML, settingsTemplateTooltipHTML, settingsUserCustomExtensionTooltipHTML) {
var core = {};
@ -384,6 +385,16 @@ define([
}
},
onresize_end: function(paneName) {
if(preEditor.$preContentElt !== undefined && paneName == 'center') {
var padding = ($editorElt.width() - getMaxWidth()) / 2;
if(padding < constants.EDITOR_DEFAULT_PADDING) {
padding = constants.EDITOR_DEFAULT_PADDING;
}
preEditor.$preContentElt.css({
'padding-left': padding + 'px',
'padding-right': padding + 'px'
});
}
if(aceEditor !== undefined && paneName == 'center') {
aceEditor.resize();
var bottomMargin = (aceEditor.renderer.$size.scrollerHeight - aceEditor.renderer.lineHeight) / 2;
@ -488,6 +499,7 @@ define([
var fileDesc;
var documentContent;
var UndoManager = require("ace/undomanager").UndoManager;
var preEditor;
core.initEditor = function(fileDescParam) {
if(fileDesc !== undefined) {
eventMgr.onFileClosed(fileDesc);
@ -518,11 +530,14 @@ define([
// Store editor scrollTop on scroll event
$editorElt.scroll(function() {
if(documentContent !== undefined) {
fileDesc.editorScrollTop = $(this).scrollTop();
preEditor.scrollTop = this.scrollTop;
fileDesc.editorScrollTop = preEditor.scrollTop;
}
});
// Store editor selection on change
$editorElt.bind("keyup mouseup", function() {
preEditor.selectionStart = this.selectionStart;
preEditor.selectionEnd = this.selectionEnd;
if(documentContent !== undefined) {
fileDesc.editorStart = this.selectionStart;
fileDesc.editorEnd = this.selectionEnd;
@ -572,9 +587,13 @@ define([
if(aceEditor !== undefined) {
newDocumentContent = aceEditor.getValue();
}
if(documentContent !== undefined && documentContent != newDocumentContent) {
if(documentContent === undefined) {
preEditor.highlight();
}
else if(documentContent != newDocumentContent) {
fileDesc.content = newDocumentContent;
eventMgr.onContentChanged(fileDesc);
preEditor.highlight();
}
documentContent = newDocumentContent;
}
@ -615,7 +634,8 @@ define([
eventMgr.onFileOpen(fileDesc);
$previewContainerElt.scrollTop(fileDesc.previewScrollTop);
if(window.lightMode) {
$editorElt.scrollTop(fileDesc.editorScrollTop);
preEditor.scrollTop = fileDesc.editorScrollTop;
$editorElt.scrollTop(preEditor.scrollTop);
}
else {
_.defer(function() {
@ -704,7 +724,7 @@ define([
screenWidth = screenWidth || 0;
//var codeFontSize = settings.editorFontSize;
//var codeLineHeight = Math.round(codeFontSize * 20 / 12);
var previewFontSize = size * 13 / 12;
var previewFontSize = size; // * 13 / 12;
styleContent += [
'@media (min-width: ' + screenWidth + 'px) {',
'#wmd-input, .textarea-helper {',
@ -717,9 +737,9 @@ define([
'}',
].join('\n');
}
applyFont(15);
applyFont(16, 600);
applyFont(17, 1200);
applyFont(16);
applyFont(17, 600);
applyFont(18, 1200);
function applyMaxWidth(maxWidth, screenWidth) {
styleContent += [
@ -837,17 +857,12 @@ define([
});
// Editor
if(window.preMode) {
// In light mode, we replace ACE with a textarea
$('#wmd-input').addClass('form-control').attr('contenteditable', true);
// Create UI layout after textarea
createLayout();
}
else if(window.lightMode) {
// In light mode, we replace ACE with a textarea
if(window.lightMode) {
// In pre mode, we replace ACE with an editable pre
$('#wmd-input').replaceWith(function() {
return $('<textarea id="wmd-input">').addClass(this.className).addClass('form-control');
var result = $('<pre id="wmd-input">').addClass(this.className).addClass('form-control');
preEditor = new PreEditor(result[0]);
return result;
});
// Create UI layout after textarea

View File

@ -93,7 +93,11 @@ define([
h.processUpdateTime = 50;
h.Config({"HTML-CSS": {EqnChunk: 10,EqnChunkFactor: 1},SVG: {EqnChunk: 10,EqnChunkFactor: 1}})
});
/*benweet
Don't hash inline math $...$ (see https://github.com/benweet/stackedit/issues/136)
var u = /(\$\$?|\\(?:begin|end)\{[a-z]*\*?\}|\\[\\{}$]|[{}]|(?:\n\s*)+|@@\d+@@)/i, r;
*/
var u = /(\$\$|\\(?:begin|end)\{[a-z]*\*?\}|\\[\\{}$]|[{}]|(?:\n\s*)+|@@\d+@@)/i, r;
r = 3 === "aba".split(/(b)/).length ? function(a, f) {
return a.split(f)
} : function(a, f) {

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -713,7 +713,7 @@
if (!util.isVisible(inputArea)) {
return;
}
if (!isInitialState && doc.activeElement && doc.activeElement !== inputArea) { // this happens when tabbing out of the input box
if (!isInitialState && !inputArea.focused) { // this happens when tabbing out of the input box
return;
}
@ -742,7 +742,7 @@
}
else if (doc.selection) {
if (doc.activeElement && doc.activeElement !== inputArea) {
if (!inputArea.focused) {
return;
}
@ -811,7 +811,9 @@
inputArea.value = stateObj.text;
}
this.setInputAreaSelection();
inputArea.scrollTop = stateObj.scrollTop;
setTimeout(function() {
inputArea.scrollTop = stateObj.scrollTop;
}, 0);
};
// Gets a collection of HTML chunks from the inptut textarea.
@ -1431,7 +1433,7 @@
// on mousedown.
if (uaSniffed.isIE) {
button.onmousedown = function () {
if (doc.activeElement && doc.activeElement !== panels.input) { // we're not even in the input box, so there's no selection
if (!panels.input.focused) { // we're not even in the input box, so there's no selection
return;
}
panels.ieCachedRange = document.selection.createRange();

View File

@ -0,0 +1,11 @@
Prism.languages.latex = {
// A tex command e.g. \foo
'keyword': /\\(?:[^a-zA-Z]|[a-zA-Z]+)/g,
// Curly and square braces
'lparen': /[[({]/g,
// Curly and square braces
'rparen': /[\])}]/g,
// A comment. Tex comments start with % and go to
// the end of the line
'comment': /%.*/g,
};

View File

@ -0,0 +1,308 @@
Prism.languages.md = (function() {
var urlPattern = /\b((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>\[\]'"]+|\([^\s()<>\[\]'"]*\))+(?:\([^\s()<>\[\]'"]*\)|[^\s`!()\[\]{}:'".,<>?«»“”‘’]))/gi;
var emailPattern = /[a-z0-9!#$%&'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+\/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+(?:[A-Z]{2}|com|org|net|edu|gov|mil|biz|info|mobi|name|aero|asia|jobs|museum)\b/gi;
var md = {};
md.pre = {
pattern: /(^|(?:^|(?:^|\n)(?![ \t]*([*+\-]|\d+\.)[ \t]).*\n)\s*?\n)(\s*(?:[ ]{4}|\t).*(?:\n|$))+/g,
lookbehind: true,
inside: {
}
};
md['pre gfm'] = {
pattern: /^ {0,3}`{3}.*?\n(.*?\n)*? {0,3}`{3} *$/gm,
inside: {
"md md-pre": /`{3}/
}
};
md['h1 alt'] = {
pattern: /^(.+)[ \t]*\n=+[ \t]*$/gm,
inside: {
}
};
md['h2 alt'] = {
pattern: /^(.+)[ \t]*\n-+[ \t]*$/gm,
inside: {
}
};
md.hr = {
pattern: /^([*\-_] *){3,}$/gm,
};
md.li = {
pattern: /^[ \t]*([*+\-]|\d+\.)[ \t].+$/gm,
inside: {
"md md-li": /^[ ]?([*+\-]|\d+\.)[ \t]/m,
"md md-li2": /^[ ]?(?:[ ]{2}|[ ]{1})([*+\-]|\d+\.)[ \t]/m,
"md md-li3": /^[ ]?(?:[ ]{4}|[ ]{2})([*+\-]|\d+\.)[ \t]/m,
"md md-li4": /^[ ]?(?:[ ]{6}|[ ]{3})([*+\-]|\d+\.)[ \t]/m,
"md md-li5": /^[ ]?(?:[ ]{8}|[ ]{4})([*+\-]|\d+\.)[ \t]/m,
"md md-li6": /^[ ]?(?:[ ]{10}|[ ]{5})([*+\-]|\d+\.)[ \t]/m,
"md md-li7": /^[ ]?(?:[ ]{12}|[ ]{6})([*+\-]|\d+\.)[ \t]/m,
"md md-li8": /^[ ]?(?:[ ]{14}|[ ]{7})([*+\-]|\d+\.)[ \t]/m,
"md md-li9": /^[ ]?(?:[ ]{16}|[ ]{8})([*+\-]|\d+\.)[ \t]/m,
"md md-li10": /^[ ]?(?:[ ]{18}|[ ]{9})([*+\-]|\d+\.)[ \t]/m,
"md md-li11": /^[ ]?(?:[ ]{20}|[ ]{10})([*+\-]|\d+\.)[ \t]/m
}
};
for (var i = 6; i >= 1; i--) {
md["h" + i] = {
pattern: new RegExp("^#{" + i + "} .*$", "gm"),
inside: {
"md md-hash": new RegExp("^#{" + i + "} ")
}
};
}
md.blockquote = {
pattern: /^>[ ]*[^\n]+$/gm,
inside: {
"md md-gt": /^>[ ]*/
}
};
md['math block'] = {
pattern: /(\$\$|\\\\\[|\\\\\\\\\()[\s\S]*?(\$\$|\\\\\]|\\\\\\\\\))/g,
inside: {
"md md-bracket-start": /^(\$\$|\\\\\[|\\\\\\\\\()/,
"md md-bracket-end": /(\$\$|\\\\\]|\\\\\\\\\))/,
rest: Prism.languages.latex
}
};
md['latex block'] = {
pattern: /\\?\\begin\{[a-z]*\*?\}[\s\S]*?\\?\\end\{[a-z]*\*?\}/g,
inside: {
"keyword": /\\?\\(begin|end)/,
rest: Prism.languages.latex
}
};
md.fndef = {
pattern: /^ {0,3}\[\^.*?\]:[ \t]+.*$/gm,
inside: {
"ref-id": {
pattern: /\[\^.*?\]/,
inside: {
"md md-bracket-start": /\[/,
"md md-bracket-end": /\]/
}
}
}
};
md.linkdef = {
pattern: /^ {0,3}\[.*?\]:[ \t]+.*$/gm,
inside: {
"link-id": {
pattern: /\[.*?\]/,
inside: {
"md md-bracket-start": /\[/,
"md md-bracket-end": /\]/
}
},
url: urlPattern,
linktitle: /['\"\(][^\'\"\)]*['\"\)]/
}
};
md.tocmarker = {
pattern: /(^|(?:^|\n)\s*\n)[ \t]*\[(toc|TOC)\]($|\n($|\s*\n))$/g,
inside: {
"md md-toc": /\[(toc|TOC)\]/
}
};
md.p = {
pattern: /^[^\n]+(?:\n|$)/gm,
inside: {
}
};
md.img = {
pattern: /!\[[^\]]*\]\([^\)]+\)/g,
inside: {
"md md-bang": /^!/,
"md md-bracket-start": /\[/,
"md md-alt": /[^\[]+(?=\])/,
"md md-bracket-end": /\](?=\()/,
"md img-parens": {
pattern: /\([^\)]+\)/,
inside: {
"md md-paren-start": /^\(/,
"md md-title": /(['][^']*[']|["“][^"”]*["”])(?=\)$)/,
"md md-src": /[^\('" \t]+(?=[\)'" \t])/,
"md md-paren-end": /\)$/
}
}
}
};
md.link = {
pattern: /\[(?:(\\.)|[^\[\]])*\]\([^\(\)\s]+(\(\S*?\))??[^\(\)\s]*?(\s(['][^']*[']|["“][^"”]*["”]))?\)/gm,
inside: {
"md md-bracket-start": {
pattern: /(^|[^\\])\[/,
lookbehind: true
},
"md md-underlined-text": {
pattern: /(?:(\\.)|[^\[\]])+(?=\])/
},
"md md-bracket-end": /\]\s?\(/,
"md md-paren-end": /\)$/,
"md md-href": /.*/
}
};
md.fn = {
pattern: /\[\^(.*?)\]/g,
inside: {
"ref": {
pattern: /^\[[^\[\]]+\] ?/,
inside: {
"md md-bracket-start": /\[/,
"md md-ref": /^[^\[\]]+/,
"md md-bracket-end": /\]/
}
}
}
};
md.imgref = {
pattern: /!\[(.*?)\] ?\[(.*?)\]/g,
inside: {
"md md-bang": /^!/,
"ref-end": {
pattern: /\[[^\[\]]+\]$/,
inside: {
"md md-bracket-start": /\[/,
"md md-href": /[^\[\]]+(?=]$)/,
"md md-bracket-end": /\]/
}
},
"ref-start": {
pattern: /^\[[^\[\]]+\] ?/,
inside: {
"md md-bracket-start": /\[/,
"md md-alt": /^[^\[\]]+/,
"md md-bracket-end": /\]/
}
}
}
};
md.linkref = {
pattern: /\[(.*?)\] ?\[(.*?)\]/g,
inside: {
"ref-end": {
pattern: /\[[^\[\]]+\]$/,
inside: {
"md md-bracket-start": /\[/,
"md md-href": /[^\[\]]+(?=]$)/,
"md md-bracket-end": /\]/
}
},
"ref-start": {
pattern: /^\[[^\[\]]+\] ?/,
inside: {
"md md-bracket-start": /\[/,
"md md-underlined-text": /^[^\[\]]+/,
"md md-bracket-end": /\]/
}
}
}
};
md.url = {
pattern: urlPattern
};
md.email = {
pattern: emailPattern
};
md.code = {
pattern: /(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/g,
lookbehind: true,
inside: {
"md md-code": /`/
}
};
md.math = {
pattern: /\$.*?\$/g,
inside: {
"md md-bracket-start": /^\$/,
"md md-bracket-end": /\$$/,
rest: Prism.languages.latex
}
};
md.strong = {
pattern: /([_\*])\1((?!\1{2}).)*\1{2}/g,
inside: {
"md md-strong": /([_\*])\1/g
}
};
md.em = {
pattern: /(^|[^\\])(\*|_)(\S[^\2]*?)??[^\s\\]+?\2/g,
lookbehind: true,
inside: {
"md md-em md-start": /^(\*|_)/,
"md md-em md-close": /(\*|_)$/
}
};
md.strike = {
pattern: /(^|\n|\W)(~~)(?=\S)([^\r]*?\S)\2/gm,
lookbehind: true,
inside: {
"md md-s": /(~~)/,
"md-strike-text": /[^~]+/
}
};
var rest = {
code: md.code,
math: md.math,
fn: md.fn,
img: md.img,
link: md.link,
imgref: md.imgref,
linkref: md.linkref,
url: md.url,
email: md.email,
strong: md.strong,
em: md.em,
strike: md.strike,
comment: Prism.languages.markup.comment,
tag: Prism.languages.markup.tag,
entity: Prism.languages.markup.entity
};
for (var c = 6; c >= 1; c--) {
md["h" + c].inside.rest = rest;
}
md["h1 alt"].inside.rest = rest;
md["h2 alt"].inside.rest = rest;
md.p.inside.rest = rest;
md.blockquote.inside.rest = rest;
md.li.inside.rest = rest;
md.fndef.inside.rest = rest;
md.blockquote.inside.rest.li = md.li;
rest = {
code: md.code,
fn: md.fn,
link: md.link,
linkref: md.linkref,
};
md.strong.inside.rest = rest;
md.em.inside.rest = rest;
md.strike.inside.rest = rest;
var inside = {
code: md.code,
strong: md.strong,
em: md.em,
strike: md.strike,
comment: Prism.languages.markup.comment,
tag: Prism.languages.markup.tag,
entity: Prism.languages.markup.entity
};
md.link.inside["md md-underlined-text"].inside = inside;
md.linkref.inside["ref-start"].inside["md md-underlined-text"].inside = inside;
return md;
/*
Prism.hooks.add("wrap", function (t) {
var i = -1 !== document.getElementsByTagName("body")[0].className.indexOf("tmpl-diffs") ? true : false;
if (0 === t.type.indexOf("img") && !i) {
var s = t.content.match(/md\-src"\s>([^<]+)/),
a = t.content.match(/md\-alt"\s>([^<]+)/);
s && s[1] && s[1].match(n) && (a = ' alt="' + (a ? e(a[1]) : "") + '"', t.content += "<span class='img-preview' contenteditable='false'><img src='" + s[1] + "' " + a + " /></span>");
}
});
*/
})();

View File

@ -62,7 +62,9 @@ requirejs.config({
'Typo.js': 'bower-libs/Typo.js',
css: 'bower-libs/require-css/css',
'css-builder': 'bower-libs/require-css/css-builder',
normalize: 'bower-libs/require-css/normalize'
normalize: 'bower-libs/require-css/normalize',
prism: 'bower-libs/prism/prism',
'prism-core': 'bower-libs/prism/components/prism-core',
},
shim: {
underscore: {
@ -83,6 +85,19 @@ requirejs.config({
'yaml-js': {
exports: 'YAML'
},
'prism-core': {
exports: 'Prism'
},
'bower-libs/prism/components/prism-markup': [
'prism-core'
],
'libs/prism-latex': [
'prism-core'
],
'libs/prism-markdown': [
'bower-libs/prism/components/prism-markup',
'libs/prism-latex'
],
'bootstrap-record': [
'mousetrap'
],

View File

@ -17,6 +17,7 @@
@font-size-base: 15px;
@line-height-base: 1.45;
@p-margin: 1.1em;
@headings-font-family: inherit;
@font-face {
font-family: 'Source Sans Pro';
@ -68,6 +69,19 @@
src: local('Source Code Pro Bold'), local('SourceCodePro-Bold'), url("../font/SourceCodePro-Bold-webfont.woff") format('woff');
}
@font-face {
font-family: 'Inconsolata';
font-style: normal;
font-weight: 400;
src: local('Inconsolata'), url("../font/Inconsolata-Regular-webfont.woff") format('woff');
}
@font-face {
font-family: 'Inconsolata';
font-style: normal;
font-weight: 700;
src: local('Inconsolata Bold'), local('Inconsolata-Bold'), url("../font/Inconsolata-Bold-webfont.woff") format('woff');
}
@font-face {
font-family: 'Anonymous Pro';
font-style: normal;
@ -136,6 +150,10 @@ h1, h2, h3, h4, h5, h6 {
margin: 1.3em 0;
}
pre {
word-break: break-all;
}
p,
pre,
pre.prettyprint,
@ -150,7 +168,7 @@ hr {
code, pre {
font-family: @font-family-monospace;
letter-spacing: @font-family-monospace-letter-spacing;
font-size: 0.95em !important;
font-size: 0.9em;
}
pre, pre.prettyprint {

View File

@ -35,6 +35,7 @@
// Editor
@tertiary-bg: #fff;
@tertiary-color-lighter: fade(@tertiary-color, 40%);
@tertiary-color-light: fade(@tertiary-color, 60%);
@tertiary-color: darken(@secondary-desaturated, 7.5%);
@tertiary-color-dark: darken(@tertiary-color, 15%);
@ -57,7 +58,7 @@
@document-panel-width: 320px;
@jgrowl-width: 260px;
@resizer-size: 32px;
@editor-line-weight: 1.6;
@editor-line-weight: 1.65;
/* Bootstrap */
@body-bg: @secondary-bg-light;
@ -140,7 +141,7 @@ body {
}
#preview-contents {
padding: 15px;
padding: 30px;
margin: 0 auto 180px;
text-align: justify;
}
@ -1201,20 +1202,233 @@ a {
}
}
@font-face {
font-family: 'PT Sans';
font-style: normal;
font-weight: 400;
src: local('PT Sans'), local('PTSans'), url("../font/PTSans-Regular-webfont.woff") format('woff');
}
@font-face {
font-family: 'PT Sans';
font-style: normal;
font-weight: 700;
src: local('PT Sans Bold'), local('PTSans-Bold'), url("../font/PTSans-Bold-webfont.woff") format('woff');
}
@font-face {
font-family: 'PT Sans';
font-style: italic;
font-weight: 400;
src: local('PT Sans Italic'), local('PTSans-Italic'), url("../font/PTSans-Italic-webfont.woff") format('woff');
}
@font-face {
font-family: 'PT Sans';
font-style: italic;
font-weight: 700;
src: local('PT Sans Bold Italic'), local('PTSans-BoldItalic'), url("../font/PTSans-BoldItalic-webfont.woff") format('woff');
}
#wmd-input {
font-family: @font-family-monospace;
letter-spacing: @font-family-monospace-letter-spacing;
letter-spacing: normal;
font-size: @font-size-base;
border-radius: 0;
color: @tertiary-color-dark;
.box-shadow(none);
resize: none;
border: none;
padding: 0 @padding-base-horizontal;
padding: 0;
line-height: @editor-line-weight;
div& {
padding: 0;
}
pre& {
background-color: @tertiary-bg;
font-family: "PT Sans", sans-serif;
overflow: auto;
white-space: pre-wrap;
word-break: break-word;
> div {
margin: 0 auto;
}
}
.code,
.pre {
color: @tertiary-color-darker;
font: normal 0.9em @font-family-monospace
}
.tag {
color: @tertiary-color-darker;
font: bold 0.9em @font-family-monospace;
.punctuation,
.attr-value,
.attr-name {
font-weight: normal;
}
}
.latex, .math {
color: @tertiary-color;
}
.entity {
font: italic 0.9em @font-family-monospace;
color: @tertiary-color;
}
.comment {
font-size: 0.9em;
color: @tertiary-color-light;
}
.keyword {
color: @tertiary-color-dark;
font-weight: bold;
}
.code, .img, .imgref, .md-toc {
background-color: @code-bg;
border-radius: @border-radius-base;
padding: 0.15em 0;
}
.md-toc {
font-size: 2.5em;
padding: 0.2em;
}
/*
.pre {
line-height: 1.8;
margin-left: 1.8em
}
*/
.link, .linkref {
.md-underlined-text {
color: inherit;
}
}
.blockquote {
color: @tertiary-color;
padding-left: 2em;
.li {
padding-left: 0;
}
}
.h1, .h2, .h3, .h4, .h5, .h6 {
font-weight: 600;
.md-hash {
color: @tertiary-color-lighter;
}
}
.h1, .h11 { font-size: 1.4em; }
.h2, .h22 { font-size: 1.3em; }
.h3 { font-size: 1.2em; }
.h4 { font-size: 1.1em; }
.h5 { font-size: 1em; }
.h6 { font-size: 0.9em; }
.url,.email {
color: @tertiary-color-light;
}
.md {
color: @tertiary-color-light;
font-style: normal;
font-weight: 400
}
.em,.em .md {
font-style: italic
}
.strong,.strong .md {
font-weight: 600
}
.md-strike-text {
text-decoration: line-through
}
.md-underlined-text {
text-decoration: underline;
}
.li {
padding-left: 0.8em;
.li {
padding-left: 0;
}
}
.md-li,.md-li2,.md-li3,.md-li4,.md-li5,.md-li6,.md-li7,.md-li8,.md-li9,.md-li10,.md-li11 {
white-space: pre-line;
}
.md-li {
padding-left: 1.2em
}
.md-li2 {
padding-left: 2.4em
}
.md-li3 {
padding-left: 3.6em
}
.md-li4 {
padding-left: 4.8em
}
.md-li5 {
padding-left: 6em
}
.md-li6 {
padding-left: 7.2em
}
.md-li7 {
padding-left: 8.4em
}
.md-li8 {
padding-left: 9.6em
}
.md-li9 {
padding-left: 10.8em
}
.md-li10 {
padding-left: 12em
}
.md-li11 {
padding-left: 13.2em
}
.img,
.imgref {
padding: 0.2em 0.4em;
padding-right: 0
}
.md-bang,
.md-alt,
.md-title {
color: #666
}
}
.textarea-helper {
@ -1223,7 +1437,7 @@ a {
position: absolute;
top: -100px;
height: 1px;
padding: 0 @padding-base-horizontal;
padding: 0;
line-height: @editor-line-weight;
position: absolute;
overflow: auto;