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;
+  }
+};