Commit 365aeeb1 authored by Thibaut Frain's avatar Thibaut Frain

Connection procedure update:

- can login / logout
- login parameters stored in sessionStorage
- error management (all code is in promises)
parent b857476e
......@@ -25,6 +25,7 @@
<div data-role="header" data-position="fixed" data-theme="a">
<a href="#page=contactlist" class="ui-btn-left ui-btn ui-btn-inline ui-mini ui-corner-all ui-btn-icon-left ui-icon-user">Contacts</a>
<h1>Jabber Client</h1>
<a href="#page=connection" class="ui-btn-right ui-btn ui-btn-inline ui-mini ui-corner-all">Connection</a>
</div>
<div data-role="page" overflow="hidden">
<div role="main" class="ui-content gadget-container" overflow="hidden"></div>
......
......@@ -38,6 +38,10 @@
rJS(window)
.allowPublicAcquisition('manageService', function (params) {
this.props.app_services.monitor(params[0]);
})
.allowPublicAcquisition('send', function (datas) {
console.log('[xmpp datas output] : ' + datas);
return this.getDeclaredGadget("connection")
......@@ -71,24 +75,36 @@
}
})
.allowPublicAcquisition('publishConnectionState', function (options) {
.allowPublicAcquisition('jio_put', function (params) {
return this.getDeclaredGadget('jio')
.push(function (jio_gadget) {
return jio_gadget.put(params[0]);
});
})
.allowPublicAcquisition('jio_get', function (params) {
return this.getDeclaredGadget('jio')
.push(function (jio_gadget) {
return jio_gadget.get(params[0]);
});
})
.allowPublicAcquisition('loadGadgetAfterLogin', function () {
var gadget = this,
state = options[0],
came_from;
if (state === "connected") {
if (this.props.came_from !== undefined) {
came_from = this.props.came_from;
delete this.props.came_from;
return this.aq_pleasePublishMyState(came_from)
.push(function () {
gadget.render(came_from);
});
}
return this.aq_pleasePublishMyState({page: "contactlist"})
.push(this.pleaseRedirectMyHash.bind(this));
if (this.props.came_from !== undefined) {
came_from = this.props.came_from;
delete this.props.came_from;
return this.aq_pleasePublishMyState(came_from)
.push(function (hash) {
if (hash === window.location.hash) {
return gadget.render(came_from);
}
return gadget.pleaseRedirectMyHash(hash);
});
}
return this.aq_pleasePublishMyState({page: "connection"})
return this.aq_pleasePublishMyState({page: "contactlist"})
.push(this.pleaseRedirectMyHash.bind(this));
})
......@@ -122,14 +138,17 @@
.declareAcquiredMethod("pleaseRedirectMyHash", "pleaseRedirectMyHash")
// Initialize header toolbar
.allowPublicAcquisition('renderConnection', function () {
return this.aq_pleasePublishMyState({page: "connection"})
.push(this.pleaseRedirectMyHash.bind(this));
})
.ready(function (g) {
g.props = {};
g.chatbox_gadgets = {};
$("[data-role='header']").toolbar();
return g.getDeclaredGadget('jio')
.push(function (io_gadget) {
return io_gadget.createJio({
.push(function (jio_gadget) {
return jio_gadget.createJio({
"type": "local",
"username": "jabberclient",
"application_name": "jabberclient"
......@@ -159,6 +178,7 @@
page_element;
element = gadget.__element.querySelector(".gadget-container");
return this.getDeclaredGadget("connection")
.push(function (connection_gadget) {
return connection_gadget.isConnected();
......@@ -174,7 +194,7 @@
gadget.props.came_from = options;
return gadget.getDeclaredGadget("connection")
.push(function (connection_gadget) {
return connection_gadget.pleaseConnectMe();
return connection_gadget.tryAutoConnect();
});
}
return gadget.getDeclaredGadget(options.page)
......@@ -189,9 +209,20 @@
}
element.appendChild(page_element);
if (page_gadget.render !== undefined) {
page_gadget.render(options);
return page_gadget.render(options);
}
})
.push(function () {
if (page_gadget.startService !== undefined) {
return page_gadget.startService();
}
});
})
.push(function () {
if (!gadget.props.app_services) {
gadget.props.app_services = new RSVP.Monitor();
return gadget.props.app_services;
}
});
});
......
......@@ -15,37 +15,42 @@
<script src="../<%= copy.handlebars.relative_dest %>"></script>
<script src="../mixin_promise/mixin_promise.js" ></script>
<script src="jabberclient_connection.js"></script>
</head>
<body>
<div class="login-box ui-corner-all ui-shadow">
<h3>Status: Not connected</h3><br/>
<form class="login-form" data-ajax="false">
<div class="ui-field-contain">
<input type="url" name="server" placeholder="Jabber server url" value="https://mail.tiolive.com/chat/http-bind/" required>
</div>
<div class="ui-field-contain">
<input type="text" name="jid" placeholder="Jabber ID" required>
<script class="login-template" type="text/x-handlebars-template">
<div class="login-box ui-corner-all ui-shadow">
<h3>Status: Not connected</h3><br/>
<form class="login-form" data-ajax="false">
<div class="ui-field-contain">
<input type="url" name="server" placeholder="Jabber server url" value="{{server}}" required>
</div>
<div class="ui-field-contain">
<input type="text" name="jid" placeholder="Jabber ID" value="{{jid}}" required>
</div>
<div class="ui-field-contain">
<input type="password" name="passwd" placeholder="Password" required>
</div>
<fieldset class="ui-btn-inline">
<input type="submit" value="Log In">
</fieldset>
</form>
</div>
</script>
<script class="logout-template" type="text/x-handlebars-template">
<div class="logout-box ui-corner-all ui-shadow">
<h3>Status: Authenticated</h3>
<div class="ui-grid-a">
<div class="ui-block-a"><h4>Server URL</h4></div>
<div class="ui-block-b"><h5 class="server">{{server}}</h5></div>
</div>
<div class="ui-field-contain">
<input type="password" name="passwd" placeholder="Password" required>
<div class="ui-grid-a">
<div class="ui-block-a"><h4>Jabber ID</h4></div>
<div class="ui-block-b"><h5 class="jid">{{jid}}</h5></div>
</div>
<fieldset class="ui-btn-inline">
<input type="submit" value="Log In">
</fieldset>
</form>
</div>
<div class="logout-box ui-corner-all ui-shadow" style="display: none;">
<h3>Status: Authenticated</h3>
<div class="ui-grid-a">
<div class="ui-block-a"><h4>Server URL</h4></div>
<div class="ui-block-b"><h5 class="server"></h5></div>
<button class="ui-btn ui-btn-b ui-btn-inline ui-corner-all">Logout</button>
</div>
<div class="ui-grid-a">
<div class="ui-block-a"><h4>Jabber ID</h4></div>
<div class="ui-block-b"><h5 class="jid"></h5></div>
</div>
<button class="ui-btn ui-btn-b ui-btn-inline ui-corner-all">Logout</button>
</div>
</body>
</script>
<script src="jabberclient_connection.js"></script>
</head>
<body>
</html>
.login-box, .logout-box {
margin: 0 auto;
max-width: 35ch !important;
max-width: 40ch !important;
text-align: center;
padding: 1%;
}
......
/*global window, rJS, Strophe, $, $iq,
XMLSerializer, DOMParser, RSVP, localStorage*/
/*global window, rJS, Strophe, $, $iq, Handlebars,
XMLSerializer, DOMParser, RSVP, sessionStorage, promiseEventListener*/
/*jslint nomen: true*/
(function ($, Strophe, rJS) {
(function ($, Strophe, rJS, Handlebars) {
"use strict";
var gadget_klass = rJS(window),
login_template_source = gadget_klass.__template_element
.querySelector(".login-template").innerHTML,
login_template = Handlebars.compile(login_template_source),
logout_template_source = gadget_klass.__template_element
.querySelector(".logout-template").innerHTML,
logout_template = Handlebars.compile(logout_template_source);
function parseXML(xmlString) {
return new DOMParser()
......@@ -15,29 +22,87 @@
return new XMLSerializer().serializeToString(xml);
}
function showLogin(gadget, params) {
var login_box = gadget.props.login_box,
logout_box = gadget.props.logout_box;
$(login_box).find('input[name="server"]').val(params.server);
$(login_box).find('input[name="jid"]').val(params.jid);
$(login_box).find('input[name="passwd"]').val(params.passwd);
$(logout_box).hide();
$(login_box).show();
function logout(gadget) {
sessionStorage.removeItem("connection_params");
return gadget.render();
}
function showLogout(gadget, params) {
var login_box = gadget.props.login_box,
logout_box = gadget.props.logout_box;
$(logout_box).find('.server').html(params.server);
$(logout_box).find('.jid').html(params.jid);
$(login_box).hide();
$(logout_box).show();
function showLogout(gadget) {
return new RSVP.Queue()
.push(function () {
var jid = Strophe.getBareJidFromJid(gadget.props.connection.jid);
$(gadget.__element).html(logout_template({
server: gadget.props.connection.service,
jid: jid
}));
})
.push(function () {
return promiseEventListener(
gadget.__element.querySelector('.logout-box button'),
'click',
false
);
})
.push(function () {
if (gadget.props.connection) {
gadget.props.connection.disconnect();
}
});
}
function setInputListener(gadget) {
return new RSVP.Promise(function (resolveInputAssignment) {
function canceller() {
if (gadget.props.connection &&
gadget.props.connection.xmlInput) {
delete gadget.props.connection.xmlInput;
}
}
function resolver(resolve, reject) {
gadget.props.connection.xmlInput = function (domElement) {
try {
[].forEach.call(domElement.children, function (child) {
gadget.manageService(
gadget.receive(serializeXML(child))
);
});
} catch (e) {
reject(e);
}
};
resolveInputAssignment();
}
gadget.manageService(new RSVP.Promise(resolver, canceller));
});
}
function loopConnectionListener(gadget, params) {
function login(gadget, params) {
return new RSVP.Queue()
.push(function () {
return setInputListener(gadget);
})
.push(function () {
sessionStorage.setItem(
"connection_params",
JSON.stringify(params)
);
})
.push(function () {
return gadget.props.connection.send(
$iq({type: 'get'}).c('query', {xmlns: 'jabber:iq:roster'})
.tree()
);
})
.push(function () {
return gadget.loadGadgetAfterLogin();
});
}
function connectionListener(gadget, params) {
var connection = new Strophe.Connection(params.server),
connection_callback;
gadget.props.connection = connection;
function canceller() {
if (connection_callback !== undefined) {
......@@ -47,44 +112,53 @@
function resolver(resolve, reject) {
connection_callback = function (status) {
if (status === Strophe.Status.CONNECTED) {
// init jabber inputs
connection.xmlInput = function (domElement) {
[].forEach.call(domElement.children, function (child) {
gadget.receive(serializeXML(child));
});
};
connection.send(
$iq({type: 'get'}).c('query', {xmlns: 'jabber:iq:roster'}).tree()
);
// inform parent gadget
gadget.publishConnectionState('connected');
// show logout box
showLogout(gadget, params);
// register params in localStorage
localStorage.setItem('jabberclient_login', JSON.stringify(params));
} else if (status === Strophe.Status.DISCONNECTED) {
// Destroy connection object
gadget.props.connection = null;
// Inform parent gadget
gadget.publishConnectionState('disconnected');
// Show login box
showLogin(gadget, params);
// remove params in localStorage
localStorage.removeItem('jabberclient_login');
}
new RSVP.Queue()
.push(function () {
if (status === Strophe.Status.CONNECTED) {
return login(gadget, params);
}
if (status === Strophe.Status.DISCONNECTED) {
return logout(gadget);
}
})
.fail(function (e) {
reject(e);
});
};
connection.connect(params.jid, params.passwd, connection_callback);
gadget.props.connection = connection;
}
return new RSVP.Promise(resolver, canceller);
}
rJS(window)
function showLogin(gadget) {
var params = {
server: "https://mail.tiolive.com/chat/http-bind/"
};
return new RSVP.Queue()
.push(function () {
$(gadget.__element).html(login_template(params));
})
.push(function () {
return promiseEventListener(
gadget.__element.querySelector('form.login-form'),
'submit',
false
);
})
.push(function (submit_event) {
$(submit_event.target).serializeArray()
.forEach(function (field) {
params[field.name] = field.value;
});
gadget.manageService(connectionListener(gadget, params));
});
}
.declareAcquiredMethod('pleaseRedirectMyHash', 'pleaseRedirectMyHash')
gadget_klass
.declareAcquiredMethod('publishConnectionState', 'publishConnectionState')
.declareAcquiredMethod("manageService", "manageService")
.declareAcquiredMethod('loadGadgetAfterLogin', 'loadGadgetAfterLogin')
.declareMethod("isConnected", function () {
if (this.props.connection) {
......@@ -103,53 +177,32 @@
return this.props.connection.send(parseXML(xmlString));
})
.declareMethod('disconnect', function () {
if (this.connection && this.connection.connected) {
return this.connection.disconnect();
}
.declareMethod('logout', function () {
logout(this);
})
.declareMethod("pleaseConnectMe", function () {
var params = JSON.parse(localStorage.getItem('jabberclient_login'));
.declareAcquiredMethod("renderConnection", "renderConnection")
.declareMethod("tryAutoConnect", function () {
var params = JSON.parse(sessionStorage.getItem('connection_params'));
if (params !== null &&
typeof params === 'object' &&
Object.keys(params).length === 3) {
return loopConnectionListener(this, params);
this.manageService(connectionListener(this, params));
} else {
return this.renderConnection();
}
return this.publishConnectionState("disconnected");
})
.ready(function (g) {
g.props = {
login_box: g.__element.querySelector('.login-box'),
logout_box: g.__element.querySelector('.logout_box')
};
g.submitLoginCallback = function (e) {
e.preventDefault();
g.props.params = {};
$(this).serializeArray().forEach(function (elem) {
g.props.params[elem.name] = elem.value;
});
loopConnectionListener(g, g.props.params);
return false;
};
g.submitLogoutCallback = function (e) {
g.connection.disconnect();
g.publishConnectionState('disconnected');
};
window.g = g;
return new RSVP.Promise(function (resolve) {
$(document).on('submit', 'form.login-form', g.submitLoginCallback);
$(document).on('click', '.logout-box button', g.submitLogoutCallback);
resolve();
}, function () {
$(document).off('submit', 'form.login-form', g.submitLoginCallback);
$(document).off('click', '.logout-box button', g.submitLogoutCallback);
});
g.props = {};
})
.declareMethod('render', function () {
if (this.props.connection &&
this.props.connection.authenticated) {
return showLogout(this);
}
return showLogin(this);
});
}($, Strophe, rJS));
}($, Strophe, rJS, Handlebars));
......@@ -113,25 +113,6 @@
.declareMethod('receivePresence', function (presence) {
updateContactList(this, parseXML(presence));
})
.declareMethod('receive', function (message) {
var that = this,
body = parseXML(message);
if ($(body).find('iq').length !== 0 &&
$(body).find('query').length !== 0 &&
$(body).find('query').attr('xmlns') === "jabber:iq:roster") {
this.contactList = new ContactList($(body).find('iq')[0]);
} else if ($(body).find('presence')) {
$(body).find('presence').each(function (index, elem) {
updateContactList(that, elem);
});
}
})
.declareMethod('updatePresence', function (presence) {
presence = parseXML(presence);
updateContactList(this, presence);
});
}($, Strophe, rJS(window)));
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment