diff --git a/public/res/eventMgr.js b/public/res/eventMgr.js index 1c78a242..0358b855 100644 --- a/public/res/eventMgr.js +++ b/public/res/eventMgr.js @@ -98,7 +98,7 @@ define([ }; } - // Add a Hook to the eventMgr that we can fire using eventMgr.eventName() + // Declare an event Hook in the eventMgr that we can fire using eventMgr.eventName() function addEventHook(eventName) { eventMgr[eventName] = createEventHook(eventName); } @@ -113,7 +113,7 @@ define([ } }; - // Call every onInit listeners (extensions only) + // Call every onInit listeners (enabled extensions only) createEventHook("onInit")(); // Load/Save extension config from/to settings @@ -183,8 +183,7 @@ define([ addEventHook("onPagedownConfigure"); addEventHook("onSectionsCreated"); addEventHook("onMarkdownTrim"); - addEventHook("onExtraExtensions"); - + // Operation on ACE addEventHook("onAceCreated"); diff --git a/public/res/extensions/markdownExtra.js b/public/res/extensions/markdownExtra.js index d28d0866..b3e2678e 100644 --- a/public/res/extensions/markdownExtra.js +++ b/public/res/extensions/markdownExtra.js @@ -74,9 +74,6 @@ define([ editor.hooks.chain("onPreviewRefresh", prettify.prettyPrint); } Markdown.Extra.init(converter, options); - - // Send extensions list to other extensions - eventMgr.onExtraExtensions(markdownExtra.config.extensions); }; return markdownExtra; diff --git a/public/res/extensions/markdownSectionParser.js b/public/res/extensions/markdownSectionParser.js index a3e8f537..1a440bdd 100644 --- a/public/res/extensions/markdownSectionParser.js +++ b/public/res/extensions/markdownSectionParser.js @@ -1,6 +1,9 @@ define([ - "classes/Extension" -], function(Extension) { + "underscore", + "extensions/markdownExtra", + "extensions/mathJax", + "classes/Extension", +], function(_, markdownExtra, mathJax, Extension) { var markdownSectionParser = new Extension("markdownSectionParser", "Markdown section parser"); @@ -10,26 +13,49 @@ define([ }; markdownSectionParser.onPagedownConfigure = function(editor) { + + // Build a regexp to look for section delimiters + var regexp = '^.+[ \\t]*\\n=+[ \\t]*\\n+|^.+[ \\t]*\\n-+[ \\t]*\\n+|^\\#{1,6}[ \\t]*.+?[ \\t]*\\#*\\n+'; // Title delimiters + if(markdownExtra.config.enabled) { + if(_.some(markdownExtra.config.extensions, function(extension) { + return extension == "fenced_code_gfm"; + })) { + regexp = '^```.*\\n[\\s\\S]*?\\n```|' + regexp; // Fenced block delimiters + } + } + if(mathJax.config.enabled) { + // Math delimiter has to follow 1 empty line to be considered as a section delimiter + regexp = '^[ \\t]*\\n[ \\t]*\\$\\$[\\s\\S]*\\$\\$|' + regexp; // $$ math delimiters + regexp = '^[ \\t]*\\n[ \\t]*\\\\\\\\\\[[\\s\\S]*\\\\\\\\\\]|' + regexp; // \\[ \\] math delimiters + regexp = '^[ \\t]*\\n[ \\t]*\\\\\\\\begin\\{[a-z]*\\*?\\}[\\s\\S]*\\\\\\\\end\\{[a-z]*\\*?\\}|' + regexp; // \\begin{...} \\end{...} math delimiters + } + regexp = new RegExp(regexp, 'gmi'); + var converter = editor.getConverter(); converter.hooks.chain("preConversion", function(text) { eventMgr.previewStartTime = new Date(); var tmpText = text + "\n\n"; var sectionList = [], offset = 0; - // Look for titles (excluding gfm blocs) - tmpText.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 - sectionList.push(tmpText.substring(offset, matchOffset)); - offset = matchOffset; - } - return ""; + // Look for delimiters + tmpText.replace(regexp, function(match, matchOffset) { + // Create a new section with the text preceding the delimiter + var sectionText = tmpText.substring(offset, matchOffset); + sectionList.push({ + text: sectionText, + textWithDelimiter: '\n
\n\n' + sectionText + '\n' + }); + offset = matchOffset; }); // Last section - sectionList.push(tmpText.substring(offset, text.length)); + var sectionText = tmpText.substring(offset, text.length); + sectionList.push({ + text: sectionText, + textWithDelimiter: '\n
\n\n' + sectionText + '\n' + }); eventMgr.onSectionsCreated(sectionList); - return text; + return _.reduce(sectionList, function(result, section) { + return result + section.textWithDelimiter; + }, ''); }); }; diff --git a/public/res/extensions/partialRendering.js b/public/res/extensions/partialRendering.js index 52a736ee..27385dc5 100644 --- a/public/res/extensions/partialRendering.js +++ b/public/res/extensions/partialRendering.js @@ -1,9 +1,10 @@ define([ "underscore", "crel", + "extensions/markdownExtra", "classes/Extension", "text!html/partialRenderingSettingsBlock.html", -], function(_, crel, Extension, partialRenderingSettingsBlockHTML) { +], function(_, crel, markdownExtra, Extension, partialRenderingSettingsBlockHTML) { var partialRendering = new Extension("partialRendering", "Partial Rendering", true); partialRendering.settingsBlock = partialRenderingSettingsBlockHTML; @@ -63,6 +64,7 @@ define([ sectionsToRemove = sectionList.slice(leftIndex, sectionList.length + rightIndex); sectionList = leftSections.concat(modifiedSections).concat(rightSections); } + var doFootnotes = false; var hasFootnotes = false; partialRendering.onSectionsCreated = function(sectionListParam) { @@ -70,8 +72,8 @@ define([ var newSectionList = []; var newLinkDefinition = '\n'; hasFootnotes = false; - _.each(sectionListParam, function(text) { - text += "\n\n"; + _.each(sectionListParam, function(section) { + var text = section.textWithDelimiter + '\n'; // Strip footnotes if(doFootnotes) { @@ -94,14 +96,11 @@ define([ return wholeMatch; }); - // Skip space only sections - if(/\S/.test(text)) { - // Add section to the newSectionList - newSectionList.push({ - id: ++sectionCounter, - text: text + '\n' - }); - } + // Add section to the newSectionList + newSectionList.push({ + id: ++sectionCounter, + text: text + '\n' + }); }); updateSectionList(newSectionList, newLinkDefinition); @@ -131,14 +130,14 @@ define([ id: 'wmd-preview-section-' + section.id, class: 'wmd-preview-section preview-content' }); - var isFirst = true; + var isNextDelimiter = false; while (childNode) { var nextNode = childNode.nextSibling; - if(isFirst === false && /(^| )wmd-title($| )/.test(childNode.className)) { - // Stop when encountered the next wmd-title + if(isNextDelimiter === true && childNode.tagName == 'DIV' && childNode.className == 'se-section-delimiter') { + // Stop when encountered the next delimiter break; } - isFirst = false; + isNextDelimiter = true; if(childNode.tagName == 'DIV' && childNode.className == 'footnotes') { _.each(childNode.querySelectorAll("ol > li"), storeFootnote); } @@ -197,10 +196,14 @@ define([ }); }; - partialRendering.onExtraExtensions = function(extraExtensions) { - doFootnotes = _.some(extraExtensions, function(extension) { - return extension == "footnotes"; - }); + partialRendering.onInit = function(extraExtensions) { + if(markdownExtra.config.enabled) { + if(_.some(markdownExtra.config.extensions, function(extension) { + return extension == "footnotes"; + })) { + doFootnotes = true; + } + } }; partialRendering.onReady = function() { diff --git a/public/res/extensions/scrollLink.js b/public/res/extensions/scrollLink.js index e990fcb8..910c7c4f 100644 --- a/public/res/extensions/scrollLink.js +++ b/public/res/extensions/scrollLink.js @@ -37,8 +37,8 @@ define([ var mdTextOffset = 0; var mdSectionOffset = 0; var firstSectionOffset = offsetBegin; - _.each(sectionList, function(sectionText) { - mdTextOffset += sectionText.length + firstSectionOffset; + _.each(sectionList, function(section) { + mdTextOffset += section.text.length + firstSectionOffset; firstSectionOffset = 0; var documentPosition = aceEditor.session.doc.indexToPosition(mdTextOffset); var screenPosition = aceEditor.session.documentToScreenPosition(documentPosition.row, documentPosition.column); @@ -54,18 +54,19 @@ define([ // Try to find corresponding sections in the preview htmlSectionList = []; - var htmlSectionOffset = 0; + var htmlSectionOffset; var previewScrollTop = $previewElt.scrollTop(); - // Each title element is a section separator - $previewElt.find(".preview-content > .wmd-title").each(function() { - var $titleElt = $(this); + $previewElt.find(".preview-content > .se-section-delimiter + *").each(function() { + var $delimiterElt = $(this); // Consider div scroll position and header element top margin - var newSectionOffset = $titleElt.position().top + previewScrollTop + pxToFloat($titleElt.css('margin-top')); - htmlSectionList.push({ - startOffset: htmlSectionOffset, - endOffset: newSectionOffset, - height: newSectionOffset - htmlSectionOffset - }); + var newSectionOffset = $delimiterElt.position().top + previewScrollTop + pxToFloat($delimiterElt.css('margin-top')); + if(htmlSectionOffset !== undefined) { + htmlSectionList.push({ + startOffset: htmlSectionOffset, + endOffset: newSectionOffset, + height: newSectionOffset - htmlSectionOffset + }); + } htmlSectionOffset = newSectionOffset; }); // Last section diff --git a/public/res/styles/main.less b/public/res/styles/main.less index 66a6a141..8cdf95ab 100644 --- a/public/res/styles/main.less +++ b/public/res/styles/main.less @@ -339,7 +339,7 @@ a { display: inline-block; visibility: hidden; width: 8px; - height: 7px; + height: 8px; border-radius: 1px; margin: 0 2px; background-color: @btn-success-color;