Comparing version 2.2.4 to 3.0.0
@@ -51,2 +51,9 @@ /** | ||
exports.invert = function(ops) { | ||
return unpackOps(ops).map(function(op) { | ||
op.invert() | ||
return op | ||
}) | ||
} | ||
exports.compose = function(ops1, ops2) { | ||
@@ -169,3 +176,3 @@ //exports.transform(ops2, ops1) | ||
case 'Manipulate': | ||
return new exports.Manipulate(op.path, op.prop, op.value) | ||
return new exports.Manipulate(op.path, op.prop, op.value, op.oldvalue) | ||
case 'ManipulateText': | ||
@@ -172,0 +179,0 @@ return new exports.ManipulateText(op.path, op.diff) |
@@ -177,3 +177,3 @@ /** | ||
summary.attributeChanged[attr].forEach(function(node) { | ||
oplist.push(new Manipulate(pathTo(node, rootNode), attr, node.getAttribute(attr))) | ||
oplist.push(new Manipulate(pathTo(node, rootNode), attr, node.getAttribute(attr), summary.getOldAttribute(node, attr))) | ||
}) | ||
@@ -180,0 +180,0 @@ } |
@@ -52,2 +52,6 @@ /** | ||
ManipulateText.prototype.invert = function() { | ||
this.diff = changesets.invert(this.diff) | ||
} | ||
ManipulateText.prototype.apply = function (rootNode, index, dry) { | ||
@@ -54,0 +58,0 @@ if(!this.path || dry) return |
@@ -25,6 +25,7 @@ /** | ||
// Paths are arrays, where [] is the root node | ||
function Manipulate(path, prop, value) { | ||
function Manipulate(path, prop, value, oldvalue) { | ||
this.path = path | ||
this.prop = prop | ||
this.value = value | ||
this.oldvalue = oldvalue || null | ||
this.type = 'Manipulate' | ||
@@ -76,2 +77,8 @@ } | ||
Manipulate.prototype.invert = function() { | ||
var value = this.value | ||
this.value = this.oldvalue | ||
this.oldvalue = value | ||
} | ||
Manipulate.prototype.apply = function (rootNode, index) { | ||
@@ -83,3 +90,7 @@ if(!this.path) return | ||
myNode.setAttribute(this.prop, this.value) | ||
if (this.value === null) { | ||
myNode.removeAttribute(this.prop) | ||
}else { | ||
myNode.setAttribute(this.prop, this.value) | ||
} | ||
} |
@@ -111,2 +111,9 @@ /** | ||
Move.prototype.invert = function() { | ||
var from = this.from | ||
, to = this.to | ||
this.from = to | ||
this.to = from | ||
} | ||
Move.prototype.apply = function(rootNode, index, dry) { | ||
@@ -113,0 +120,0 @@ var myNode |
{ | ||
"name": "dom-ot", | ||
"version": "2.2.4", | ||
"version": "3.0.0", | ||
"description": "Operational transform library for DOM operations (conforms to shareJS' spec)", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -20,7 +20,8 @@ # dom-ot | ||
### new domOT.Move(fromPath, toPath, [serializedNode]) | ||
This operation allows you to move a node from one path to another. Set `fromPath` to null to insert a node into the tree (which should be passed as `serializedNode`, serialized with [vdom-serialize](http://github.com/marcelklehr/vdom-serialize)). | ||
Set `toPath` to null, to remove a node from the tree. | ||
This operation allows you to move a node from one path to another. | ||
Set `fromPath` to null to insert a node into the tree (which should be passed as `serializedNode`, serialized with [vdom-serialize](http://github.com/marcelklehr/vdom-serialize)). | ||
Set `toPath` to null, to remove a node from the tree (you should also pass `serializedNode` here to enable inversion of the operation). | ||
### new domOT.Manipulate(path, attribute, [value]) | ||
This operation allows you to set an attribute named `attribute` of a given node at `path` to a specific `value`. Omit value to remove the attribute. | ||
### new domOT.Manipulate(path, attribute, value, oldValue=null) | ||
This operation allows you to set an attribute named `attribute` of a given node at `path` to a specific `value`. Set value to null to remove the attribute. | ||
@@ -33,2 +34,5 @@ ### new domOT.ManipulateText(path, diff) | ||
### Operation#invert() | ||
Inverts the operation *in-place*. | ||
### Operation#apply(rootNode, [index]) | ||
@@ -53,2 +57,8 @@ Apply an operation on a document, specified by `rootNode`. Optionally, you may set `index` to `true`, to automatically index nodes for importing MutationSummaries (see the mutationSummary adapter). | ||
## Changelog | ||
v3.0.0 | ||
* Implement operation inversion | ||
## Legal | ||
@@ -55,0 +65,0 @@ (c) 2015 by Marcel Klehr |
@@ -10,2 +10,11 @@ var chai = require('chai') | ||
/* | ||
Table of contents | ||
* transformations | ||
* applications | ||
* inversion | ||
* mutationSummary adapter | ||
*/ | ||
describe('dom-ot', function() { | ||
@@ -374,3 +383,147 @@ describe('transformations', function() { | ||
}) | ||
describe('applications', function() { | ||
var div | ||
beforeEach(function() { | ||
div = document.createElement('div') | ||
}) | ||
it('should insert a node', function() { | ||
var newnode = domOT.serialize(document.createElement('i')) | ||
, op = new domOT.Move(null, [0], newnode) | ||
op.apply(div) | ||
expect(div.firstChild).to.be.instanceof(Element) | ||
expect(div.firstChild.tagName.toLowerCase()).to.equal('i') | ||
}) | ||
it('should insert a node as a sibling', function() { | ||
div.appendChild(document.createElement('p')) | ||
div.appendChild(document.createElement('p')) | ||
var newnode = domOT.serialize(document.createElement('i')) | ||
, op = new domOT.Move(null, [1], newnode) | ||
op.apply(div) | ||
expect(div.childNodes[1]).to.be.instanceof(Element) | ||
expect(div.childNodes[1].tagName.toLowerCase()).to.equal('i') | ||
}) | ||
it('should delete a node', function() { | ||
div.appendChild(document.createElement('i')) | ||
var newnode = domOT.serialize(document.createElement('i')) | ||
, op = new domOT.Move([0], null, newnode) | ||
op.apply(div) | ||
expect(div.childNodes.length).to.equal(0) | ||
}) | ||
it('should delete a node as a sibling', function() { | ||
div.appendChild(document.createElement('p')) | ||
div.appendChild(document.createElement('i')) | ||
div.appendChild(document.createElement('p')) | ||
var newnode = domOT.serialize(document.createElement('i')) | ||
, op = new domOT.Move([1], null, newnode) | ||
op.apply(div) | ||
expect(div.childNodes.length).to.equal(2) | ||
expect(div.childNodes[0].tagName.toLowerCase()).to.equal('p') | ||
expect(div.childNodes[1].tagName.toLowerCase()).to.equal('p') | ||
}) | ||
it('should move a node', function() { | ||
div.appendChild(document.createElement('p')) | ||
var i = document.createElement('i') | ||
div.appendChild(i) | ||
var op = new domOT.Move([1], [0,0]) | ||
op.apply(div) | ||
expect(div.childNodes.length).to.equal(1) | ||
expect(div.childNodes[0].tagName.toLowerCase()).to.equal('p') | ||
expect(div.childNodes[0].firstChild).to.be.instanceof(Element) | ||
expect(div.childNodes[0].firstChild).to.equal(i) | ||
expect(div.childNodes[0].firstChild.tagName.toLowerCase()).to.equal('i') | ||
}) | ||
it('should set an attribute', function() { | ||
var op = new domOT.Manipulate([], 'class', 'foo') | ||
op.apply(div) | ||
expect(div.getAttribute('class')).to.equal('foo') | ||
}) | ||
it('should set a textNode\'s value', function() { | ||
var text = document.createTextNode('hello world!') | ||
div.appendChild(text) | ||
var op = new domOT.ManipulateText([0], Changeset.fromDiff(diffEngine.diff_main('hello world!','hello my world!')).pack()) | ||
op.apply(div) | ||
expect(text.nodeValue).to.equal('hello my world!') | ||
}) | ||
}) | ||
describe('inversion', function() { | ||
var div | ||
beforeEach(function() { | ||
div = document.createElement('div') | ||
}) | ||
it('should invert an insert', function() { | ||
var initial = div.cloneNode(true) | ||
var newnode = domOT.serialize(document.createElement('i')) | ||
, op = new domOT.Move(null, [0], newnode) | ||
op.apply(div) | ||
op.invert() | ||
op.apply(div) | ||
expect(div.outerHTML).to.equal(initial.outerHTML) | ||
}) | ||
it('should invert a removal', function() { | ||
var el = document.createElement('i') | ||
div.appendChild(el) | ||
var initial = div.cloneNode(true) | ||
var newnode = domOT.serialize(el) | ||
var op = new domOT.Move([0], null, newnode) | ||
op.apply(div) | ||
op.invert() | ||
op.apply(div) | ||
expect(div.outerHTML).to.equal(initial.outerHTML) | ||
}) | ||
it('should invert an attrib manipulation', function() { | ||
div.setAttribute('class', 'foo') | ||
var initial = div.cloneNode(true) | ||
var op = new domOT.Manipulate([], 'class', 'bar', 'foo') | ||
op.apply(div) | ||
op.invert() | ||
op.apply(div) | ||
expect(div.outerHTML).to.equal(initial.outerHTML) | ||
}) | ||
it('should invert an attrib insertion', function() { | ||
var initial = div.cloneNode(true) | ||
var op = new domOT.Manipulate([], 'class', 'bar') | ||
op.apply(div) | ||
op.invert() | ||
op.apply(div) | ||
expect(div.outerHTML).to.equal(initial.outerHTML) | ||
}) | ||
it('should invert an attrib removal', function() { | ||
div.setAttribute('class', 'foo') | ||
var initial = div.cloneNode(true) | ||
var op = new domOT.Manipulate([], 'class', null, 'foo') | ||
op.apply(div) | ||
op.invert() | ||
op.apply(div) | ||
expect(div.outerHTML).to.equal(initial.outerHTML) | ||
}) | ||
}) | ||
describe('mutationSummary adapter', function() { | ||
@@ -941,82 +1094,2 @@ var div | ||
describe('applications', function() { | ||
var div | ||
beforeEach(function() { | ||
div = document.createElement('div') | ||
}) | ||
it('should insert a node', function() { | ||
var newnode = domOT.serialize(document.createElement('i')) | ||
, op = new domOT.Move(null, [0], newnode) | ||
op.apply(div) | ||
expect(div.firstChild).to.be.instanceof(Element) | ||
expect(div.firstChild.tagName.toLowerCase()).to.equal('i') | ||
}) | ||
it('should insert a node as a sibling', function() { | ||
div.appendChild(document.createElement('p')) | ||
div.appendChild(document.createElement('p')) | ||
var newnode = domOT.serialize(document.createElement('i')) | ||
, op = new domOT.Move(null, [1], newnode) | ||
op.apply(div) | ||
expect(div.childNodes[1]).to.be.instanceof(Element) | ||
expect(div.childNodes[1].tagName.toLowerCase()).to.equal('i') | ||
}) | ||
it('should delete a node', function() { | ||
div.appendChild(document.createElement('i')) | ||
var newnode = domOT.serialize(document.createElement('i')) | ||
, op = new domOT.Move([0], null, newnode) | ||
op.apply(div) | ||
expect(div.childNodes.length).to.equal(0) | ||
}) | ||
it('should delete a node as a sibling', function() { | ||
div.appendChild(document.createElement('p')) | ||
div.appendChild(document.createElement('i')) | ||
div.appendChild(document.createElement('p')) | ||
var newnode = domOT.serialize(document.createElement('i')) | ||
, op = new domOT.Move([1], null, newnode) | ||
op.apply(div) | ||
expect(div.childNodes.length).to.equal(2) | ||
expect(div.childNodes[0].tagName.toLowerCase()).to.equal('p') | ||
expect(div.childNodes[1].tagName.toLowerCase()).to.equal('p') | ||
}) | ||
it('should move a node', function() { | ||
div.appendChild(document.createElement('p')) | ||
var i = document.createElement('i') | ||
div.appendChild(i) | ||
var op = new domOT.Move([1], [0,0]) | ||
op.apply(div) | ||
expect(div.childNodes.length).to.equal(1) | ||
expect(div.childNodes[0].tagName.toLowerCase()).to.equal('p') | ||
expect(div.childNodes[0].firstChild).to.be.instanceof(Element) | ||
expect(div.childNodes[0].firstChild).to.equal(i) | ||
expect(div.childNodes[0].firstChild.tagName.toLowerCase()).to.equal('i') | ||
}) | ||
it('should set an attribute', function() { | ||
var op = new domOT.Manipulate([], 'class', 'foo') | ||
op.apply(div) | ||
expect(div.getAttribute('class')).to.equal('foo') | ||
}) | ||
it('should set a textNode\'s value', function() { | ||
var text = document.createTextNode('hello world!') | ||
div.appendChild(text) | ||
var op = new domOT.ManipulateText([0], Changeset.fromDiff(diffEngine.diff_main('hello world!','hello my world!')).pack()) | ||
op.apply(div) | ||
expect(text.nodeValue).to.equal('hello my world!') | ||
}) | ||
}) | ||
}) |
Sorry, the diff of this file is too big to display
656913
18859
65
9