changeset 4:5e97e1808a35

Add support for the roster.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Sat, 22 Dec 2018 02:59:29 +0100
parents 5aa1bf7154b0
children cd0434bb2eb1
files client.js index.xhtml roster.js util.js
diffstat 4 files changed, 106 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/client.js
+++ b/client.js
@@ -76,16 +76,12 @@ document.addEventListener('DOMContentLoa
             pass_element.disabled = true;
         } else if (status == Strophe.Status.CONNFAIL) {
             console.log('Strophe failed to connect.');
-            connect_button.value = 'connect';
-            jid_element.disabled = false;
-            pass_element.disabled = false;
+            onDisconnected();
         } else if (status == Strophe.Status.DISCONNECTING) {
             console.log('Strophe is disconnecting.');
         } else if (status == Strophe.Status.DISCONNECTED) {
             console.log('Strophe is disconnected.');
-            connect_button.value = 'connect';
-            jid_element.disabled = false;
-            pass_element.disabled = false;
+            onDisconnected();
         } else if (status == Strophe.Status.CONNECTED) {
             console.log('Strophe is connected.');
             onConnected();
@@ -95,8 +91,22 @@ document.addEventListener('DOMContentLoa
     function onConnected()
     {
         connected_div.hidden = false;
+        initRoster(connection);
         initPEP(connection);
         initNickname(connection);
         initAvatar(connection);
     }
+
+    function onDisconnected()
+    {
+        connect_button.value = 'connect';
+        jid_element.disabled = false;
+        pass_element.disabled = false;
+        for (let item of document.getElementById('roster-table')) {
+            item.remove();
+        }
+        for (let item of document.getElementById('pep-table')) {
+            item.remove();
+        }
+    }
 });
--- a/index.xhtml
+++ b/index.xhtml
@@ -62,6 +62,13 @@
 <option value="presence">Only your contacts</option>
 </select></label>
 </p>
+<h2>Contact list</h2>
+<table>
+<thead>
+<tr><th>JID</th><th>Name</th><th>Subscription</th><th>Groups</th><th>⚠️ Delete</th></tr>
+</thead>
+<tbody id="roster-table"/>
+</table>
 <h2>PEP</h2>
 <table>
 <thead>
@@ -106,6 +113,7 @@
 <script src="nickname.js"/>
 <script src="avatar.js"/>
 <script src="pep.js"/>
+<script src="roster.js"/>
 
 </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/roster.js
@@ -0,0 +1,81 @@
+'use strict';
+
+function initRoster(connection) {
+    const roster_table = document.getElementById('roster-table');
+
+    const iq = $iq({type: 'get'})
+        .c('query', {xmlns: NS.roster});
+    connection.sendIQ(iq, onRoster, onRosterError.bind(null, 'roster query failed.'));
+
+    function onRoster(result_iq)
+    {
+        const items = parseXPath(result_iq, './roster:query/roster:item', XPathResult.ORDERED_NODE_ITERATOR_TYPE);
+        while (true) {
+            const item = items.iterateNext();
+            if (!item)
+                break;
+            const jid = item.getAttributeNS(null, 'jid');
+            const subscription = item.getAttributeNS(null, 'subscription');
+            const name = item.getAttributeNS(null, 'name');
+            const groups = item.children;
+            const tr = document.createElementNS('http://www.w3.org/1999/xhtml', 'tr');
+            let td = document.createElementNS('http://www.w3.org/1999/xhtml', 'td');
+            const a = document.createElementNS('http://www.w3.org/1999/xhtml', 'a');
+            a.setAttributeNS(null, 'href', 'xmpp:' + jid);
+            a.textContent = jid;
+            td.appendChild(a);
+            tr.appendChild(td);
+            td = document.createElementNS('http://www.w3.org/1999/xhtml', 'td');
+            const input = document.createElementNS('http://www.w3.org/1999/xhtml', 'input');
+            input.value = name;
+            input.onblur = function (evt) {
+                const iq = $iq({type: 'set'})
+                    .c('query', {xmlns: NS.roster})
+                        .c('item', {jid: jid, name: evt.target.value});
+                for (let group of groups)
+                    iq.c('group').t(group.textContent).up();
+                connection.sendIQ(iq, onRosterSet, onRosterSetError.bind(null, 'Roster set failed.'));
+            };
+            td.appendChild(input);
+            tr.appendChild(td);
+            td = document.createElementNS('http://www.w3.org/1999/xhtml', 'td');
+            td.textContent = subscription;
+            tr.appendChild(td);
+            td = document.createElementNS('http://www.w3.org/1999/xhtml', 'td');
+            for (let group of groups) {
+                const span = document.createElementNS('http://www.w3.org/1999/xhtml', 'span');
+                // TODO: use a tag system for the UI.
+                span.textContent = group.textContent;
+                td.appendChild(span);
+            }
+            tr.appendChild(td);
+            td = document.createElementNS('http://www.w3.org/1999/xhtml', 'td');
+            const button = document.createElementNS('http://www.w3.org/1999/xhtml', 'button');
+            button.textContent = 'Remove this contact';
+            button.onclick = function (evt) {
+                const iq = $iq({type: 'set'})
+                    .c('query', {xmlns: NS.roster})
+                        .c('item', {jid: jid, subscription: 'unsubscribe'});
+                connection.sendIQ(iq, onRosterSet.bind(node), onRosterSetError.bind(node, 'contact removal failed.'));
+            };
+            td.appendChild(button);
+            tr.appendChild(td);
+            roster_table.appendChild(tr);
+        }
+    }
+
+    function onRosterError(string)
+    {
+        console.log('Failed to retrieve your contact list: ' + string);
+    }
+
+    function onRosterSet(result_iq)
+    {
+        console.log(result_iq);
+    }
+
+    function onRosterSetError(string)
+    {
+        console.log('Failed to retrieve your contact list: ' + string);
+    }
+}
--- a/util.js
+++ b/util.js
@@ -1,5 +1,6 @@
 const NS = {
     xrd: 'http://docs.oasis-open.org/ns/xri/xrd-1.0',
+    roster: 'jabber:iq:roster',
     disco_items: 'http://jabber.org/protocol/disco#items',
     disco_info: 'http://jabber.org/protocol/disco#info',
     dataforms: 'jabber:x:data',