Mercurial > eldonilo > barbecue
view sxe-document.js @ 6:24aa8dccb170
Make XMPP actually work.
author | Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> |
---|---|
date | Tue, 31 Jan 2012 15:59:28 +0100 |
parents | 03ef53b969bd |
children | 7b2ca4d5af6d |
line wrap: on
line source
'use strict'; /** Copyright (c) 2012 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ 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': this.add(jid, child); break; case 'set': this.update(jid, child); break; case 'remove': this.remove(jid, child); break; case 'document-end': this.state = 'started'; break; } } }, createState: function(state, root, parent) { if (!root) root = this.dom; 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'); element.setAttributeNS(null, 'type', 'attr'); 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(state, child, rid); 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; }, empty: function() { var children = this.dom.childNodes; for (var i = children.length - 1; i >= 0; i--) this.dom.removeChild(children[i]); } };