Merge pull request #3096 from CatoTH/Issue3077-highlight-inline-diff
Add an explicit line highlighting function for the diff
This commit is contained in:
commit
42cf987aed
@ -331,7 +331,7 @@ angular.module('OpenSlidesApp.motions', [
|
|||||||
text = '';
|
text = '';
|
||||||
for (var i = 0; i < changes.length; i++) {
|
for (var i = 0; i < changes.length; i++) {
|
||||||
text += this.getTextBetweenChangeRecommendations(versionId, (i === 0 ? null : changes[i - 1]), changes[i], highlight);
|
text += this.getTextBetweenChangeRecommendations(versionId, (i === 0 ? null : changes[i - 1]), changes[i], highlight);
|
||||||
text += changes[i].getDiff(this, versionId);
|
text += changes[i].getDiff(this, versionId, highlight);
|
||||||
}
|
}
|
||||||
text += this.getTextRemainderAfterLastChangeRecommendation(versionId, changes);
|
text += this.getTextRemainderAfterLastChangeRecommendation(versionId, changes);
|
||||||
break;
|
break;
|
||||||
@ -740,7 +740,13 @@ angular.module('OpenSlidesApp.motions', [
|
|||||||
oldText = data.outerContextStart + data.innerContextStart +
|
oldText = data.outerContextStart + data.innerContextStart +
|
||||||
data.html + data.innerContextEnd + data.outerContextEnd;
|
data.html + data.innerContextEnd + data.outerContextEnd;
|
||||||
|
|
||||||
return diffService.diff(oldText, this.text, lineLength, this.line_from);
|
var diff = diffService.diff(oldText, this.text, lineLength, this.line_from);
|
||||||
|
|
||||||
|
if (highlight > 0) {
|
||||||
|
diff = lineNumberingService.highlightLine(diff, highlight);
|
||||||
|
}
|
||||||
|
|
||||||
|
return diff;
|
||||||
},
|
},
|
||||||
getType: function(original_full_html) {
|
getType: function(original_full_html) {
|
||||||
return this.type;
|
return this.type;
|
||||||
|
@ -71,6 +71,32 @@ angular.module('OpenSlidesApp.motions.lineNumbering', [])
|
|||||||
return isLineNumber;
|
return isLineNumber;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this._getLineNumberNode = function(fragment, lineNumber) {
|
||||||
|
return fragment.querySelector('.os-line-number.line-number-' + lineNumber);
|
||||||
|
};
|
||||||
|
|
||||||
|
this._htmlToFragment = function(html) {
|
||||||
|
var fragment = document.createDocumentFragment(),
|
||||||
|
div = document.createElement('DIV');
|
||||||
|
div.innerHTML = html;
|
||||||
|
while (div.childElementCount) {
|
||||||
|
var child = div.childNodes[0];
|
||||||
|
div.removeChild(child);
|
||||||
|
fragment.appendChild(child);
|
||||||
|
}
|
||||||
|
return fragment;
|
||||||
|
};
|
||||||
|
|
||||||
|
this._fragmentToHtml = function(fragment) {
|
||||||
|
var div = document.createElement('DIV');
|
||||||
|
while (fragment.firstChild) {
|
||||||
|
var child = fragment.firstChild;
|
||||||
|
fragment.removeChild(child);
|
||||||
|
div.appendChild(child);
|
||||||
|
}
|
||||||
|
return div.innerHTML;
|
||||||
|
};
|
||||||
|
|
||||||
this._createLineBreak = function () {
|
this._createLineBreak = function () {
|
||||||
var br = document.createElement('br');
|
var br = document.createElement('br');
|
||||||
br.setAttribute('class', 'os-line-break');
|
br.setAttribute('class', 'os-line-break');
|
||||||
@ -413,6 +439,15 @@ angular.module('OpenSlidesApp.motions.lineNumbering', [])
|
|||||||
return this._insertLineNumbersToNode(root, lineLength, highlight);
|
return this._insertLineNumbersToNode(root, lineLength, highlight);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {string} html
|
||||||
|
* @param {number} lineLength
|
||||||
|
* @param {string} highlight - optional
|
||||||
|
* @param {function} callback
|
||||||
|
* @param {number} firstLine
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
this.insertLineNumbers = function (html, lineLength, highlight, callback, firstLine) {
|
this.insertLineNumbers = function (html, lineLength, highlight, callback, firstLine) {
|
||||||
var newHtml, newRoot;
|
var newHtml, newRoot;
|
||||||
|
|
||||||
@ -438,12 +473,81 @@ angular.module('OpenSlidesApp.motions.lineNumbering', [])
|
|||||||
return newHtml;
|
return newHtml;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} html
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
this.stripLineNumbers = function (html) {
|
this.stripLineNumbers = function (html) {
|
||||||
var root = document.createElement('div');
|
var root = document.createElement('div');
|
||||||
root.innerHTML = html;
|
root.innerHTML = html;
|
||||||
this._stripLineNumbers(root);
|
this._stripLineNumbers(root);
|
||||||
return root.innerHTML;
|
return root.innerHTML;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Traverses up the DOM tree until it finds a node with a nextSibling, then returns that sibling
|
||||||
|
*
|
||||||
|
* @param node
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
this._findNextAuntNode = function(node) {
|
||||||
|
if (node.nextSibling) {
|
||||||
|
return node.nextSibling;
|
||||||
|
} else if (node.parentNode) {
|
||||||
|
return this._findNextAuntNode(node.parentNode);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this._highlightUntilNextLine = function(lineNumberNode) {
|
||||||
|
var currentNode = lineNumberNode,
|
||||||
|
foundNextLineNumber = false;
|
||||||
|
|
||||||
|
do {
|
||||||
|
var wasHighlighted = false;
|
||||||
|
if (currentNode.nodeType === TEXT_NODE) {
|
||||||
|
var node = document.createElement('span');
|
||||||
|
node.setAttribute('class', 'highlight');
|
||||||
|
node.innerHTML = currentNode.nodeValue;
|
||||||
|
currentNode.parentNode.insertBefore(node, currentNode);
|
||||||
|
currentNode.parentNode.removeChild(currentNode);
|
||||||
|
currentNode = node;
|
||||||
|
wasHighlighted = true;
|
||||||
|
} else {
|
||||||
|
wasHighlighted = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentNode.childNodes.length > 0 && !this._isOsLineNumberNode(currentNode) && !wasHighlighted) {
|
||||||
|
currentNode = currentNode.childNodes[0];
|
||||||
|
} else if (currentNode.nextSibling) {
|
||||||
|
currentNode = currentNode.nextSibling;
|
||||||
|
} else {
|
||||||
|
currentNode = this._findNextAuntNode(currentNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._isOsLineNumberNode(currentNode)) {
|
||||||
|
foundNextLineNumber = true;
|
||||||
|
}
|
||||||
|
} while (!foundNextLineNumber && currentNode !== null);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} html
|
||||||
|
* @param {number} lineNumber
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
this.highlightLine = function (html, lineNumber) {
|
||||||
|
var fragment = this._htmlToFragment(html),
|
||||||
|
lineNumberNode = this._getLineNumberNode(fragment, lineNumber);
|
||||||
|
|
||||||
|
if (lineNumberNode) {
|
||||||
|
this._highlightUntilNextLine(lineNumberNode);
|
||||||
|
html = this._fragmentToHtml(fragment);
|
||||||
|
}
|
||||||
|
|
||||||
|
return html;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -286,4 +286,42 @@ describe('linenumbering', function () {
|
|||||||
expect(outHtml).toBe("<ul>\n\n<li>" + noMarkup(1) + "Point 1</li>\n\n</ul>");
|
expect(outHtml).toBe("<ul>\n\n<li>" + noMarkup(1) + "Point 1</li>\n\n</ul>");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('line highlighting', function() {
|
||||||
|
it('highlights a simple line', function () {
|
||||||
|
var inHtml = lineNumberingService.insertLineNumbers("<span>Lorem ipsum dolorsit amet</span>", 5);
|
||||||
|
var highlighted = lineNumberingService.highlightLine(inHtml, 2);
|
||||||
|
expect(highlighted).toBe(noMarkup(1) + '<span>Lorem ' + brMarkup(2) + '<span class="highlight">ipsum </span>' + brMarkup(3) + 'dolor' + brMarkup(4) + 'sit ' + brMarkup(5) + 'amet</span>');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('highlights a simple line with formattings', function () {
|
||||||
|
var inHtml = lineNumberingService.insertLineNumbers("<span>Lorem ipsum <strong>dolorsit amet Lorem</strong><em> ipsum dolorsit amet</em> Lorem ipsum dolorsit amet</span>", 20);
|
||||||
|
expect(inHtml).toBe(noMarkup(1) + '<span>Lorem ipsum <strong>dolorsit ' +
|
||||||
|
brMarkup(2) + 'amet Lorem</strong><em> ipsum ' +
|
||||||
|
brMarkup(3) + 'dolorsit amet</em> Lorem ' + brMarkup(4) + 'ipsum dolorsit amet</span>');
|
||||||
|
|
||||||
|
var highlighted = lineNumberingService.highlightLine(inHtml, 2);
|
||||||
|
expect(highlighted).toBe(noMarkup(1) + '<span>Lorem ipsum <strong>dolorsit ' +
|
||||||
|
brMarkup(2) + '<span class="highlight">amet Lorem</span></strong><em><span class="highlight"> ipsum </span>' +
|
||||||
|
brMarkup(3) + 'dolorsit amet</em> Lorem ' + brMarkup(4) + 'ipsum dolorsit amet</span>');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('highlights the last line', function () {
|
||||||
|
var inHtml = lineNumberingService.insertLineNumbers("<span>Lorem ipsum dolorsit amet</span>", 5);
|
||||||
|
var highlighted = lineNumberingService.highlightLine(inHtml, 5);
|
||||||
|
expect(highlighted).toBe(noMarkup(1) + '<span>Lorem ' + brMarkup(2) + 'ipsum ' + brMarkup(3) + 'dolor' + brMarkup(4) + 'sit ' + brMarkup(5) + '<span class="highlight">amet</span></span>');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('highlights the first line', function () {
|
||||||
|
var inHtml = lineNumberingService.insertLineNumbers("<span>Lorem ipsum dolorsit amet</span>", 5);
|
||||||
|
var highlighted = lineNumberingService.highlightLine(inHtml, 1);
|
||||||
|
expect(highlighted).toBe(noMarkup(1) + '<span><span class="highlight">Lorem </span>' + brMarkup(2) + 'ipsum ' + brMarkup(3) + 'dolor' + brMarkup(4) + 'sit ' + brMarkup(5) + 'amet</span>');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not change the string if the line number is not found', function () {
|
||||||
|
var inHtml = lineNumberingService.insertLineNumbers("<span>Lorem ipsum dolorsit amet</span>", 5);
|
||||||
|
var highlighted = lineNumberingService.highlightLine(inHtml, 8);
|
||||||
|
expect(highlighted).toBe(noMarkup(1) + '<span>Lorem ' + brMarkup(2) + 'ipsum ' + brMarkup(3) + 'dolor' + brMarkup(4) + 'sit ' + brMarkup(5) + 'amet</span>');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user