diff --git a/css/default.css b/css/default.css index bf47a172..465d6dc8 100644 --- a/css/default.css +++ b/css/default.css @@ -2,7 +2,7 @@ @page { margin: 25mm 25mm 25mm 25mm; } - #wmd-preview { + #preview-contents { padding: 0px; margin: 0px; } @@ -16,7 +16,7 @@ body { tab-size: 4; } -#wmd-preview { +#preview-contents { padding: 19px; margin-bottom: 50px; } @@ -46,7 +46,7 @@ div,span,a,ul,li,textarea,input,button { text-shadow: none !important; } -.btn,.navbar-inner,#wmd-preview,.add-on { +.btn,.navbar-inner,.add-on { border: none !important; } @@ -720,7 +720,7 @@ table tbody+tbody { border-top: 2px solid #dddddd; } -#wmd-preview blockquote { +#preview-contents blockquote { border-color: #ddd; border-color: rgba(0, 0, 0, 0.15); } @@ -796,7 +796,7 @@ input[type="file"] { background-color: rgba(215, 215, 215, 0.75) !important; } -.viewer #wmd-preview { +.viewer #preview-contents { max-width: 1024px; margin: 50px auto; } diff --git a/js/core.js b/js/core.js index 567bb60a..3080e63c 100644 --- a/js/core.js +++ b/js/core.js @@ -181,7 +181,7 @@ define([ extensionMgr.onLayoutConfigure(layoutGlobalConfig); if(settings.layoutOrientation == "horizontal") { $(".ui-layout-south").remove(); - $(".preview-container").html('
'); + $(".preview-container").html('
'); layout = $('body').layout($.extend(layoutGlobalConfig, { east__resizable: true, east__size: .5, @@ -190,7 +190,7 @@ define([ } else if(settings.layoutOrientation == "vertical") { $(".ui-layout-east").remove(); - $(".preview-container").html('
'); + $(".preview-container").html('
'); layout = $('body').layout($.extend(layoutGlobalConfig, { south__resizable: true, south__size: .5, @@ -299,6 +299,7 @@ define([ else { previewWrapper = function(makePreview) { return function() { + window.previewStartTime = new Date().getTime(); makePreview(); if(documentContent === undefined) { previewContainerElt.scrollTop(fileDesc.previewScrollTop); diff --git a/js/extensionMgr.js b/js/extensionMgr.js index 4a7717aa..2c8f52e5 100644 --- a/js/extensionMgr.js +++ b/js/extensionMgr.js @@ -158,11 +158,16 @@ define([ var counter = 0; function tryFinished() { if(++counter === nbAsyncPreviewCallback) { - onPreviewFinished(); + var html = ""; + $("#preview-contents > .preview-content").each(function() { + html += $(this).html(); + }); + onPreviewFinished(html); + console.log("Preview time: " + (new Date().getTime() - window.previewStartTime)); } } // We assume images are loading in the preview - $("#wmd-preview").waitForImages(tryFinished); + $("#preview-contents").waitForImages(tryFinished); _.each(onAsyncPreviewCallbackList, function(asyncPreviewCallback) { asyncPreviewCallback(tryFinished); }); diff --git a/js/extensions/buttonHtmlCode.js b/js/extensions/buttonHtmlCode.js index f0e2e44f..7828fdb4 100644 --- a/js/extensions/buttonHtmlCode.js +++ b/js/extensions/buttonHtmlCode.js @@ -30,12 +30,12 @@ define([ selectedFileDesc = fileDesc; }; - buttonHtmlCode.onPreviewFinished = function() { + buttonHtmlCode.onPreviewFinished = function(html) { try { var htmlCode = _.template(buttonHtmlCode.config.template, { documentTitle: selectedFileDesc.title, documentMarkdown: selectedFileDesc.content, - documentHTML: $("#wmd-preview").html() + documentHTML: html }); $("#input-html-code").val(htmlCode); } diff --git a/js/extensions/buttonStat.js b/js/extensions/buttonStat.js index 88c718c2..5c4d5f2e 100644 --- a/js/extensions/buttonStat.js +++ b/js/extensions/buttonStat.js @@ -45,7 +45,7 @@ define([ }; buttonStat.onPreviewFinished = function() { - var text = $("#wmd-preview").clone().find("script").remove().end().text(); + var text = $("#preview-contents").clone().find("script").remove().end().text(); $("#span-stat-value1").text((text.match(new RegExp(buttonStat.config.value1, "g")) || []).length); $("#span-stat-value2").text((text.match(new RegExp(buttonStat.config.value2, "g")) || []).length); $("#span-stat-value3").text((text.match(new RegExp(buttonStat.config.value3, "g")) || []).length); diff --git a/js/extensions/documentSelector.js b/js/extensions/documentSelector.js index aa4e21d1..4c1b12a6 100644 --- a/js/extensions/documentSelector.js +++ b/js/extensions/documentSelector.js @@ -17,7 +17,7 @@ define([ }; documentSelector.onLoadSettings = function() { - utils.setInputValue("#select-document-selector-orderby", documentSelector.config.sortBy); + utils.setInputValue("#select-document-selector-orderby", documentSelector.config.orderBy); utils.setInputValue("#input-document-selector-shortcut-previous", documentSelector.config.shortcutPrevious); utils.setInputValue("#input-document-selector-shortcut-next", documentSelector.config.shortcutNext); }; diff --git a/js/extensions/mathJax.js b/js/extensions/mathJax.js index 7f8a3534..7d9d4675 100644 --- a/js/extensions/mathJax.js +++ b/js/extensions/mathJax.js @@ -61,6 +61,7 @@ define([ }); }; + var converter = undefined; var ready = false; // true after initial typeset is complete var pending = false; // true when MathJax has been requested var preview = null; // the preview container @@ -209,7 +210,7 @@ define([ function RestartMJ() { pending = false; HUB.cancelTypeset = false; // won't need to do this in the future - HUB.Queue([ "Typeset", HUB, preview ]); + HUB.Queue([ "Typeset", HUB, converter.eltList || preview ]); HUB.Queue(afterRefreshCallback); } @@ -236,9 +237,9 @@ define([ mathJax.onEditorConfigure = function(editorObject) { preview = document.getElementById("wmd-preview"); - var converterObject = editorObject.getConverter(); - converterObject.hooks.chain("preConversion", removeMath); - converterObject.hooks.chain("postConversion", replaceMath); + converter = editorObject.getConverter(); + converter.hooks.chain("preConversion", removeMath); + converter.hooks.chain("postConversion", replaceMath); }; mathJax.onAsyncPreview = function(callback) { afterRefreshCallback = callback; diff --git a/js/extensions/partialRendering.js b/js/extensions/partialRendering.js index d203a006..c9809d92 100644 --- a/js/extensions/partialRendering.js +++ b/js/extensions/partialRendering.js @@ -9,8 +9,46 @@ define([ partialRendering.settingsBlock = partialRenderingSettingsBlockHTML; var converter = undefined; - var sectionList = []; - var convertedSectionsList = []; + var sectionIdGenerator = 0; + var sectionList = [ + { + text: "" + } + ]; + var sectionsToRemove = undefined; + function updateSectionList(newSectionList) { + + // Find modified sections starting from left + 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 right + 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); + var modifiedSections = newSectionList.slice(leftIndex, newSectionList.length + rightIndex); + var rightSections = sectionList.slice(sectionList.length + rightIndex, sectionList.length); + sectionsToRemove = sectionList.slice(leftIndex, sectionList.length + rightIndex); + sectionList = leftSections.concat(modifiedSections).concat(rightSections); + } var hasFootnotes = false; function extractSections(text) { @@ -43,44 +81,78 @@ define([ if(title) { // We just found a title which means end of the previous section if(matchOffset > offset) { - newSectionList.push(text.substring(offset, matchOffset) + "\n" + linkDefinition); + newSectionList.push({ + id: ++sectionIdGenerator, + text: text.substring(offset, matchOffset) + "\n" + linkDefinition + }); offset = matchOffset; } } return ""; }); // Last section - newSectionList.push(text.substring(offset, text.length) + linkDefinition); + newSectionList.push({ + id: ++sectionIdGenerator, + text: text.substring(offset, text.length) + linkDefinition + }); - sectionList = newSectionList; + updateSectionList(newSectionList); } var isRendering = false; + var footnoteContainer = $('
'); + var footnoteContainerFirstChild = $('
').appendTo(footnoteContainer); function renderSections() { - // Renders sections + converter.eltList = []; + // Remove outdated sections + _.each(sectionsToRemove, function(section) { + $("#wmd-preview-section-" + section.id).remove(); + footnoteContainer.find("#footnotes-section-" + section.id).remove(); + }); + var footnoteContainerElt = $("#wmd-preview-section-footnotes"); + footnoteContainerElt.empty(); + + // Renders modified sections isRendering = true; - convertedSectionsList = _.map(sectionList, converter.makeHtml); + var previousSectionElt = $("#wmd-preview"); + var previousFootnoteElt = footnoteContainerFirstChild; + _.each(sectionList, function(section) { + if(section.isConverted === true) { + previousSectionElt = $("#wmd-preview-section-" + section.id); + footnoteContainer.find("#footnotes-section-" + section.id).each(function() { + previousFootnoteElt = $(this); + }); + return; + } + var sectionHtml = converter.makeHtml(section.text); + var sectionElt = $('
').html(sectionHtml); + sectionElt.find("div.footnotes").each(function() { + var footnoteElt = $(this).attr("id", "footnotes-section-" + section.id); + previousFootnoteElt.after(footnoteElt); + previousFootnoteElt = footnoteElt; + }); + previousSectionElt.after(sectionElt); + previousSectionElt = sectionElt; + converter.eltList.push(sectionElt[0]); + section.isConverted = true; + }); isRendering = false; - $("#wmd-preview").html(convertedSectionsList.join("")); - - // Move footnotes in the footer... + // Rewrite footnotes in the footer if(hasFootnotes === true) { // Recreate a footnote list var footnoteElts = $("
    "); - $("#wmd-preview > div.footnotes > ol > li").each(function(index) { + footnoteContainer.find("div.footnotes > ol > li").each(function(index) { hasFootnotes = true; var elt = $(this); - footnoteElts.append(elt); + footnoteElts.append(elt.clone()); // Restore footnotes numbers var refId = "#fnref\\:" + elt.attr("id").substring(3); $(refId).text(index + 1); }); // Append the whole footnotes at the end of the document - $("#wmd-preview > div.footnotes").remove(); - $("#wmd-preview").append($('
    ').append("
    ").append(footnoteElts)); + footnoteContainerElt.html($('
    ').append("
    ").append(footnoteElts)); } - } partialRendering.onEditorConfigure = function(editor) { @@ -96,6 +168,11 @@ define([ $("#wmd-preview").html(renderSections()); }); }; + + partialRendering.onReady = function() { + $("#preview-contents").append($('
    ')); + + }; return partialRendering; }); \ No newline at end of file diff --git a/js/extensions/scrollLink.js b/js/extensions/scrollLink.js index 5242200d..fde37257 100644 --- a/js/extensions/scrollLink.js +++ b/js/extensions/scrollLink.js @@ -70,7 +70,7 @@ define([ var htmlSectionOffset = 0; var previewScrollTop = previewElt.scrollTop(); // Each title element is a section separator - $("#wmd-preview").children("h1,h2,h3,h4,h5,h6").each(function() { + $("#preview-contents > .preview-content").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({ @@ -176,7 +176,7 @@ define([ editor.getConverter().hooks.chain("postConversion", function(text) { // To avoid losing scrolling position before elements are fully // loaded - var previewElt = $("#wmd-preview"); + var previewElt = $("#preview-contents"); previewElt.height(previewElt.height()); return text; }); @@ -184,7 +184,7 @@ define([ scrollLink.onPreviewFinished = function() { // Now set the correct height - $("#wmd-preview").height("auto"); + $("#preview-contents").height("auto"); isScrollEditor = true; buildSections(); }; diff --git a/js/extensions/toc.js b/js/extensions/toc.js index 41d1f105..294953b3 100644 --- a/js/extensions/toc.js +++ b/js/extensions/toc.js @@ -106,7 +106,7 @@ define([ } var elementList = []; - $("#wmd-preview").children("h1, h2, h3, h4, h5, h6").each(function() { + $("#preview-contents > .preview-content").children("h1, h2, h3, h4, h5, h6").each(function() { elementList.push(new TocElement($(this).prop("tagName"), createAnchor($(this)), $(this).text())); }); elementList = groupTags(elementList); @@ -117,9 +117,11 @@ define([ // Run TOC generation when conversion is finished directly on HTML editor.hooks.chain("onPreviewRefresh", function() { var htmlToc = buildToc(); - var html = $("#wmd-preview").html(); - html = html.replace(new RegExp("

    " + toc.config.marker + "<\\/p>", "g"), htmlToc); - $("#wmd-preview").html(html); + $("#preview-contents > .preview-content").each(function() { + var html = $(this).html(); + html = html.replace(new RegExp("

    " + toc.config.marker + "<\\/p>", "g"), htmlToc); + $(this).html(html); + }); $(".table-of-contents").html(htmlToc); }); }; diff --git a/js/publisher.js b/js/publisher.js index 6bee6cfe..ca772aab 100644 --- a/js/publisher.js +++ b/js/publisher.js @@ -120,6 +120,13 @@ define([ publishLocation(callback, errorFlag || error); }); } + + // Get the html from the onPreviewFinished callback + var previewHtml = undefined; + extensionMgr.addHookCallback("onPreviewFinished", function(html) { + previewHtml = html; + }); + var publishRunning = false; publisher.publish = function() { @@ -131,7 +138,7 @@ define([ publishRunning = true; extensionMgr.onPublishRunning(true); publishFileDesc = fileMgr.currentFile; - publishHTML = $("#wmd-preview").html(); + publishHTML = previewHtml; publishAttributesList = _.values(publishFileDesc.publishLocations); publishLocation(function(errorFlag) { publishRunning = false; @@ -190,7 +197,7 @@ define([ // Perform provider's publishing var fileDesc = fileMgr.currentFile; - var html = $("#wmd-preview").html(); + var html = previewHtml; var content = getPublishContent(fileDesc, publishAttributes, html); provider.publish(publishAttributes, fileDesc.title, content, function(error) { if(error === undefined) { @@ -234,14 +241,12 @@ define([ utils.saveAs(content, title + ".md"); }); $(".action-download-html").click(function() { - var content = $("#wmd-preview").html(); var title = fileMgr.currentFile.title; - utils.saveAs(content, title + ".html"); + utils.saveAs(previewHtml, title + ".html"); }); $(".action-download-template").click(function() { var fileDesc = fileMgr.currentFile; - var html = $("#wmd-preview").html(); - var content = publisher.applyTemplate(fileDesc, undefined, html); + var content = publisher.applyTemplate(fileDesc, undefined, previewHtml); utils.saveAs(content, fileDesc.title + (settings.template.indexOf("documentHTML") === -1 ? ".md" : ".html")); }); }); diff --git a/js/sharing.js b/js/sharing.js index e591e345..119364da 100644 --- a/js/sharing.js +++ b/js/sharing.js @@ -98,9 +98,9 @@ define([ if(importParameters === undefined) { return; } - $("#wmd-preview, #file-title").hide(); + $("#preview-contents, #file-title").hide(); provider.importPublic(importParameters, function(error, title, content) { - $("#wmd-preview, #file-title").show(); + $("#preview-contents, #file-title").show(); if(error) { return; } diff --git a/themes/blue-gray/blue-gray.css b/themes/blue-gray/blue-gray.css index f84fa9ee..ad59affe 100644 --- a/themes/blue-gray/blue-gray.css +++ b/themes/blue-gray/blue-gray.css @@ -1,6 +1,6 @@ body, .btn, -#wmd-preview, +#preview-contents, .modal-footer, pre, input[disabled], diff --git a/themes/night/night.css b/themes/night/night.css index 1c6cf878..38b7d220 100644 --- a/themes/night/night.css +++ b/themes/night/night.css @@ -1,6 +1,6 @@ body, .btn, -#wmd-preview, +#preview-contents, .modal-footer, input[disabled], select[disabled], @@ -54,11 +54,11 @@ blockquote { border-color: #333; } -#wmd-preview { +#preview-contents { color: #ccc; } -#wmd-preview blockquote { +#preview-contents blockquote { border-color: #444; } diff --git a/viewer.html b/viewer.html index a7aa6aab..16c96c37 100644 --- a/viewer.html +++ b/viewer.html @@ -76,7 +76,7 @@

    -
    +