2012-04-05 00:50:04 +02:00
|
|
|
var Changeset = require('./Changeset');
|
|
|
|
var ChangesetUtils = require('./ChangesetUtils');
|
|
|
|
var _ = require('./underscore');
|
|
|
|
|
2012-04-05 15:20:48 +02:00
|
|
|
var lineMarkerAttribute = 'lmkr';
|
|
|
|
|
|
|
|
// If one of these attributes are set to the first character of a
|
|
|
|
// line it is considered as a line attribute marker i.e. attributes
|
|
|
|
// set on this marker are applied to the whole line.
|
|
|
|
// The list attribute is only maintained for compatibility reasons
|
|
|
|
var lineAttributes = [lineMarkerAttribute,'list'];
|
|
|
|
|
|
|
|
/*
|
2012-04-06 17:44:34 +02:00
|
|
|
The Attribute manager builds changesets based on a document
|
|
|
|
representation for setting and removing range or line-based attributes.
|
2012-04-05 15:20:48 +02:00
|
|
|
|
2012-04-06 17:44:34 +02:00
|
|
|
@param rep the document representation to be used
|
2012-04-05 15:20:48 +02:00
|
|
|
@param applyChangesetCallback this callback will be called
|
|
|
|
once a changeset has been built.
|
2012-04-08 21:21:05 +02:00
|
|
|
|
|
|
|
|
|
|
|
A document representation contains
|
|
|
|
- an array `alines` containing 1 attributes string for each line
|
|
|
|
- an Attribute pool `apool`
|
|
|
|
- a SkipList `lines` containing the text lines of the document.
|
2012-04-05 15:20:48 +02:00
|
|
|
*/
|
|
|
|
|
2012-04-05 00:50:04 +02:00
|
|
|
var AttributeManager = function(rep, applyChangesetCallback)
|
|
|
|
{
|
|
|
|
this.rep = rep;
|
|
|
|
this.applyChangesetCallback = applyChangesetCallback;
|
|
|
|
this.author = '';
|
2012-04-05 01:07:47 +02:00
|
|
|
|
|
|
|
// If the first char in a line has one of the following attributes
|
|
|
|
// it will be considered as a line marker
|
2012-04-05 00:50:04 +02:00
|
|
|
};
|
|
|
|
|
2012-04-07 01:05:25 +02:00
|
|
|
AttributeManager.lineAttributes = lineAttributes;
|
|
|
|
|
2012-04-05 00:50:04 +02:00
|
|
|
AttributeManager.prototype = _(AttributeManager.prototype).extend({
|
|
|
|
|
|
|
|
applyChangeset: function(changeset){
|
2012-04-05 15:20:48 +02:00
|
|
|
if(!this.applyChangesetCallback) return changeset;
|
|
|
|
|
2012-04-05 00:50:04 +02:00
|
|
|
var cs = changeset.toString();
|
|
|
|
if (!Changeset.isIdentity(cs))
|
|
|
|
{
|
|
|
|
this.applyChangesetCallback(cs);
|
|
|
|
}
|
2012-04-05 15:20:48 +02:00
|
|
|
|
|
|
|
return changeset;
|
2012-04-05 00:50:04 +02:00
|
|
|
},
|
|
|
|
|
2012-04-05 15:22:22 +02:00
|
|
|
/*
|
|
|
|
Sets attributes on a 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 attribute: an array of attributes
|
|
|
|
*/
|
|
|
|
setAttributesOnRange: function(start, end, attribs)
|
|
|
|
{
|
2012-04-05 22:26:39 +02:00
|
|
|
var builder = Changeset.builder(this.rep.lines.totalWidth());
|
|
|
|
ChangesetUtils.buildKeepToStartOfRange(this.rep, builder, start);
|
2012-04-05 15:22:22 +02:00
|
|
|
ChangesetUtils.buildKeepRange(this.rep, builder, start, end, attribs, this.rep.apool);
|
|
|
|
return this.applyChangeset(builder);
|
|
|
|
},
|
|
|
|
|
2012-04-05 15:20:48 +02:00
|
|
|
/*
|
|
|
|
Returns if the line already has a line marker
|
|
|
|
@param lineNum: the number of the line
|
|
|
|
*/
|
2012-04-05 00:50:04 +02:00
|
|
|
lineHasMarker: function(lineNum){
|
2012-04-05 01:07:47 +02:00
|
|
|
var that = this;
|
|
|
|
|
2012-04-05 15:20:48 +02:00
|
|
|
return _.find(lineAttributes, function(attribute){
|
2012-04-05 01:07:47 +02:00
|
|
|
return that.getAttributeOnLine(lineNum, attribute) != '';
|
|
|
|
}) !== undefined;
|
2012-04-05 00:50:04 +02:00
|
|
|
},
|
|
|
|
|
2012-04-05 15:20:48 +02:00
|
|
|
/*
|
|
|
|
Gets a specified attribute on a line
|
|
|
|
@param lineNum: the number of the line to set the attribute for
|
|
|
|
@param attributeKey: the name of the attribute to get, e.g. list
|
|
|
|
*/
|
2012-04-05 00:50:04 +02:00
|
|
|
getAttributeOnLine: function(lineNum, attributeName){
|
|
|
|
// get `attributeName` attribute of first char of line
|
|
|
|
var aline = this.rep.alines[lineNum];
|
|
|
|
if (aline)
|
|
|
|
{
|
|
|
|
var opIter = Changeset.opIterator(aline);
|
|
|
|
if (opIter.hasNext())
|
|
|
|
{
|
|
|
|
return Changeset.opAttributeValue(opIter.next(), attributeName, this.rep.apool) || '';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return '';
|
|
|
|
},
|
|
|
|
|
|
|
|
/*
|
|
|
|
Sets a specified attribute on a line
|
|
|
|
@param lineNum: the number of the line to set the attribute for
|
|
|
|
@param attributeKey: the name of the attribute to set, e.g. list
|
|
|
|
@param attributeValue: an optional parameter to pass to the attribute (e.g. indention level)
|
|
|
|
|
|
|
|
*/
|
|
|
|
setAttributeOnLine: function(lineNum, attributeName, attributeValue){
|
|
|
|
var loc = [0,0];
|
|
|
|
var builder = Changeset.builder(this.rep.lines.totalWidth());
|
|
|
|
var hasMarker = this.lineHasMarker(lineNum);
|
|
|
|
|
|
|
|
ChangesetUtils.buildKeepRange(this.rep, builder, loc, (loc = [lineNum, 0]));
|
|
|
|
|
|
|
|
if(hasMarker){
|
|
|
|
ChangesetUtils.buildKeepRange(this.rep, builder, loc, (loc = [lineNum, 1]), [
|
|
|
|
[attributeName, attributeValue]
|
|
|
|
], this.rep.apool);
|
|
|
|
}else{
|
|
|
|
// add a line marker
|
|
|
|
builder.insert('*', [
|
|
|
|
['author', this.author],
|
|
|
|
['insertorder', 'first'],
|
2012-04-05 15:20:48 +02:00
|
|
|
[lineMarkerAttribute, '1'],
|
2012-04-05 00:50:04 +02:00
|
|
|
[attributeName, attributeValue]
|
|
|
|
], this.rep.apool);
|
|
|
|
}
|
|
|
|
|
|
|
|
return this.applyChangeset(builder);
|
|
|
|
},
|
|
|
|
|
|
|
|
/*
|
|
|
|
Removes a specified attribute on a line
|
|
|
|
@param lineNum: the number of the affected line
|
|
|
|
@param attributeKey: the name of the attribute to remove, e.g. list
|
|
|
|
|
|
|
|
*/
|
|
|
|
removeAttributeOnLine: function(lineNum, attributeName, attributeValue){
|
|
|
|
|
|
|
|
var loc = [0,0];
|
|
|
|
var builder = Changeset.builder(this.rep.lines.totalWidth());
|
|
|
|
var hasMarker = this.lineHasMarker(lineNum);
|
|
|
|
|
|
|
|
if(hasMarker){
|
2012-04-07 03:42:05 +02:00
|
|
|
ChangesetUtils.buildKeepRange(this.rep, builder, loc, (loc = [lineNum, 0]));
|
2012-04-05 00:50:04 +02:00
|
|
|
ChangesetUtils.buildRemoveRange(this.rep, builder, loc, (loc = [lineNum, 1]));
|
|
|
|
}
|
|
|
|
|
|
|
|
return this.applyChangeset(builder);
|
|
|
|
},
|
|
|
|
|
|
|
|
/*
|
|
|
|
Sets a specified attribute on a line
|
|
|
|
@param lineNum: the number of the line to set the attribute for
|
|
|
|
@param attributeKey: the name of the attribute to set, e.g. list
|
|
|
|
@param attributeValue: an optional parameter to pass to the attribute (e.g. indention level)
|
|
|
|
*/
|
|
|
|
toggleAttributeOnLine: function(lineNum, attributeName, attributeValue) {
|
|
|
|
return this.getAttributeOnLine(attributeName) ?
|
|
|
|
this.removeAttributeOnLine(lineNum, attributeName) :
|
|
|
|
this.setAttributeOnLine(lineNum, attributeName, attributeValue);
|
|
|
|
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
module.exports = AttributeManager;
|