view client.js @ 45:8b69b3a1ef8e

Add support for WebSocket.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Sat, 23 May 2020 18:58:01 +0200
parents fe59565063af
children 010b905a74d4
line wrap: on
line source

'use strict';

document.addEventListener('DOMContentLoaded', function () {
    let connection = null;

    const jid_element = document.getElementById('jid');
    const pass_element = document.getElementById('pass');
    const connect_button = document.getElementById('connect');
    const spinner_img = document.getElementById('connect-spinner');

    const connected_div = document.getElementById('connected');

    const avatar_img = document.getElementById('avatar');

    const tabs = ['profile', 'mam', 'pep', 'account'];
    function onHashChange() {
        const hash = location.hash.substr(1);
        if (!tabs.includes(hash))
            return;
        for (let tab of tabs) {
            const tab_name = 'tab-' + tab;
            const tab_element = document.getElementById(tab_name);
            if (tab == hash) {
                tab_element.classList.add('active')
                const content_elements = document.getElementsByClassName(tab_name);
                for (let element of content_elements)
                    element.hidden = false;
            } else {
                tab_element.classList.remove('active')
                const content_elements = document.getElementsByClassName(tab_name);
                for (let element of content_elements)
                    element.hidden = true;
            }
        }
    }

    onHashChange();
    window.addEventListener('hashchange', onHashChange);

    function rawInput(data)
    {
        console.log('RECV', data);
    }

    function rawOutput(data)
    {
        console.log('SENT', data);
    }

    connect_button.addEventListener('click', function (evt) {
        if (!connect_button.classList.contains('disconnect')) {
            const jid = jid_element.value;
            getBOSHService(jid).then((bosh_service) => {
                connection = new Strophe.Connection(bosh_service);
                connection.rawInput = rawInput;
                connection.rawOutput = rawOutput;
                connection.connect(jid,
                                   pass_element.value,
                                   onConnect);
            });
        } else if (connection != null) {
            connection.disconnect();
        }
        evt.preventDefault();
    });

    function getBOSHService(jid)
    {
        return new Promise((resolve, reject) => {
            const [nodepart, domainpart] = jid.split('@', 2);
            const url = 'https://' + domainpart + '/.well-known/host-meta';
            const xhr = new XMLHttpRequest();
            xhr.onload = function (evt) {
                const xml = evt.target.responseXML;
                const links = parseXPath(xml, './xrd:XRD/xrd:Link', XPathResult.ORDERED_NODE_ITERATOR_TYPE);
                let bosh_service = null;
                let ws_service = null;
                while (true) {
                    const link = links.iterateNext();
                    if (!link)
                        break;
                    const rel = link.getAttributeNS(null, 'rel');
                    if (rel == 'urn:xmpp:alt-connections:xbosh')
                        bosh_service = link.getAttributeNS(null, 'href');
                    else if (rel == 'urn:xmpp:alt-connections:websocket')
                        ws_service = link.getAttributeNS(null, 'href');
                }
                console.log('bosh_service', bosh_service);
                console.log('ws_service', ws_service);
                resolve(ws_service || bosh_service);
            };
            xhr.open('GET', url);
            xhr.send();
        });
    }

    function onConnect(status)
    {
        if (status == Strophe.Status.CONNECTING) {
            console.log('Strophe is connecting.');
            connect_button.value = 'Log out';
            connect_button.classList.add('disconnect');
            jid_element.disabled = true;
            pass_element.disabled = true;
            displaySpinner(spinner_img);
        } else if (status == Strophe.Status.CONNFAIL) {
            console.log('Strophe failed to connect.');
            onDisconnected();
        } else if (status == Strophe.Status.DISCONNECTING) {
            console.log('Strophe is disconnecting.');
            displaySpinner(spinner_img);
        } else if (status == Strophe.Status.DISCONNECTED) {
            console.log('Strophe is disconnected.');
            onDisconnected();
        } else if (status == Strophe.Status.CONNECTED) {
            console.log('Strophe is connected.');
            onConnected();
        }
    }

    function onConnected()
    {
        const new_node = document.createElementNS('http://www.w3.org/1999/xhtml', 'span');
        const parent_node = connect.parentNode;
        const text = document.createTextNode('Logged in as ' + connection.authzid + ' ');
        new_node.appendChild(text);
        parent_node.insertBefore(new_node, connect);

        jid_element.hidden = true;
        pass_element.hidden = true;
        connected_div.hidden = false;
        hideSpinner(spinner_img);
        initRoster(connection);
        initPEP(connection);
        initNickname(connection);
        initAvatar(connection);
        initVCard(connection);
        initMAM(connection);
    }

    function onDisconnected()
    {
        connect_button.value = 'Log in';
        connect_button.classList.remove('disconnect');
        jid_element.hidden = false;
        jid_element.disabled = false;
        pass_element.hidden = false;
        pass_element.disabled = false;
        hideSpinner(spinner_img);
        connected_div.hidden = true;
        let table = document.getElementById('roster-table');
        while (table.hasChildNodes()) {
            table.removeChild(table.lastChild);
        }
        table = document.getElementById('pep-table');
        while (table.hasChildNodes()) {
            table.removeChild(table.lastChild);
        }
        location.reload();
    }
});