NodeElement.setTag stops being a magic method that tries to simulate
tagName as being a mutable property. It's now just a shortcut for
replaceWith combined with copying replaced element contents, attributes
and custom data. This change:
- allows for removal of a separate nodeTagChange event,
- simplifies implementation,
- makes api more in line with DOM specification,
- invalidates references to the old node explicitly by returning
reference to a newly created node.
},
setTag: function(tagName) {
},
setTag: function(tagName) {
- var node = this.document.createDocumentNode({tagName: tagName}),
- oldTagName = this.getTagName(),
- myContents = this._$.contents();
+ var node = this.document.createDocumentNode({tagName: tagName});
this.getAttrs().forEach(function(attribute) {
this.getAttrs().forEach(function(attribute) {
- node.setAttr(attribute.name, attribute.value, true);
+ node.setAttr(attribute.name, attribute.value);
- node.setData(this.getData());
- if(this.sameNode(this.document.root)) {
- this.document._defineDocumentProperties(node._$);
- }
+ this.contents().forEach(function(child) {
+ node.append(child);
+ });
- /* TODO: This invalidates old references to this node. Caching instances on nodes would fix this. */
- this._$.replaceWith(node._$);
- this._setNativeNode(node._$[0]);
- this._$.append(myContents);
- this.triggerChangeEvent('nodeTagChange', {oldTagName: oldTagName, newTagName: this.getTagName()});
- },
+ node.setData(this.getData());
+ this.replaceWith(node);
+ return node;
+ },
setAttr: function(name, value, silent) {
var oldVal = this.getAttr(name);
setAttr: function(name, value, silent) {
var oldVal = this.getAttr(name);
it('can change tag name', function() {
var node = elementNodeFromXML('<div></div>');
it('can change tag name', function() {
var node = elementNodeFromXML('<div></div>');
+ node = node.setTag('span');
expect(node.getTagName()).to.equal('span');
});
expect(node.getTagName()).to.equal('span');
});
- it('emits nodeTagChange event', function() {
- var node = elementNodeFromXML('<div></div>'),
- spy = sinon.spy();
-
- node.document.on('change', spy);
- node.setTag('span');
- var event = spy.args[0][0];
-
- expect(event.type).to.equal('nodeTagChange');
- expect(event.meta.node.sameNode(node)).to.be.true;
- expect(event.meta.oldTagName).to.equal('div');
- });
-
describe('Implementation specific expectations', function() {
describe('Implementation specific expectations', function() {
- // DOM specifies ElementNode tag as a read-only property, so
- // changing it in a seamless way is a little bit tricky. For this reason
- // the folowing expectations are required, despite the fact that they actually are
- // motivated by implemetation details.
-
- it('keeps node in the document', function() {
- var doc = getDocumentFromXML('<div><header></header></div>'),
- header = doc.root.contents()[0];
- header.setTag('span');
- expect(header.parent().sameNode(doc.root)).to.be.true;
- });
it('keeps custom data', function() {
var node = elementNodeFromXML('<div></div>');
node.setData('key', 'value');
it('keeps custom data', function() {
var node = elementNodeFromXML('<div></div>');
node.setData('key', 'value');
+ node = node.setTag('header');
expect(node.getTagName()).to.equal('header');
expect(node.getData()).to.eql({key: 'value'});
expect(node.getTagName()).to.equal('header');
expect(node.getData()).to.eql({key: 'value'});
expect(doc.root.getTagName()).to.equal('span');
});
expect(doc.root.getTagName()).to.equal('span');
});
- it('keeps contents', function() {
+ it('keeps node contents', function() {
var node = elementNodeFromXML('<div><div></div></div>');
var node = elementNodeFromXML('<div><div></div></div>');
+ node = node.setTag('header');
expect(node.contents()).to.have.length(1);
});
});
expect(node.contents()).to.have.length(1);
});
});