define([ "jquery", "underscore", "classes/Extension", "text!html/partialRenderingSettingsBlock.html", ], function($, _, Extension, partialRenderingSettingsBlockHTML) { var partialRendering = new Extension("partialRendering", "Partial Rendering", true); partialRendering.settingsBlock = partialRenderingSettingsBlockHTML; var converter = undefined; var sectionCounter = 0; var sectionList = []; var linkDefinition = undefined; var sectionsToRemove = []; var modifiedSections = []; var insertAfterSection = undefined; var fileChanged = false; function updateSectionList(newSectionList, newLinkDefinition) { modifiedSections = []; sectionsToRemove = []; insertAfterSection = undefined; // Render everything if file or linkDefinition changed if(fileChanged === true || linkDefinition != newLinkDefinition) { fileChanged = false; linkDefinition = newLinkDefinition; sectionsToRemove = sectionList; sectionList = newSectionList; modifiedSections = newSectionList; return; } // Find modified sections starting from top var leftIndex = sectionList.length; _.some(sectionList, function(section, index) { if(index >= newSectionList.length || section.text != newSectionList[index].text) { leftIndex = index; return true; } }); // Find modified sections starting from bottom var rightIndex = -sectionList.length; _.some(sectionList.slice().reverse(), function(section, index) { if(index >= newSectionList.length || section.text != newSectionList[newSectionList.length - index - 1].text) { rightIndex = -index; return true; } }); if(leftIndex === sectionList.length && rightIndex === -leftIndex) { // No modification detected... return; } // Create an array composed of left unmodified, modified, right // unmodified sections var leftSections = sectionList.slice(0, leftIndex); modifiedSections = newSectionList.slice(leftIndex, newSectionList.length + rightIndex); var rightSections = sectionList.slice(sectionList.length + rightIndex, sectionList.length); insertAfterSection = _.last(leftSections); sectionsToRemove = sectionList.slice(leftIndex, sectionList.length + rightIndex); sectionList = leftSections.concat(modifiedSections).concat(rightSections); } var doFootnotes = false; var hasFootnotes = false; partialRendering.onSectionsCreated = function(sectionListParam) { var newSectionList = []; var newLinkDefinition = ""; hasFootnotes = false; _.each(sectionListParam, function(text) { text += "\n\n"; // Strip link definitions text = text.replace(/^```.*\n[\s\S]*?\n```|^[ ]{0,3}\[(.+)\]:[ \t]*\n?[ \t]*?(?=\s|$)[ \t]*\n?[ \t]*((\n*)["(](.+?)[")][ \t]*)?(?:\n+)/gm, function(wholeMatch, link) { if(link) { newLinkDefinition += wholeMatch; return ""; } return wholeMatch; }); // And footnotes eventually if(doFootnotes) { text = text.replace(/^```.*\n[\s\S]*?\n```|\n[ ]{0,3}\[\^(.+?)\]\:[ \t]*\n?([\s\S]*?)\n{1,2}((?=\n[ ]{0,3}\S)|$)/g, function(wholeMatch, footnote) { if(footnote) { hasFootnotes = true; newLinkDefinition += wholeMatch; return ""; } return wholeMatch; }); } // Skip space only sections if(/\S/.test(text)) { // Add section to the newSectionList newSectionList.push({ id: ++sectionCounter, text: text }); } }); updateSectionList(newSectionList, newLinkDefinition); }; var footnoteContainerElt = $('
'); var footnoteList = {}; function refreshSections() { // Remove outdated sections _.each(sectionsToRemove, function(section) { $("#wmd-preview-section-" + section.id).remove(); }); var wmdPreviewElt = $("#wmd-preview"); var insertAfterSectionElt = insertAfterSection === undefined ? wmdPreviewElt : $("#wmd-preview-section-" + insertAfterSection.id); _.each(modifiedSections, function(section) { var sectionElt = $('
'); _.some(wmdPreviewElt.contents(), function(elt, index) { elt = $(elt); if(index !== 0 && elt.is(".wmd-title")) { return true; } else if(elt.is("div.footnotes")) { elt.find("ol > li").each(function() { var footnoteElt = $(this).clone(); var id = footnoteElt.attr("id").substring(3); footnoteList[id] = footnoteElt; }); elt.remove(); } else { sectionElt.append(elt); } }); insertAfterSectionElt.after(sectionElt); insertAfterSectionElt = sectionElt; }); // Rewrite footnotes in the footer and update footnote numbers footnoteContainerElt.empty(); var usedFootnoteIds = []; if(hasFootnotes === true) { var footnoteElts = $("
    "); $("#preview-contents a.footnote").each(function(index) { var id=$(this).text(index + 1).attr("id").substring(6); usedFootnoteIds.push(id); footnoteElts.append(footnoteList[id].clone()); }); if(usedFootnoteIds.length > 0) { // Append the whole footnotes at the end of the document footnoteContainerElt.html($('
    ').append("
    ").append(footnoteElts)); } // Keep used footnotes only in our map footnoteList = _.pick(footnoteList, usedFootnoteIds); } } partialRendering.onEditorConfigure = function(editor) { converter = editor.getConverter(); converter.hooks.chain("preConversion", function(text) { var result = _.map(modifiedSections, function(section) { return section.text; }); result.push(linkDefinition + "\n\n"); return result.join(""); }); editor.hooks.chain("onPreviewRefresh", function() { refreshSections(); }); }; partialRendering.onReady = function() { $("#preview-contents").append(footnoteContainerElt); $("#wmd-preview").hide(); }; partialRendering.onFileSelected = function() { fileChanged = true; }; partialRendering.onFileOpen = function() { if(converter.extraExtensions) { doFootnotes = _.some(converter.extraExtensions, function(extension) { return extension == "footnotes"; }); } }; return partialRendering; });