complete redesign: use nodejs on server instead of php - documentation to be updated
This commit is contained in:
676
nodejs/public/javascripts/safechat.js
Normal file
676
nodejs/public/javascripts/safechat.js
Normal file
@@ -0,0 +1,676 @@
|
||||
/*! @file
|
||||
|
||||
@id $Id$
|
||||
|
||||
This is the main application as it is fully run in the user's browser.
|
||||
|
||||
@dot
|
||||
digraph X {
|
||||
|
||||
start [URL="\ref start()"];
|
||||
newuser [URL="\ref newuser()"];
|
||||
login [URL="\ref login()"];
|
||||
createkeypair [URL="\ref createkeypair()"];
|
||||
chat [URL="\ref chat()"];
|
||||
getpwd [URL="\ref getpwd()"];
|
||||
setpw [URL="\ref setpw()"];
|
||||
get [URL="\ref get()"];
|
||||
sendmessage [URL="\ref sendmessage()"];
|
||||
|
||||
start -> newuser [label="if no keys exist"];
|
||||
start -> login [label="if keys exist"];
|
||||
newuser -> createkeypair [label="on submit"];
|
||||
createkeypair -> "openpgp.generateKeyPair";
|
||||
"openpgp.generateKeyPair" -> login [label="keys generated in local store"];
|
||||
login -> chat [label="user is valid on server"];
|
||||
chat -> getpwd [label="password not yet entered"];
|
||||
getpwd -> setpw [label="on input"];
|
||||
setpw -> chat [label="password is valid"];
|
||||
chat -> chat [label="remain in chat"];
|
||||
chat -> get [label="start timer"];
|
||||
get -> get [label="restart timer"];
|
||||
chat -> sendmessage [label="on submit"];
|
||||
sendmessage -> chat [label="remain in chat"];
|
||||
}
|
||||
@enddot
|
||||
*/
|
||||
// 1 2 3 4 5 6 7 8
|
||||
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
|
||||
var password = null; ///< password, only stored temporary, until reload
|
||||
var username = null; ///< username, only used during registration
|
||||
var filecontent = new Array(); ///< temporary storage for attachments
|
||||
var socket = io.connect();
|
||||
|
||||
var reboottimer = null;
|
||||
/// Show error messsage
|
||||
/** Fades in an error message and logs to console.
|
||||
@param data (optional) The error can be a string or any structure.
|
||||
Strings are shown to the user, structures are logged only.
|
||||
@param stay (optional) If not given as @c true, reloads page after 5s. */
|
||||
function error(data, stay) {
|
||||
$("#status").hide();
|
||||
$("#status").addClass("error")
|
||||
$("#status").removeClass("notice")
|
||||
$("#status").removeClass("success")
|
||||
if (data) {
|
||||
if (typeof data == 'string') {
|
||||
$("#status").html(data);
|
||||
console.log("error: "+data);
|
||||
} else {
|
||||
$("#status").html('unknown error: '+JSON.stringify(data));
|
||||
console.log("error: "+JSON.stringify(data));
|
||||
}
|
||||
} else {
|
||||
$("#status").html('error');
|
||||
console.log("error");
|
||||
}
|
||||
$("#status").show();
|
||||
if (!stay) {
|
||||
console.log("reboot in 5s");
|
||||
console.log((new Error('stacktrace')).stack);
|
||||
if (!reboottimer) reboottimer = setTimeout(function() {
|
||||
reboottimer = null;
|
||||
start();
|
||||
}, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
/// Show notice messsage
|
||||
/** Fades in an notice message and logs to console.
|
||||
@param text (optional) The data is a string. */
|
||||
function notice(text) {
|
||||
$("#status").hide()
|
||||
$("#status").addClass("notice")
|
||||
$("#status").removeClass("error")
|
||||
$("#status").removeClass("success")
|
||||
if (text) {
|
||||
$("#status").html(text);
|
||||
console.log("notice: "+text);
|
||||
} else {
|
||||
$("#status").html('');
|
||||
console.log("notice");
|
||||
}
|
||||
$("#status").show();
|
||||
}
|
||||
|
||||
/// Show notice messsage
|
||||
/** Fades in an success message and logs to console.
|
||||
@param text (optional) The data is a string. */
|
||||
function success(text) {
|
||||
$("#status").hide();
|
||||
$("#status").addClass("success")
|
||||
$("#status").removeClass("error")
|
||||
$("#status").removeClass("notice")
|
||||
if (text) {
|
||||
$("#status").html(text);
|
||||
console.log("success: "+text);
|
||||
} else {
|
||||
$("#status").html('');
|
||||
console.log("success");
|
||||
}
|
||||
$("#status").show();
|
||||
}
|
||||
|
||||
/// Show status message in the main screen area
|
||||
/** @param id HTML id to be shown.
|
||||
@param msg The success message text */
|
||||
function status(id, msg) {
|
||||
console.log("state: "+id);
|
||||
if (msg) success(msg); else $("#status").fadeOut('slow');
|
||||
$("#main").children(":not(#"+id+")").hide();
|
||||
$("#main #"+id).fadeIn("slow", function() {
|
||||
$("#main #"+id+" form input:first-child").focus();
|
||||
});
|
||||
}
|
||||
|
||||
function emit(signal, data) {
|
||||
console.log("<-snd "+signal);
|
||||
socket.emit(signal, data);
|
||||
}
|
||||
|
||||
function connected() {
|
||||
console.log("server connected");
|
||||
$("#connectionstatus #bad").hide();
|
||||
$("#connectionstatus #good").show();
|
||||
success("server connected");
|
||||
}
|
||||
|
||||
function disconnected() {
|
||||
console.log("server disconnected");
|
||||
$("#connectionstatus #good").hide();
|
||||
$("#connectionstatus #bad").show();
|
||||
error("server disconnected", true);
|
||||
}
|
||||
|
||||
function connectionstatus() {
|
||||
if (socket.connected) connected(); else disconnected();
|
||||
}
|
||||
|
||||
/// Alert user
|
||||
/** Alert user, e.g. that a new message has arrived. */
|
||||
function beep(user) {
|
||||
success("message from "+user+" received");
|
||||
navigator.vibrate =
|
||||
navigator.vibrate || navigator.webkitVibrate || navigator.mozVibrate || navigator.msVibrate;
|
||||
if (navigator.vibrate) {
|
||||
// vibration API supported
|
||||
navigator.vibrate(1000);
|
||||
}
|
||||
(new Audio("sounds/A-Tone-His_Self-1266414414.mp3")).play();
|
||||
}
|
||||
|
||||
/// Toggle Menu Display
|
||||
function togglemenu() {
|
||||
$("#menu").toggle();
|
||||
}
|
||||
|
||||
/// Download Profile Backup
|
||||
function backup() {
|
||||
var download = document.createElement('a');
|
||||
download.href = 'data:attachment/text,'+encodeURI(JSON.stringify(localStorage));
|
||||
download.target = '_blank';
|
||||
function pad(n) {return n<10 ? '0'+n : n}
|
||||
var now = new Date();
|
||||
download.download =
|
||||
pad(now.getFullYear())+pad(now.getMonth()+1)+pad(now.getDate())+
|
||||
"-"+userid()+"@"+window.location.hostname+".bak";
|
||||
var clickEvent = new MouseEvent("click", {
|
||||
"view": window,
|
||||
"bubbles": true,
|
||||
"cancelable": false
|
||||
});
|
||||
download.dispatchEvent(clickEvent);
|
||||
togglemenu();
|
||||
}
|
||||
|
||||
/// Upload Profile Backup
|
||||
function restore(evt) {
|
||||
if (!window.FileReader)
|
||||
return error("your browser dows not support file upload", true);
|
||||
for (var i=0, f; f=evt.target.files[i]; ++i) {
|
||||
var file = f;
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(evt) {
|
||||
if (evt.target.error) return error("error reading file", true);
|
||||
if (evt.target.readyState==0) return notice("waiting for data …");
|
||||
if (evt.target.readyState==1) return notice("loading data …");
|
||||
var parsed=JSON.parse(evt.target.result);
|
||||
togglemenu();
|
||||
localStorage.pubkey = parsed.pubkey;
|
||||
localStorage.privkey = parsed.privkey;
|
||||
success("backup is restored");
|
||||
console.log("reboot after restore in 2s");
|
||||
if (!reboottimer) reboottimer = setTimeout(function() {
|
||||
reboottimer = null;
|
||||
start();
|
||||
}, 2000);
|
||||
}
|
||||
reader.readAsText(file);
|
||||
}
|
||||
}
|
||||
|
||||
/// Configure local groups
|
||||
/** … */
|
||||
function groups() {
|
||||
}
|
||||
|
||||
/// Check if password is set and matches the repeated password
|
||||
/** Checks if both passwords are identical and valid and gives
|
||||
feedback to the user.
|
||||
|
||||
Called when user edits the password fields.
|
||||
|
||||
Sets @ref username and checks @ref password - if both are well
|
||||
defined, enables the submit button.
|
||||
|
||||
@param pwd The password.
|
||||
@param pwd2 The repeated password. */
|
||||
function checkpwd(pwd, pwd2) {
|
||||
$("#register").submit(function(event) {
|
||||
return false;
|
||||
});
|
||||
if (pwd==pwd2) password=pwd;
|
||||
else password=null;
|
||||
if (!password||password.length<1) password=null;
|
||||
$("#createuser").prop("disabled", !(username && password));
|
||||
if (password) {
|
||||
if (username) success("user is ready to be created");
|
||||
else notice("password matches, please chose a valid user name");
|
||||
} else {
|
||||
if (username) notice("passwords don't match");
|
||||
else if ($('#user').val()) notice("user name is already in use");
|
||||
else notice("please chose a user name");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if the receiver of a message exists on server.
|
||||
/** Calls checknewuser.php on server and enables the message submit
|
||||
button if the receiver of the message exists on the server. */
|
||||
function checkpartner(user) {
|
||||
$("#chat").submit(function(event) {
|
||||
return false;
|
||||
});
|
||||
emit("user", user);
|
||||
}
|
||||
|
||||
/// Create Local Public-/Private-Key Pair
|
||||
/** Called if user has not yet his keys, just generates a new key pair. */
|
||||
function createkeypair(user, pwd) {
|
||||
notice("generating keys");
|
||||
openpgp.generateKeyPair({
|
||||
numBits: 4096,
|
||||
userId: user,
|
||||
passphrase: pwd
|
||||
}).then(function(keyPair) {
|
||||
success("keys generated");
|
||||
localStorage.pubkey = keyPair.publicKeyArmored;
|
||||
localStorage.privkey = keyPair.privateKeyArmored;
|
||||
login();
|
||||
}).catch(function(e) {
|
||||
error("generating key pairs failed");
|
||||
});
|
||||
}
|
||||
|
||||
/// Get Own Public Key
|
||||
/** @return public key object */
|
||||
function publicKey() {
|
||||
if (typeof localStorage.pubkey == 'undefined') {
|
||||
if (typeof localStorage.pubKey == 'undefined') {
|
||||
return null;
|
||||
} else {
|
||||
localStorage.pubkey = localStorage.pubKey;
|
||||
localStorage.removeItem(pubKey);
|
||||
}
|
||||
}
|
||||
return openpgp.key.readArmored(localStorage.pubkey);
|
||||
}
|
||||
|
||||
/// Get Own Private Key
|
||||
/** @return private key object */
|
||||
function privateKey() {
|
||||
if (typeof localStorage.privkey == 'undefined') {
|
||||
if (typeof localStorage.privKey == 'undefined') {
|
||||
return null;
|
||||
} else {
|
||||
localStorage.privkey = localStorage.privKey;
|
||||
localStorage.removeItem(privKey);
|
||||
}
|
||||
}
|
||||
return openpgp.key.readArmored(localStorage.privkey);
|
||||
}
|
||||
|
||||
/// Get Own User Name
|
||||
/** Get user name as user id of first public key */
|
||||
function userid() {
|
||||
if (!publicKey() ||
|
||||
publicKey().keys.length < 1 ||
|
||||
publicKey().keys[0].getUserIds().length < 1) return null
|
||||
return publicKey().keys[0].getUserIds()[0];
|
||||
}
|
||||
|
||||
/// Clear Message Text And Attachments
|
||||
/** Does not remove the receiver's name */
|
||||
function clearmessage() {
|
||||
filecontent = new Array();
|
||||
$('#preview').empty();
|
||||
$("#msg").val("");
|
||||
}
|
||||
|
||||
/// Display Image Attachments
|
||||
function attachments(files, id) {
|
||||
if (files) files.forEach(function(file) {
|
||||
var img = document.createElement('img');
|
||||
img.src = file.content;
|
||||
$(id).append(img);
|
||||
});
|
||||
}
|
||||
|
||||
/// Upload Attachment
|
||||
/** Prepares attachment to be sent in a message. If the attachment is
|
||||
an image, it resizes the image to 400px on the lager side.
|
||||
|
||||
By now, only images are supported.
|
||||
|
||||
Stores data in global variable @ref filecontent. */
|
||||
function fileupload(evt) {
|
||||
if (!window.FileReader)
|
||||
return error("your browser does not support file upload", true);
|
||||
for (var i=0, f; f=evt.target.files[i]; ++i) {
|
||||
var file = f;
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(evt) {
|
||||
if (evt.target.error) return error("error reading file", true);
|
||||
if (evt.target.readyState==0) return notice("waiting for data …");
|
||||
if (evt.target.readyState==1) return notice("loading data …");
|
||||
if (!file.type.match('^image/'))
|
||||
return error(file.name+": not an image", true);
|
||||
var img = document.createElement("img");
|
||||
img.onload = function() {
|
||||
var MAX = 400;
|
||||
var width = img.width;
|
||||
var height = img.height;
|
||||
if (width > MAX) {
|
||||
height *= MAX / width;
|
||||
width = MAX;
|
||||
}
|
||||
if (height > MAX) {
|
||||
width *= MAX / height;
|
||||
height = MAX;
|
||||
}
|
||||
var canvas = document.createElement("canvas");
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
var ctx = canvas.getContext("2d");
|
||||
ctx.drawImage(img, 0, 0, width, height);
|
||||
img.onload = function() {
|
||||
filecontent.push({type: file.type, content: img.src});
|
||||
$("#preview").append(img);
|
||||
success('image of type '+file.type+' is ready to be sent');
|
||||
}
|
||||
img.src = canvas.toDataURL(file.type);
|
||||
}
|
||||
img.src=evt.target.result;
|
||||
}
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets Receiver's Name
|
||||
/** Called when clicked on a receiver's name. Sets focus to the
|
||||
message text field.
|
||||
|
||||
@param name The receiver's name. */
|
||||
function setreceiver(name) {
|
||||
$("#recv").val(name);
|
||||
checkpartner(name);
|
||||
$("#msg").focus();
|
||||
}
|
||||
|
||||
var userMap = null;
|
||||
function users(userlist) {
|
||||
console.log("rcv-> users");
|
||||
userMap = new Array();
|
||||
userlist.forEach(function(usr) {
|
||||
userMap[usr.name] = usr.pubkey;
|
||||
console.log(" user: "+usr.name);
|
||||
});
|
||||
localStorage.userMap = JSON.stringify(userMap);
|
||||
}
|
||||
|
||||
function fail(msg) {
|
||||
console.log("rcv-> fail");
|
||||
error(msg);
|
||||
}
|
||||
|
||||
function loggedin() {
|
||||
console.log("rcv-> login");
|
||||
success("login successful");
|
||||
chat();
|
||||
}
|
||||
|
||||
function user(usr) {
|
||||
if (usr.exists) console.log("rcv-> user("+usr.name+")");
|
||||
else console.log("rcv-> user("+usr.name+"): name is available");
|
||||
if ($("#newuser").is(":visible") && usr.name==$('#user').val()) {
|
||||
// same username as in the create user form
|
||||
$("#createuser").prop("disabled", usr.exists); // todo: check password
|
||||
if (!usr.exists) {
|
||||
username = usr.name;
|
||||
success("user name "+usr.name+" is available");
|
||||
} else {
|
||||
username = null;
|
||||
error("user name "+usr.name+" is in use", true);
|
||||
}
|
||||
}
|
||||
if ($("#chat").is(":visible") && usr.name==$("#recv").val()) { // same username as in receiver
|
||||
$("#send").prop("disabled", !usr.exists);
|
||||
if (usr.exists) success("recipient exists");
|
||||
else error("unknown recipient", true);
|
||||
}
|
||||
if (userMap == null) {
|
||||
if (localStorage.userMap) {
|
||||
userMap = JSON.parse(localStorage.userMap);
|
||||
} else {
|
||||
userMap = new Array();
|
||||
}
|
||||
}
|
||||
if (usr.exists && usr.pubkey && userMap[usr.name] != usr.pubkey) {
|
||||
userMap[usr.name] = usr.pubkey;
|
||||
localStorage.userMap = JSON.stringify(userMap);
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a user's public key.
|
||||
/** The first time, gets it from the server, later from the cache. */
|
||||
function getPublicKey(user) {
|
||||
var deferredObject = $.Deferred();
|
||||
if (userMap && userMap[user]) deferredObject.resolve(userMap[user]);
|
||||
else deferredObject.reject("unknown user");
|
||||
return deferredObject.promise();
|
||||
}
|
||||
|
||||
/// Received a list of messages from server
|
||||
function messages(ms) {
|
||||
console.log("rcv-> messages");
|
||||
notice("load messages, please wait …");
|
||||
ms.forEach(function(msg) {
|
||||
message(msg, false);
|
||||
});
|
||||
success("ready");
|
||||
status("chat");
|
||||
}
|
||||
|
||||
/// Received a message from server
|
||||
function message(m, signaling=true) {
|
||||
if (signaling) console.log("rcv-> message("+m.user+")");
|
||||
if (!password || !privateKey()) return;
|
||||
var key=openpgp.key.readArmored(m.pubkey);
|
||||
if (key.err) return error("key of sender unreadable", true);
|
||||
var message = openpgp.message.readArmored(m.msg);
|
||||
var privkey = privateKey().keys[0];
|
||||
if (privkey.decrypt(password)) // prepare own key
|
||||
openpgp.decryptAndVerifyMessage(privkey, key.keys, message)
|
||||
.then(function(msg) { // decryption succeded
|
||||
// prepend message to list of messages
|
||||
var message = JSON.parse(msg.text);
|
||||
$("#msgs") // todo: check msg.signatures[0].valid
|
||||
.prepend('<div id="id'+(m.id)+'" class="msg '+
|
||||
(m.user==userid()?"me":"other")+
|
||||
'"><div class="header">'+
|
||||
'<span class="date">'+
|
||||
(new Date(m.time)).toLocaleString()+
|
||||
'</span><span class="sender">'+
|
||||
'<a href="javascript:void(0)" '+
|
||||
'onclick="setreceiver(this.innerHTML)">'+
|
||||
m.user+
|
||||
'</a>'+(message.receiver?" → "+message.receiver:"")+
|
||||
'</span></div>'+
|
||||
'<div class="text">'+
|
||||
message.text+
|
||||
'</div></div><div class="clear"/>');
|
||||
// show attachments
|
||||
attachments(message.files, '#id'+m.id+' .text');
|
||||
// calculate and show emoticons
|
||||
$('#id'+m.id).emoticonize();
|
||||
if (signaling) beep(m.user);
|
||||
})
|
||||
.catch(function(e) {
|
||||
// not for me
|
||||
success();
|
||||
});
|
||||
}
|
||||
|
||||
/// Send Message To Server
|
||||
/** User wants to send a message. Encrypt message with own private and
|
||||
the receiver's public key, then send it to the server. */
|
||||
function sendmessage(recv, txt) {
|
||||
notice("1/3 preparing message …");
|
||||
$("#message").fadeOut("slow");
|
||||
getPublicKey(recv) // get receiver's public key
|
||||
.done(function(pk) {
|
||||
var key=openpgp.key.readArmored(pk);
|
||||
if (!pk||key.err) {
|
||||
$("#message").fadeIn("slow");
|
||||
error("receiver's key not found", true);
|
||||
return;
|
||||
}
|
||||
var privkey = privateKey().keys[0];
|
||||
privkey.decrypt(password); // get own private key ready
|
||||
var message = JSON.stringify({receiver: recv, text: txt, files: filecontent});
|
||||
notice("2/3 encrypting message …");
|
||||
openpgp.signAndEncryptMessage(key.keys.concat(publicKey().keys), privkey, message)
|
||||
.then(function(msg) { // message is encrypted
|
||||
notice("3/3 sending message …");
|
||||
emit("message", {user: userid(), content: msg});
|
||||
clearmessage();
|
||||
})
|
||||
.catch(function(e) {
|
||||
$("#message").fadeIn("slow");
|
||||
error("encryption of message failed", true);
|
||||
});
|
||||
})
|
||||
.fail(function(e) {
|
||||
$("#message").fadeIn("slow");
|
||||
error("user not found", true);
|
||||
});
|
||||
$("#message").fadeIn("slow");
|
||||
}
|
||||
|
||||
/// Check And Set Password
|
||||
/** Check if given password matches to decrypt the private key. If so,
|
||||
store it in global temporary variable @ref password and start the
|
||||
chat. The password matches, when the private key can be decrypted.
|
||||
|
||||
@param pwd The password to check. */
|
||||
function setpw(pwd) {
|
||||
if (privateKey().keys[0].decrypt(pwd)) {
|
||||
success("password matches");
|
||||
$("#removeKey").hide();
|
||||
password = pwd;
|
||||
chat();
|
||||
} else {
|
||||
notice("password does not match");
|
||||
}
|
||||
}
|
||||
|
||||
/// Create Password Entry Field
|
||||
/** Asks user for password. When user starts to enter it, it is
|
||||
permanentely checked in setpw(). As soon as the password matches,
|
||||
setpw() continues automatically. No submit is required by the
|
||||
user. */
|
||||
function getpwd() {
|
||||
$("#removeKey").show();
|
||||
status("getpwd");
|
||||
}
|
||||
|
||||
function deleteUser() {
|
||||
var uid = userid();
|
||||
localStorage.pubkey = null;
|
||||
localStorage.privkey = null;
|
||||
error("user "+uid+" permanentely lost");
|
||||
}
|
||||
|
||||
function removeKey() {
|
||||
togglemenu();
|
||||
$("#removeKey").hide();
|
||||
status('forgotpassword');
|
||||
}
|
||||
|
||||
/// Main Chat Window
|
||||
/** Gets chat widgets from server and displays them. Starts timer for
|
||||
get() which polls for new messages. */
|
||||
function chat() {
|
||||
if (!password) return getpwd();
|
||||
if ($('#msgs').is(':empty'))
|
||||
emit("messages");
|
||||
else
|
||||
status("chat");
|
||||
}
|
||||
|
||||
/// Login User
|
||||
/** This is not really a login, it is just some kind of validation.
|
||||
The server does not care if a user is online or not, it is only
|
||||
interesting to the client to make sure, everything is fine. User
|
||||
is logged in the following way: User name and public key are sent
|
||||
to the server. If the user name exists on the server and the
|
||||
public key is the same, the user is considered logged in, his
|
||||
credentials seem to be valid. If user does not yet exits on
|
||||
server, it is created now. If user exists, but public key is
|
||||
different, then this is a complete failure, something went
|
||||
terribly wrong. */
|
||||
function login() {
|
||||
$("#username").html(userid()+"@"+window.location.hostname);
|
||||
emit("login", {name: userid(),
|
||||
pubkey: localStorage.pubkey});
|
||||
success("login sent to server");
|
||||
}
|
||||
|
||||
/// Get And Display Form To Create New User
|
||||
/** Shows user creation form. On submit, a private key is generated in
|
||||
createkeypair(), then login() creates the user. */
|
||||
function newuser() {
|
||||
status("newuser");
|
||||
}
|
||||
|
||||
/// Check if local storage is available
|
||||
function checkLocalStorage() {
|
||||
var test = 'test';
|
||||
try {
|
||||
localStorage.setItem(test, test);
|
||||
localStorage.removeItem(test);
|
||||
return true;
|
||||
} catch(e) {
|
||||
status("nolocalstorage");
|
||||
error("local storage not available");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Initial Function: Startup
|
||||
/** Decide whether to login or to create a new user */
|
||||
function start() {
|
||||
$("#menu").hide();
|
||||
//status("startup");
|
||||
if (checkLocalStorage())
|
||||
try {
|
||||
if (!userid()) {
|
||||
newuser();
|
||||
} else {
|
||||
login();
|
||||
}
|
||||
} catch (m) {
|
||||
console.log(m.stack);
|
||||
error(m);
|
||||
}
|
||||
}
|
||||
|
||||
function init() {
|
||||
/// On Load, Call @ref start
|
||||
$(window.onbeforeunload = function() {
|
||||
return "Are you sure you want to navigate away?";
|
||||
});
|
||||
/// Allow Running in Background on Android
|
||||
document.addEventListener('deviceready', function () {
|
||||
if (cordova && cordova.plugins.backgroundMode) {
|
||||
cordova.plugins.backgroundMode.enable();
|
||||
}
|
||||
}, false);
|
||||
socket.io.on("connect", connected());
|
||||
socket.io.on("reconnect", connected());
|
||||
socket.io.on("disconnect", disconnected());
|
||||
socket.io.on("error", disconnected());
|
||||
socket.on("login", loggedin);
|
||||
socket.on("fail", fail);
|
||||
socket.on("user", user);
|
||||
socket.on("users", users);
|
||||
socket.on("message", message);
|
||||
socket.on("messages", messages);
|
||||
connectionstatus();
|
||||
emit('users');
|
||||
start();
|
||||
}
|
||||
|
||||
/// Start Main Loop
|
||||
$(init);
|
Reference in New Issue
Block a user