Caching results of insertLineNumbers and extractRangeByLineNumbers
This commit is contained in:
parent
4d48f2d8a5
commit
36e519a798
File diff suppressed because it is too large
Load Diff
@ -14,369 +14,398 @@ angular.module('OpenSlidesApp.motions.lineNumbering', [])
|
|||||||
* No constructs like <a...><div></div></a> are allowed. CSS-attributes like 'display: block' are ignored.
|
* No constructs like <a...><div></div></a> are allowed. CSS-attributes like 'display: block' are ignored.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.service('lineNumberingService', function () {
|
.service('lineNumberingService', [
|
||||||
var ELEMENT_NODE = 1,
|
'$cacheFactory',
|
||||||
TEXT_NODE = 3;
|
function ($cacheFactory) {
|
||||||
|
var ELEMENT_NODE = 1,
|
||||||
|
TEXT_NODE = 3;
|
||||||
|
|
||||||
this._currentInlineOffset = null;
|
this._currentInlineOffset = null;
|
||||||
this._currentLineNumber = null;
|
this._currentLineNumber = null;
|
||||||
this._prependLineNumberToFirstText = false;
|
this._prependLineNumberToFirstText = false;
|
||||||
|
|
||||||
this._isInlineElement = function (node) {
|
var lineNumberCache = $cacheFactory('linenumbering.service');
|
||||||
var inlineElements = [
|
|
||||||
'SPAN', 'A', 'EM', 'S', 'B', 'I', 'STRONG', 'U', 'BIG', 'SMALL', 'SUB', 'SUP', 'TT'
|
|
||||||
];
|
|
||||||
return (inlineElements.indexOf(node.nodeName) > -1);
|
|
||||||
};
|
|
||||||
|
|
||||||
this._isOsLineBreakNode = function (node) {
|
this.djb2hash = function(str) {
|
||||||
var isLineBreak = false;
|
var hash = 5381, char;
|
||||||
if (node && node.nodeType === ELEMENT_NODE && node.nodeName == 'BR' && node.hasAttribute('class')) {
|
for (var i = 0; i < str.length; i++) {
|
||||||
var classes = node.getAttribute('class').split(' ');
|
char = str.charCodeAt(i);
|
||||||
if (classes.indexOf('os-line-break') > -1) {
|
hash = ((hash << 5) + hash) + char;
|
||||||
isLineBreak = true;
|
|
||||||
}
|
}
|
||||||
}
|
return hash.toString();
|
||||||
return isLineBreak;
|
|
||||||
};
|
|
||||||
|
|
||||||
this._isOsLineNumberNode = function (node) {
|
|
||||||
var isLineNumber = false;
|
|
||||||
if (node && node.nodeType === ELEMENT_NODE && node.nodeName == 'SPAN' && node.hasAttribute('class')) {
|
|
||||||
var classes = node.getAttribute('class').split(' ');
|
|
||||||
if (classes.indexOf('os-line-number') > -1) {
|
|
||||||
isLineNumber = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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('name', 'L' + 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.
|
|
||||||
* Each line has a maximum length of 'length', with one exception: spaces are accepted to exceed the length.
|
|
||||||
* Otherwise the string is split by the last space or dash in the line.
|
|
||||||
*
|
|
||||||
* @param node
|
|
||||||
* @param length
|
|
||||||
* @param highlight
|
|
||||||
* @returns Array
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
this._textNodeToLines = function (node, length, highlight) {
|
|
||||||
var out = [],
|
|
||||||
currLineStart = 0,
|
|
||||||
i = 0,
|
|
||||||
firstTextNode = true,
|
|
||||||
lastBreakableIndex = null,
|
|
||||||
service = this;
|
|
||||||
var addLine = function (text, highlight) {
|
|
||||||
var node;
|
|
||||||
if (typeof highlight === 'undefined') {
|
|
||||||
highlight = -1;
|
|
||||||
}
|
|
||||||
if (firstTextNode) {
|
|
||||||
if (highlight == service._currentLineNumber - 1) {
|
|
||||||
node = document.createElement('span');
|
|
||||||
node.setAttribute('class', 'highlight');
|
|
||||||
node.innerHTML = text;
|
|
||||||
} else {
|
|
||||||
node = document.createTextNode(text);
|
|
||||||
}
|
|
||||||
firstTextNode = false;
|
|
||||||
} else {
|
|
||||||
if (service._currentLineNumber == highlight) {
|
|
||||||
node = document.createElement('span');
|
|
||||||
node.setAttribute('class', 'highlight');
|
|
||||||
node.innerHTML = text;
|
|
||||||
} else {
|
|
||||||
node = document.createTextNode(text);
|
|
||||||
}
|
|
||||||
out.push(service._createLineBreak());
|
|
||||||
out.push(service._createLineNumber());
|
|
||||||
}
|
|
||||||
out.push(node);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (node.nodeValue == "\n") {
|
this._isInlineElement = function (node) {
|
||||||
out.push(node);
|
var inlineElements = [
|
||||||
} else {
|
'SPAN', 'A', 'EM', 'S', 'B', 'I', 'STRONG', 'U', 'BIG', 'SMALL', 'SUB', 'SUP', 'TT'
|
||||||
|
];
|
||||||
|
return (inlineElements.indexOf(node.nodeName) > -1);
|
||||||
|
};
|
||||||
|
|
||||||
// This happens if a previous inline element exactly stretches to the end of the line
|
this._isOsLineBreakNode = function (node) {
|
||||||
if (this._currentInlineOffset >= length) {
|
var isLineBreak = false;
|
||||||
out.push(service._createLineBreak());
|
if (node && node.nodeType === ELEMENT_NODE && node.nodeName == 'BR' && node.hasAttribute('class')) {
|
||||||
out.push(service._createLineNumber());
|
var classes = node.getAttribute('class').split(' ');
|
||||||
this._currentInlineOffset = 0;
|
if (classes.indexOf('os-line-break') > -1) {
|
||||||
} else if (this._prependLineNumberToFirstText) {
|
isLineBreak = true;
|
||||||
out.push(service._createLineNumber());
|
}
|
||||||
}
|
}
|
||||||
this._prependLineNumberToFirstText = false;
|
return isLineBreak;
|
||||||
|
};
|
||||||
|
|
||||||
while (i < node.nodeValue.length) {
|
this._isOsLineNumberNode = function (node) {
|
||||||
var lineBreakAt = null;
|
var isLineNumber = false;
|
||||||
if (this._currentInlineOffset >= length) {
|
if (node && node.nodeType === ELEMENT_NODE && node.nodeName == 'SPAN' && node.hasAttribute('class')) {
|
||||||
if (lastBreakableIndex !== null) {
|
var classes = node.getAttribute('class').split(' ');
|
||||||
lineBreakAt = lastBreakableIndex;
|
if (classes.indexOf('os-line-number') > -1) {
|
||||||
|
isLineNumber = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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('name', 'L' + 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.
|
||||||
|
* Each line has a maximum length of 'length', with one exception: spaces are accepted to exceed the length.
|
||||||
|
* Otherwise the string is split by the last space or dash in the line.
|
||||||
|
*
|
||||||
|
* @param node
|
||||||
|
* @param length
|
||||||
|
* @param highlight
|
||||||
|
* @returns Array
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
this._textNodeToLines = function (node, length, highlight) {
|
||||||
|
var out = [],
|
||||||
|
currLineStart = 0,
|
||||||
|
i = 0,
|
||||||
|
firstTextNode = true,
|
||||||
|
lastBreakableIndex = null,
|
||||||
|
service = this;
|
||||||
|
var addLine = function (text, highlight) {
|
||||||
|
var node;
|
||||||
|
if (typeof highlight === 'undefined') {
|
||||||
|
highlight = -1;
|
||||||
|
}
|
||||||
|
if (firstTextNode) {
|
||||||
|
if (highlight == service._currentLineNumber - 1) {
|
||||||
|
node = document.createElement('span');
|
||||||
|
node.setAttribute('class', 'highlight');
|
||||||
|
node.innerHTML = text;
|
||||||
} else {
|
} else {
|
||||||
lineBreakAt = i - 1;
|
node = document.createTextNode(text);
|
||||||
}
|
}
|
||||||
|
firstTextNode = false;
|
||||||
|
} else {
|
||||||
|
if (service._currentLineNumber == highlight) {
|
||||||
|
node = document.createElement('span');
|
||||||
|
node.setAttribute('class', 'highlight');
|
||||||
|
node.innerHTML = text;
|
||||||
|
} else {
|
||||||
|
node = document.createTextNode(text);
|
||||||
|
}
|
||||||
|
out.push(service._createLineBreak());
|
||||||
|
out.push(service._createLineNumber());
|
||||||
}
|
}
|
||||||
if (lineBreakAt !== null && node.nodeValue[i] != ' ') {
|
out.push(node);
|
||||||
var currLine = node.nodeValue.substring(currLineStart, lineBreakAt + 1);
|
};
|
||||||
addLine(currLine, highlight);
|
|
||||||
|
|
||||||
currLineStart = lineBreakAt + 1;
|
if (node.nodeValue == "\n") {
|
||||||
this._currentInlineOffset = i - lineBreakAt - 1;
|
out.push(node);
|
||||||
lastBreakableIndex = null;
|
} else {
|
||||||
}
|
|
||||||
|
|
||||||
if (node.nodeValue[i] == ' ' || node.nodeValue[i] == '-') {
|
// This happens if a previous inline element exactly stretches to the end of the line
|
||||||
lastBreakableIndex = i;
|
if (this._currentInlineOffset >= length) {
|
||||||
}
|
out.push(service._createLineBreak());
|
||||||
|
out.push(service._createLineNumber());
|
||||||
this._currentInlineOffset++;
|
|
||||||
i++;
|
|
||||||
|
|
||||||
}
|
|
||||||
addLine(node.nodeValue.substring(currLineStart), highlight);
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Moves line breaking and line numbering markup before inline elements
|
|
||||||
*
|
|
||||||
* @param innerNode
|
|
||||||
* @param outerNode
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
this._moveLeadingLineBreaksToOuterNode = function (innerNode, outerNode) {
|
|
||||||
if (this._isInlineElement(innerNode)) {
|
|
||||||
if (this._isOsLineBreakNode(innerNode.firstChild)) {
|
|
||||||
var br = innerNode.firstChild;
|
|
||||||
innerNode.removeChild(br);
|
|
||||||
outerNode.appendChild(br);
|
|
||||||
}
|
|
||||||
if (this._isOsLineNumberNode(innerNode.firstChild)) {
|
|
||||||
var span = innerNode.firstChild;
|
|
||||||
innerNode.removeChild(span);
|
|
||||||
outerNode.appendChild(span);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
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, highlight) {
|
|
||||||
var oldChildren = [], i;
|
|
||||||
for (i = 0; i < node.childNodes.length; i++) {
|
|
||||||
oldChildren.push(node.childNodes[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (node.firstChild) {
|
|
||||||
node.removeChild(node.firstChild);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < oldChildren.length; i++) {
|
|
||||||
if (oldChildren[i].nodeType == TEXT_NODE) {
|
|
||||||
var ret = this._textNodeToLines(oldChildren[i], length, highlight);
|
|
||||||
for (var j = 0; j < ret.length; j++) {
|
|
||||||
node.appendChild(ret[j]);
|
|
||||||
}
|
|
||||||
} 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;
|
this._currentInlineOffset = 0;
|
||||||
node.appendChild(this._createLineBreak());
|
} else if (this._prependLineNumberToFirstText) {
|
||||||
node.appendChild(this._createLineNumber());
|
out.push(service._createLineNumber());
|
||||||
}
|
}
|
||||||
var changedNode = this._insertLineNumbersToNode(oldChildren[i], length, highlight);
|
this._prependLineNumberToFirstText = false;
|
||||||
this._moveLeadingLineBreaksToOuterNode(changedNode, node);
|
|
||||||
node.appendChild(changedNode);
|
|
||||||
} else {
|
|
||||||
throw 'Unknown nodeType: ' + i + ': ' + oldChildren[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return node;
|
while (i < node.nodeValue.length) {
|
||||||
};
|
var lineBreakAt = null;
|
||||||
|
if (this._currentInlineOffset >= length) {
|
||||||
this._calcBlockNodeLength = function (node, oldLength) {
|
if (lastBreakableIndex !== null) {
|
||||||
var newLength = oldLength;
|
lineBreakAt = lastBreakableIndex;
|
||||||
switch (node.nodeName) {
|
} else {
|
||||||
case 'LI':
|
lineBreakAt = i - 1;
|
||||||
newLength -= 5;
|
}
|
||||||
break;
|
|
||||||
case 'BLOCKQUOTE':
|
|
||||||
newLength -= 20;
|
|
||||||
break;
|
|
||||||
case 'DIV':
|
|
||||||
case 'P':
|
|
||||||
var styles = node.getAttribute("style"),
|
|
||||||
padding = 0;
|
|
||||||
if (styles) {
|
|
||||||
var leftpad = styles.split("padding-left:");
|
|
||||||
if (leftpad.length > 1) {
|
|
||||||
leftpad = parseInt(leftpad[1]);
|
|
||||||
padding += leftpad;
|
|
||||||
}
|
}
|
||||||
var rightpad = styles.split("padding-right:");
|
if (lineBreakAt !== null && node.nodeValue[i] != ' ') {
|
||||||
if (rightpad.length > 1) {
|
var currLine = node.nodeValue.substring(currLineStart, lineBreakAt + 1);
|
||||||
rightpad = parseInt(rightpad[1]);
|
addLine(currLine, highlight);
|
||||||
padding += rightpad;
|
|
||||||
|
currLineStart = lineBreakAt + 1;
|
||||||
|
this._currentInlineOffset = i - lineBreakAt - 1;
|
||||||
|
lastBreakableIndex = null;
|
||||||
}
|
}
|
||||||
newLength -= (padding / 5);
|
|
||||||
|
if (node.nodeValue[i] == ' ' || node.nodeValue[i] == '-') {
|
||||||
|
lastBreakableIndex = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._currentInlineOffset++;
|
||||||
|
i++;
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
addLine(node.nodeValue.substring(currLineStart), highlight);
|
||||||
case 'H1':
|
}
|
||||||
newLength *= 0.5;
|
return out;
|
||||||
break;
|
};
|
||||||
case 'H2':
|
|
||||||
newLength *= 0.66;
|
|
||||||
break;
|
|
||||||
case 'H3':
|
|
||||||
newLength *= 0.66;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return Math.ceil(newLength);
|
|
||||||
};
|
|
||||||
|
|
||||||
this._insertLineNumbersToBlockNode = function (node, length, highlight) {
|
|
||||||
this._currentInlineOffset = 0;
|
|
||||||
this._prependLineNumberToFirstText = true;
|
|
||||||
|
|
||||||
var oldChildren = [], i;
|
/**
|
||||||
for (i = 0; i < node.childNodes.length; i++) {
|
* Moves line breaking and line numbering markup before inline elements
|
||||||
oldChildren.push(node.childNodes[i]);
|
*
|
||||||
}
|
* @param innerNode
|
||||||
|
* @param outerNode
|
||||||
while (node.firstChild) {
|
* @private
|
||||||
node.removeChild(node.firstChild);
|
*/
|
||||||
}
|
this._moveLeadingLineBreaksToOuterNode = function (innerNode, outerNode) {
|
||||||
|
if (this._isInlineElement(innerNode)) {
|
||||||
for (i = 0; i < oldChildren.length; i++) {
|
if (this._isOsLineBreakNode(innerNode.firstChild)) {
|
||||||
if (oldChildren[i].nodeType == TEXT_NODE) {
|
var br = innerNode.firstChild;
|
||||||
var ret = this._textNodeToLines(oldChildren[i], length, highlight);
|
innerNode.removeChild(br);
|
||||||
for (var j = 0; j < ret.length; j++) {
|
outerNode.appendChild(br);
|
||||||
node.appendChild(ret[j]);
|
|
||||||
}
|
}
|
||||||
} else if (oldChildren[i].nodeType == ELEMENT_NODE) {
|
if (this._isOsLineNumberNode(innerNode.firstChild)) {
|
||||||
var firstword = this._lengthOfFirstInlineWord(oldChildren[i]),
|
var span = innerNode.firstChild;
|
||||||
overlength = ((this._currentInlineOffset + firstword) > length && this._currentInlineOffset > 0);
|
innerNode.removeChild(span);
|
||||||
if (overlength && this._isInlineElement(oldChildren[i])) {
|
outerNode.appendChild(span);
|
||||||
this._currentInlineOffset = 0;
|
|
||||||
node.appendChild(this._createLineBreak());
|
|
||||||
node.appendChild(this._createLineNumber());
|
|
||||||
}
|
}
|
||||||
var changedNode = this._insertLineNumbersToNode(oldChildren[i], length, highlight);
|
}
|
||||||
this._moveLeadingLineBreaksToOuterNode(changedNode, node);
|
};
|
||||||
node.appendChild(changedNode);
|
|
||||||
|
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 {
|
} else {
|
||||||
throw 'Unknown nodeType: ' + i + ': ' + oldChildren[i];
|
return this._lengthOfFirstInlineWord(node.firstChild);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
this._currentInlineOffset = 0;
|
this._insertLineNumbersToInlineNode = function (node, length, highlight) {
|
||||||
this._prependLineNumberToFirstText = true;
|
var oldChildren = [], i;
|
||||||
|
for (i = 0; i < node.childNodes.length; i++) {
|
||||||
|
oldChildren.push(node.childNodes[i]);
|
||||||
|
}
|
||||||
|
|
||||||
return node;
|
while (node.firstChild) {
|
||||||
};
|
node.removeChild(node.firstChild);
|
||||||
|
}
|
||||||
|
|
||||||
this._insertLineNumbersToNode = function (node, length, highlight) {
|
for (i = 0; i < oldChildren.length; i++) {
|
||||||
if (node.nodeType !== ELEMENT_NODE) {
|
if (oldChildren[i].nodeType == TEXT_NODE) {
|
||||||
throw 'This method may only be called for ELEMENT-nodes: ' + node.nodeValue;
|
var ret = this._textNodeToLines(oldChildren[i], length, highlight);
|
||||||
}
|
for (var j = 0; j < ret.length; j++) {
|
||||||
if (this._isInlineElement(node)) {
|
node.appendChild(ret[j]);
|
||||||
return this._insertLineNumbersToInlineNode(node, length, highlight);
|
}
|
||||||
} else {
|
} else if (oldChildren[i].nodeType == ELEMENT_NODE) {
|
||||||
var newLength = this._calcBlockNodeLength(node, length);
|
var firstword = this._lengthOfFirstInlineWord(oldChildren[i]),
|
||||||
return this._insertLineNumbersToBlockNode(node, newLength, highlight);
|
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, highlight);
|
||||||
|
this._moveLeadingLineBreaksToOuterNode(changedNode, node);
|
||||||
|
node.appendChild(changedNode);
|
||||||
|
} else {
|
||||||
|
throw 'Unknown nodeType: ' + i + ': ' + oldChildren[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this._stripLineNumbers = function (node) {
|
return node;
|
||||||
|
};
|
||||||
|
|
||||||
for (var i = 0; i < node.childNodes.length; i++) {
|
this._calcBlockNodeLength = function (node, oldLength) {
|
||||||
if (this._isOsLineBreakNode(node.childNodes[i]) || this._isOsLineNumberNode(node.childNodes[i])) {
|
var newLength = oldLength;
|
||||||
node.removeChild(node.childNodes[i]);
|
switch (node.nodeName) {
|
||||||
i--;
|
case 'LI':
|
||||||
|
newLength -= 5;
|
||||||
|
break;
|
||||||
|
case 'BLOCKQUOTE':
|
||||||
|
newLength -= 20;
|
||||||
|
break;
|
||||||
|
case 'DIV':
|
||||||
|
case 'P':
|
||||||
|
var styles = node.getAttribute("style"),
|
||||||
|
padding = 0;
|
||||||
|
if (styles) {
|
||||||
|
var leftpad = styles.split("padding-left:");
|
||||||
|
if (leftpad.length > 1) {
|
||||||
|
leftpad = parseInt(leftpad[1]);
|
||||||
|
padding += leftpad;
|
||||||
|
}
|
||||||
|
var rightpad = styles.split("padding-right:");
|
||||||
|
if (rightpad.length > 1) {
|
||||||
|
rightpad = parseInt(rightpad[1]);
|
||||||
|
padding += rightpad;
|
||||||
|
}
|
||||||
|
newLength -= (padding / 5);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'H1':
|
||||||
|
newLength *= 0.5;
|
||||||
|
break;
|
||||||
|
case 'H2':
|
||||||
|
newLength *= 0.66;
|
||||||
|
break;
|
||||||
|
case 'H3':
|
||||||
|
newLength *= 0.66;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return Math.ceil(newLength);
|
||||||
|
};
|
||||||
|
|
||||||
|
this._insertLineNumbersToBlockNode = function (node, length, highlight) {
|
||||||
|
this._currentInlineOffset = 0;
|
||||||
|
this._prependLineNumberToFirstText = true;
|
||||||
|
|
||||||
|
var oldChildren = [], i;
|
||||||
|
for (i = 0; i < node.childNodes.length; i++) {
|
||||||
|
oldChildren.push(node.childNodes[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (node.firstChild) {
|
||||||
|
node.removeChild(node.firstChild);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < oldChildren.length; i++) {
|
||||||
|
if (oldChildren[i].nodeType == TEXT_NODE) {
|
||||||
|
var ret = this._textNodeToLines(oldChildren[i], length, highlight);
|
||||||
|
for (var j = 0; j < ret.length; j++) {
|
||||||
|
node.appendChild(ret[j]);
|
||||||
|
}
|
||||||
|
} 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, highlight);
|
||||||
|
this._moveLeadingLineBreaksToOuterNode(changedNode, node);
|
||||||
|
node.appendChild(changedNode);
|
||||||
|
} else {
|
||||||
|
throw 'Unknown nodeType: ' + i + ': ' + oldChildren[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this._currentInlineOffset = 0;
|
||||||
|
this._prependLineNumberToFirstText = true;
|
||||||
|
|
||||||
|
return node;
|
||||||
|
};
|
||||||
|
|
||||||
|
this._insertLineNumbersToNode = function (node, length, highlight) {
|
||||||
|
if (node.nodeType !== ELEMENT_NODE) {
|
||||||
|
throw 'This method may only be called for ELEMENT-nodes: ' + node.nodeValue;
|
||||||
|
}
|
||||||
|
if (this._isInlineElement(node)) {
|
||||||
|
return this._insertLineNumbersToInlineNode(node, length, highlight);
|
||||||
} else {
|
} else {
|
||||||
this._stripLineNumbers(node.childNodes[i]);
|
var newLength = this._calcBlockNodeLength(node, length);
|
||||||
|
return this._insertLineNumbersToBlockNode(node, newLength, highlight);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
};
|
|
||||||
|
|
||||||
this._nodesToHtml = function (nodes) {
|
this._stripLineNumbers = function (node) {
|
||||||
var root = document.createElement('div');
|
|
||||||
for (var i in nodes) {
|
for (var i = 0; i < node.childNodes.length; i++) {
|
||||||
if (nodes.hasOwnProperty(i)) {
|
if (this._isOsLineBreakNode(node.childNodes[i]) || this._isOsLineNumberNode(node.childNodes[i])) {
|
||||||
root.appendChild(nodes[i]);
|
node.removeChild(node.childNodes[i]);
|
||||||
|
i--;
|
||||||
|
} else {
|
||||||
|
this._stripLineNumbers(node.childNodes[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
return root.innerHTML;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.insertLineNumbersNode = function (html, lineLength, highlight, firstLine) {
|
this._nodesToHtml = function (nodes) {
|
||||||
var root = document.createElement('div');
|
var root = document.createElement('div');
|
||||||
root.innerHTML = html;
|
for (var i in nodes) {
|
||||||
|
if (nodes.hasOwnProperty(i)) {
|
||||||
|
root.appendChild(nodes[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return root.innerHTML;
|
||||||
|
};
|
||||||
|
|
||||||
this._currentInlineOffset = 0;
|
this.insertLineNumbersNode = function (html, lineLength, highlight, firstLine) {
|
||||||
if (firstLine) {
|
var root = document.createElement('div');
|
||||||
this._currentLineNumber = firstLine;
|
root.innerHTML = html;
|
||||||
} else {
|
|
||||||
this._currentLineNumber = 1;
|
|
||||||
}
|
|
||||||
this._prependLineNumberToFirstText = true;
|
|
||||||
|
|
||||||
return this._insertLineNumbersToNode(root, lineLength, highlight);
|
this._currentInlineOffset = 0;
|
||||||
};
|
if (firstLine) {
|
||||||
|
this._currentLineNumber = firstLine;
|
||||||
|
} else {
|
||||||
|
this._currentLineNumber = 1;
|
||||||
|
}
|
||||||
|
this._prependLineNumberToFirstText = true;
|
||||||
|
|
||||||
this.insertLineNumbers = function (html, lineLength, highlight, callback, firstLine) {
|
return this._insertLineNumbersToNode(root, lineLength, highlight);
|
||||||
var newRoot = this.insertLineNumbersNode(html, lineLength, highlight, firstLine);
|
};
|
||||||
|
|
||||||
if (callback) {
|
this.insertLineNumbers = function (html, lineLength, highlight, callback, firstLine) {
|
||||||
callback();
|
var newHtml, newRoot;
|
||||||
}
|
|
||||||
|
|
||||||
return newRoot.innerHTML;
|
if (highlight > 0) {
|
||||||
};
|
// Caching versions with highlighted line numbers is probably not worth it
|
||||||
|
newRoot = this.insertLineNumbersNode(html, lineLength, highlight, firstLine);
|
||||||
|
newHtml = newRoot.innerHTML;
|
||||||
|
} else {
|
||||||
|
var cacheKey = this.djb2hash(html);
|
||||||
|
newHtml = lineNumberCache.get(cacheKey);
|
||||||
|
|
||||||
this.stripLineNumbers = function (html) {
|
if (angular.isUndefined(newHtml)) {
|
||||||
var root = document.createElement('div');
|
newRoot = this.insertLineNumbersNode(html, lineLength, highlight, firstLine);
|
||||||
root.innerHTML = html;
|
newHtml = newRoot.innerHTML;
|
||||||
this._stripLineNumbers(root);
|
lineNumberCache.put(cacheKey, newHtml);
|
||||||
return root.innerHTML;
|
}
|
||||||
};
|
}
|
||||||
});
|
|
||||||
|
if (callback) {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
return newHtml;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.stripLineNumbers = function (html) {
|
||||||
|
var root = document.createElement('div');
|
||||||
|
root.innerHTML = html;
|
||||||
|
this._stripLineNumbers(root);
|
||||||
|
return root.innerHTML;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
}());
|
}());
|
||||||
|
Loading…
Reference in New Issue
Block a user