From c3dd1777d253efbc319a88249d5858ddfd99c7fd Mon Sep 17 00:00:00 2001 From: Marcos Caceres Date: Wed, 25 May 2016 19:34:53 +1000 Subject: [PATCH 1/2] Fix(utils): links space getting chopped off (closes #783) --- js/core/utils.js | 147 ++++++++++++++++++---------------- tests/spec/core/utils-spec.js | 31 +++++++ 2 files changed, 109 insertions(+), 69 deletions(-) diff --git a/js/core/utils.js b/js/core/utils.js index c08921bfd7..0e7833c0af 100644 --- a/js/core/utils.js +++ b/js/core/utils.js @@ -13,7 +13,6 @@ define( msg.pub("end", "core/utils"); cb(); } - , /** * Allows a node to be swapped into a different document at * some insertion point(Element). This function is useful for @@ -28,7 +27,7 @@ define( * insertion point (node) - or just appended, if * the element has no children. */ - makeOwnerSwapper: function(node) { + , makeOwnerSwapper: function(node) { if(!(node instanceof Node)){ throw TypeError(); } @@ -43,21 +42,27 @@ define( }; } , calculateLeftPad: function(text) { + if (typeof text !== "string") { + throw new TypeError("Invalid input"); + } var spaceOrTab = /^[\ |\t]*/; // Find smallest padding value var leftPad = text .split("\n") - .filter(function (item){ + .filter(function(item) { return item; }) - .map(function(item){ + .reduce(function(smallest, item) { + // can't go smaller than 0 + if (smallest === 0) { + return smallest; + } var match = item.match(spaceOrTab)[0] || ""; - return (match) ? match.length : 0; - }) - .sort() - .shift(1); - return leftPad || 0; - } + return Math.min(match.length, smallest); + }, +Infinity); + return (leftPad === +Infinity) ? 0 : leftPad; + } + /** * Makes a ES conforming iterator allowing objects to be used with * methods that can interface with Iterators (Array.from(), etc.). @@ -96,6 +101,10 @@ define( throw TypeError("Invalid input"); } + if(text === "\n"){ + return "\n"; + } + function isEmpty(node) { return node.textContent === ""; } @@ -135,68 +144,68 @@ define( .map(function(textNode) { return textNode.textContent; }) - .reduce(function(collector, textContent) { - if (collector) { - return collector; - } - var result = textContent - .split("\n") - .find(function(text) { - var result = /^[\s|\w]+/gm.test(text); - return result; - }); - return result || ""; - }, ""); - var baseCol = this.calculateLeftPad(firstPaddedLine); + .find(function(textContent) { + var result = /^[\#|\s|\w]+/gm.test(textContent); + return result; + }); + // There is no padding, so just return what we started with. + if (!firstPaddedLine) { + return text; + } + var baseColumn = this.calculateLeftPad(firstPaddedLine); + + // Only if we have a baseColumn to work with ... // With only the text nodes that are not children of pre elements, // we left align all those text nodes. - Array - .from(doc.body.childNodes) - .filter(isTextNode) - .filter(function(textNode) { - // 🎵 Hey, processor! Leave those pre's alone! 🎵 - return !filterParentIsPre(textNode); - }) - .filter(function(textNode) { - // we don't care about last nodes that are just white space - var isLastChild = textNode.parentElement.lastChild === textNode; - var isJustWS = isWhiteSpace(textNode); - return !(isLastChild && isJustWS); - }) - .map(function toTrimmedTextNode(textNode) { - var rawText = textNode.textContent; - // We remove tailing space on the right, which is just there - // to pad out tags like: - //
- //
- // Next line has 2 spaces hidden! - // __
- //
- // - var trimmedRight = rawText.trimRight(); - var trimBy = this.calculateLeftPad(trimmedRight) || baseCol; - if (!trimBy) { - return null; //nothing to do - } - var exp = "^ {" + trimBy + "}"; - var startTrim = new RegExp(exp, "gm"); - var trimmedText = (trimBy) ? rawText.replace(startTrim, "") : rawText; - var newNode = textNode.ownerDocument.createTextNode(trimmedText); - // We can then swap the old with the new - return { - oldNode: textNode, - newNode: newNode, - }; - }.bind(this)) - .filter(function(nodes) { - return nodes; - }) - .forEach(function(nodes) { - var oldNode = nodes.oldNode; - var newNode = nodes.newNode; - oldNode.parentElement.replaceChild(newNode, oldNode); - }); + if(baseColumn){ + Array + .from(doc.body.childNodes) + .filter(isTextNode) + .filter(function(textNode) { + // 🎵 Hey, processor! Leave those pre's alone! 🎵 + return !filterParentIsPre(textNode); + }) + .filter(function(textNode) { + // we don't care about last nodes that are just white space + var isLastChild = textNode.parentElement.lastChild === textNode; + var isJustWS = isWhiteSpace(textNode); + return !(isLastChild && isJustWS); + }) + .map(function toTrimmedTextNode(textNode) { + var rawText = textNode.textContent; + // We remove tailing space on the right, which is just there + // to pad out tags like: + //
+ //
+ // Next line has 2 spaces hidden! + // __
+ //
+ // + var trimmedRight = rawText.trimRight(); + var trimBy = this.calculateLeftPad(trimmedRight) || baseColumn; + if (!trimBy) { + return null; //nothing to do + } + var exp = "^ {" + trimBy + "}"; + var startTrim = new RegExp(exp, "gm"); + var trimmedText = (trimBy) ? rawText.replace(startTrim, "") : rawText; + var newNode = textNode.ownerDocument.createTextNode(trimmedText); + // We can then swap the old with the new + return { + oldNode: textNode, + newNode: newNode, + }; + }.bind(this)) + .filter(function(nodes) { + return nodes; + }) + .forEach(function(nodes) { + var oldNode = nodes.oldNode; + var newNode = nodes.newNode; + oldNode.parentElement.replaceChild(newNode, oldNode); + }); + } var nodeIterator = doc.createNodeIterator(doc.body, NodeFilter.SHOW_TEXT, filterLastChildIsPadding); var iterable = this.toESIterable(nodeIterator.nextNode.bind(nodeIterator)); // Remove trailing whitespace nodes diff --git a/tests/spec/core/utils-spec.js b/tests/spec/core/utils-spec.js index f2d0c72df1..a75b07962b 100644 --- a/tests/spec/core/utils-spec.js +++ b/tests/spec/core/utils-spec.js @@ -8,6 +8,37 @@ describe("Core - Utils", function() { }); }); + describe("calculateLeftPad()", function(){ + it("throws given invalid input", function(){ + expect(function(){ + expect(utils.calculateLeftPad()); + }).toThrow(); + expect(function(){ + expect(utils.calculateLeftPad({})); + }).toThrow(); + expect(function(){ + expect(utils.calculateLeftPad(123)); + }).toThrow(); + expect(function(){ + expect(utils.calculateLeftPad(null)); + }).toThrow(); + }); + it("calculates the smallest left padding of multiline text", function(done){ + expect(utils.calculateLeftPad("")).toEqual(0); + expect(utils.calculateLeftPad("\n \n ")).toEqual(2); + expect(utils.calculateLeftPad(" ")).toEqual(25); + expect(utils.calculateLeftPad(" a ")).toEqual(1); + expect(utils.calculateLeftPad(" \n a ")).toEqual(1); + expect(utils.calculateLeftPad(" \n a ")).toEqual(1); + expect(utils.calculateLeftPad("\n \n \n ")).toEqual(4); + expect(utils.calculateLeftPad("\n \n \n ")).toEqual(2); + expect(utils.calculateLeftPad("\n \n \n \n ")).toEqual(2); + expect(utils.calculateLeftPad("\n\n\n\n\n\n\n\n\n\n")).toEqual(0); + expect(utils.calculateLeftPad(" \n\n\n\n\n \n\n\n\n\n ")).toEqual(2); + done(); + }); + }); + describe("makeOwnerSwapper()", function() { it("throws if passed something that is not a node", function(done) { expect(function() { From d7c68c38faf21e548cd049063b17f722c505cca0 Mon Sep 17 00:00:00 2001 From: Marcos Caceres Date: Wed, 25 May 2016 20:56:47 +1000 Subject: [PATCH 2/2] Fix(markdown): don't add space after quot char --- js/core/markdown.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/js/core/markdown.js b/js/core/markdown.js index 530d912b4e..0a005e92f3 100644 --- a/js/core/markdown.js +++ b/js/core/markdown.js @@ -261,7 +261,11 @@ define([ processBlockLevelElements(newBody); var dirtyHTML = toHTML(newBody.innerHTML); // Markdown parsing sometimes inserts empty p tags - var cleanHTML = dirtyHTML.replace(/

\s*<\/p>/gm, ""); + var cleanHTML = dirtyHTML + .replace(/

\s*<\/p>/gm, "") + // beautifer has a bad time with "\n"