Line-Breaking Bugfix: break before an inline element if the first word of the element exceeds the current line

This commit is contained in:
Tobias Hößl 2016-09-05 20:31:43 +02:00
parent b701127f04
commit a341071e91
2 changed files with 63 additions and 20 deletions

View File

@ -51,6 +51,23 @@ angular.module('OpenSlidesApp.motions.lineNumbering', [])
return isLineNumber; return isLineNumber;
}; };
this._createLineBreak = function () {
var br = document.createElement('br');
br.setAttribute('class', 'os-line-break');
return br;
};
this._createLineNumber = function () {
var node = document.createElement('span');
var lineNumber = this._currentLineNumber;
this._currentLineNumber++;
node.setAttribute('class', 'os-line-number line-number-' + lineNumber);
node.setAttribute('data-line-number', lineNumber + '');
node.setAttribute('contenteditable', 'false');
node.innerHTML = ' '; // Prevent tinymce from stripping out empty span's
return node;
};
/** /**
* Splits a TEXT_NODE into an array of TEXT_NODEs and BR-Elements separating them into lines. * Splits a TEXT_NODE into an array of TEXT_NODEs and BR-Elements separating them into lines.
* Each line has a maximum length of 'length', with one exception: spaces are accepted to exceed the length. * Each line has a maximum length of 'length', with one exception: spaces are accepted to exceed the length.
@ -69,28 +86,13 @@ angular.module('OpenSlidesApp.motions.lineNumbering', [])
lastBreakableIndex = null, lastBreakableIndex = null,
service = this; service = this;
var createLineBreak = function() {
var br = document.createElement('br');
br.setAttribute('class', 'os-line-break');
return br;
};
var createLineNumber = function() {
var node = document.createElement('span');
var lineNumber = service._currentLineNumber;
service._currentLineNumber++;
node.setAttribute('class', 'os-line-number line-number-' + lineNumber);
node.setAttribute('data-line-number', lineNumber + '');
node.setAttribute('contenteditable', 'false');
node.innerHTML = ' '; // Prevent tinymce from stripping out empty span's
return node;
};
var addLine = function (text) { var addLine = function (text) {
var newNode = document.createTextNode(text); var newNode = document.createTextNode(text);
if (firstTextNode) { if (firstTextNode) {
firstTextNode = false; firstTextNode = false;
} else { } else {
out.push(createLineBreak()); out.push(service._createLineBreak());
out.push(createLineNumber()); out.push(service._createLineNumber());
} }
out.push(newNode); out.push(newNode);
}; };
@ -101,11 +103,11 @@ angular.module('OpenSlidesApp.motions.lineNumbering', [])
// This happens if a previous inline element exactly stretches to the end of the line // This happens if a previous inline element exactly stretches to the end of the line
if (this._currentInlineOffset >= length) { if (this._currentInlineOffset >= length) {
out.push(createLineBreak()); out.push(service._createLineBreak());
out.push(createLineNumber()); out.push(service._createLineNumber());
this._currentInlineOffset = 0; this._currentInlineOffset = 0;
} else if (this._prependLineNumberToFirstText) { } else if (this._prependLineNumberToFirstText) {
out.push(createLineNumber()); out.push(service._createLineNumber());
} }
this._prependLineNumberToFirstText = false; this._prependLineNumberToFirstText = false;
@ -163,6 +165,17 @@ angular.module('OpenSlidesApp.motions.lineNumbering', [])
} }
}; };
this._lengthOfFirstInlineWord = function (node) {
if (!node.firstChild) {
return 0;
}
if (node.firstChild.nodeType == TEXT_NODE) {
var parts = node.firstChild.nodeValue.split(' ');
return parts[0].length;
} else {
return this._lengthOfFirstInlineWord(node.firstChild);
}
};
this._insertLineNumbersToInlineNode = function (node, length) { this._insertLineNumbersToInlineNode = function (node, length) {
var oldChildren = [], i; var oldChildren = [], i;
@ -181,6 +194,14 @@ angular.module('OpenSlidesApp.motions.lineNumbering', [])
node.appendChild(ret[j]); node.appendChild(ret[j]);
} }
} else if (oldChildren[i].nodeType == ELEMENT_NODE) { } else if (oldChildren[i].nodeType == ELEMENT_NODE) {
var firstword = this._lengthOfFirstInlineWord(oldChildren[i]),
overlength = ((this._currentInlineOffset + firstword) > length && this._currentInlineOffset > 0);
if (overlength && this._isInlineElement(oldChildren[i])) {
this._currentInlineOffset = 0;
node.appendChild(this._createLineBreak());
node.appendChild(this._createLineNumber());
}
var changedNode = this._insertLineNumbersToNode(oldChildren[i], length); var changedNode = this._insertLineNumbersToNode(oldChildren[i], length);
this._moveLeadingLineBreaksToOuterNode(changedNode, node); this._moveLeadingLineBreaksToOuterNode(changedNode, node);
node.appendChild(changedNode); node.appendChild(changedNode);
@ -252,6 +273,14 @@ angular.module('OpenSlidesApp.motions.lineNumbering', [])
node.appendChild(ret[j]); node.appendChild(ret[j]);
} }
} else if (oldChildren[i].nodeType == ELEMENT_NODE) { } else if (oldChildren[i].nodeType == ELEMENT_NODE) {
var firstword = this._lengthOfFirstInlineWord(oldChildren[i]),
overlength = ((this._currentInlineOffset + firstword) > length && this._currentInlineOffset > 0);
if (overlength && this._isInlineElement(oldChildren[i])) {
this._currentInlineOffset = 0;
node.appendChild(this._createLineBreak());
node.appendChild(this._createLineNumber());
}
var changedNode = this._insertLineNumbersToNode(oldChildren[i], length); var changedNode = this._insertLineNumbersToNode(oldChildren[i], length);
this._moveLeadingLineBreaksToOuterNode(changedNode, node); this._moveLeadingLineBreaksToOuterNode(changedNode, node);
node.appendChild(changedNode); node.appendChild(changedNode);

View File

@ -212,5 +212,19 @@ describe('linenumbering', function () {
expect(outHtml).toBe(expected); expect(outHtml).toBe(expected);
expect(lineNumberingService.stripLineNumbers(outHtml)).toBe(inHtml); expect(lineNumberingService.stripLineNumbers(outHtml)).toBe(inHtml);
}); });
it('breaks before an inline element, if the first word of the new inline element is longer than the remaining line (1)', function () {
var inHtml = "<p>Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie <strong>consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio</strong>.</p>";
var outHtml = lineNumberingService.insertLineNumbers(inHtml, 80);
expect(outHtml).toBe('<p>' + noMarkup(1) + 'Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie ' + brMarkup(2) + '<strong>consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan ' + brMarkup(3) + 'et iusto odio</strong>.</p>');
expect(lineNumberingService.stripLineNumbers(outHtml)).toBe(inHtml);
});
it('breaks before an inline element, if the first word of the new inline element is longer than the remaining line (2)', function () {
var inHtml = "<p><span>Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie <strong>consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio</strong>.</span></p>";
var outHtml = lineNumberingService.insertLineNumbers(inHtml, 80);
expect(outHtml).toBe('<p>' + noMarkup(1) + '<span>Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie ' + brMarkup(2) + '<strong>consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan ' + brMarkup(3) + 'et iusto odio</strong>.</span></p>');
expect(lineNumberingService.stripLineNumbers(outHtml)).toBe(inHtml);
});
}); });
}); });