Mercurial > eldonilo > barbecue
diff sxe-document.js @ 5:03ef53b969bd
Add XMPP support.
author | Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> |
---|---|
date | Tue, 31 Jan 2012 01:09:41 +0100 |
parents | |
children | 24aa8dccb170 |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/sxe-document.js @@ -0,0 +1,157 @@ +'use strict'; + +var Document = function(initiator, name, host, domId, prolog) { + this.initiator = initiator; + this.name = name; + this.host = host; + + this.prolog = prolog || 'data:application/xhtml+xml,%3C%3Fxml%20version%3D%271.0%27%3F%3E%0A%3C%21DOCTYPE%20html%3E%0A'; + this.state = 'not-started'; + this.records = {}; + this.dom = document.getElementById(domId); +}; + +Document.prototype = { + add: function(jid, child) { + var record = new Record(jid, child); + + if (record.rid in this.records) + console.log('duplicate new'); + + this.records[record.rid] = record; + record.toDOM(this.records, this.dom); + }, + update: function(jid, child) { + var target = child.getAttributeNS(null, 'target'); + + if (!(target in this.records)) + return; // Ignore it. + + var record = this.records[target]; + console.log(record, child); + child.setAttributeNS(null, 'rid', target); + + var version = +child.getAttributeNS(null, 'version'); + if (this.state === 'getting-state') + record.version = version; + else + record.version++; + + if (record.version === version) { + var type = child.getAttributeNS(null, 'type'); + if (type === 'text' || type === 'attr' || type === 'comment') { + var chdata = child.getAttributeNS(null, 'chdata'); + var replacefrom = +child.getAttributeNS(null, 'replacefrom'); + var replacen = +child.getAttributeNS(null, 'replacen'); + if (chdata && replacefrom && replacen) { + var string = record.chdata.substr(0, replacefrom); + string += chdata; + string += record.chdata.substr(replacefrom + replacen); + child.removeAttributeNS(null, 'replacefrom'); + child.removeAttributeNS(null, 'replacen'); + child.setAttributeNS(null, 'chdata', string); + } + } + record.update(jid, child); + record.toDOM(this.records, this.dom); + } else + ; // Not sure I understand correctly. + }, + remove: function(jid, child) { + var rid = child.getAttributeNS(null, 'target'); + this.records[rid].remove(this.records); + delete this.records[rid]; + }, + processState: function(jid, elements) { + var i = 0; + var first = elements[0]; + if (first.localName === 'document-begin') { + if (this.state !== 'not-started') + return; //TODO: the session has already started. + i = 1; + this.prolog = first.getAttributeNS(null, 'prolog'); + this.state = 'getting-session'; + } + + //TODO: if the session isn’t started, should ignore changes? + + for (; i < elements.length; i++) { + var child = elements[i]; + var change = child.localName; + + switch (change) { + case 'new': + doc.add(jid, child); + break; + case 'set': + doc.update(jid, child); + break; + case 'remove': + doc.remove(jid, child); + break; + case 'document-end': + this.state = 'started'; + break; + } + } + }, + createState: function(root, parent, state) { + var children = root.childNodes; + for (var i = 0; i < children.length; i++) { + var child = children[i]; + var element = document.createElementNS(Lightstring.NS.sxe, 'new'); + var rid = Lightstring.newId('GUID'); + element.setAttributeNS(null, 'rid', rid); + + if (parent) + element.setAttributeNS(null, 'parent', parent); + + switch (child.nodeType) { + case 1: + element.setAttributeNS(null, 'type', 'element'); + element.setAttributeNS(null, 'ns', child.namespaceURI); + element.setAttributeNS(null, 'name', child.localName); + state.push(element); + + //TODO: move that elsewhere, or make it prettier. + var convertAttr = function(attr) { + var element = document.createElementNS(Lightstring.NS.sxe, 'new'); + var arid = Lightstring.newId('GUID'); + element.setAttributeNS(null, 'rid', arid); + element.setAttributeNS(null, 'parent', rid); + if (attr.namespaceURI) + element.setAttributeNS(null, 'ns', attr.namespaceURI); + element.setAttributeNS(null, 'name', attr.localName); + element.setAttributeNS(null, 'chdata', attr.textContent); + state.push(element); + }; + + for (var j = 0; j < child.attributes.length; j++) + convertAttr(child.attributes[j]); + + state = this.createState(child, rid, state); + break; + + case 3: + element.setAttributeNS(null, 'type', 'text'); + element.setAttributeNS(null, 'chdata', child.textContent); + state.push(element); + break; + + case 7: + element.setAttributeNS(null, 'type', 'processinginstruction'); + element.setAttributeNS(null, 'pitarget', child.target); + element.setAttributeNS(null, 'pidata', child.data); + state.push(element); + break; + + case 8: + element.setAttributeNS(null, 'type', 'comment'); + element.setAttributeNS(null, 'chdata', child.textContent); + state.push(element); + break; + } + } + return state; + } +};