Fix 2772. Skipping line marker when applying attribs to a range

pull/2777/head
Luiza Pagliari 2015-09-08 11:55:36 -03:00
parent 92798f21e8
commit 330d2b079d
2 changed files with 108 additions and 48 deletions

View File

@ -55,14 +55,71 @@ AttributeManager.prototype = _(AttributeManager.prototype).extend({
Sets attributes on a range Sets attributes on a range
@param start [row, col] tuple pointing to the start of the range @param start [row, col] tuple pointing to the start of the range
@param end [row, col] tuple pointing to the end of the range @param end [row, col] tuple pointing to the end of the range
@param attribute: an array of attributes @param attribs: an array of attributes
*/ */
setAttributesOnRange: function(start, end, attribs) setAttributesOnRange: function(start, end, attribs)
{
// instead of applying the attributes to the whole range at once, we need to apply them
// line by line, to be able to disregard the "*" used as line marker. For more details,
// see https://github.com/ether/etherpad-lite/issues/2772
var allChangesets;
for(var row = start[0]; row <= end[0]; row++) {
var rowRange = this._findRowRange(row, start, end);
var startCol = rowRange[0];
var endCol = rowRange[1];
var rowChangeset = this._setAttributesOnRangeByLine(row, startCol, endCol, attribs);
// compose changesets of all rows into a single changeset, as the range might not be continuous
// due to the presence of line markers on the rows
if (allChangesets) {
allChangesets = Changeset.compose(allChangesets.toString(), rowChangeset.toString(), this.rep.apool);
} else {
allChangesets = rowChangeset;
}
}
return this.applyChangeset(allChangesets);
},
_findRowRange: function(row, start, end)
{
var startCol, endCol;
var startLineOffset = this.rep.lines.offsetOfIndex(row);
var endLineOffset = this.rep.lines.offsetOfIndex(row+1);
var lineLength = endLineOffset - startLineOffset;
// find column where range on this row starts
if (row === start[0]) { // are we on the first row of range?
startCol = start[1];
} else {
startCol = this.lineHasMarker(row) ? 1 : 0; // remove "*" used as line marker
}
// find column where range on this row ends
if (row === end[0]) { // are we on the last row of range?
endCol = end[1]; // if so, get the end of range, not end of row
} else {
endCol = lineLength - 1; // remove "\n"
}
return [startCol, endCol];
},
/*
Sets attributes on a range, by line
@param row the row where range is
@param startCol column where range starts
@param endCol column where range ends
@param attribs: an array of attributes
*/
_setAttributesOnRangeByLine: function(row, startCol, endCol, attribs)
{ {
var builder = Changeset.builder(this.rep.lines.totalWidth()); var builder = Changeset.builder(this.rep.lines.totalWidth());
ChangesetUtils.buildKeepToStartOfRange(this.rep, builder, start); ChangesetUtils.buildKeepToStartOfRange(this.rep, builder, [row, startCol]);
ChangesetUtils.buildKeepRange(this.rep, builder, start, end, attribs, this.rep.apool); ChangesetUtils.buildKeepRange(this.rep, builder, [row, startCol], [row, endCol], attribs, this.rep.apool);
return this.applyChangeset(builder); return builder;
}, },
/* /*

View File

@ -2423,6 +2423,9 @@ function Ace2Inner(){
var opIter = Changeset.opIterator(rep.alines[n]); var opIter = Changeset.opIterator(rep.alines[n]);
var indexIntoLine = 0; var indexIntoLine = 0;
var selectionStartInLine = 0; var selectionStartInLine = 0;
if (documentAttributeManager.lineHasMarker(n)) {
selectionStartInLine = 1; // ignore "*" used as line marker
}
var selectionEndInLine = rep.lines.atIndex(n).text.length; // exclude newline var selectionEndInLine = rep.lines.atIndex(n).text.length; // exclude newline
if (n == selStartLine) if (n == selStartLine)
{ {