Major move towards castrato awareness
This commit is contained in:
parent
507df4ea58
commit
4f4f7c4325
|
@ -1,26 +1,31 @@
|
||||||
/* Usage:
|
/* Usage:
|
||||||
|
|
||||||
mediator.emit('audio:play',message);
|
mediator.on('audio:play', playTones );
|
||||||
mediator.emit('audio:on');
|
mediator.on('audio:on', on );
|
||||||
mediator.emit('audio:off');
|
mediator.on('audio:off', off );
|
||||||
|
mediator.on('audio:mute', mute );
|
||||||
|
mediator.on('audio:unmute', unmute );
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Sounds module, used for emitting those annoying bl-up sounds when receiving a message
|
// Sounds module, used for emitting those annoying bl-up sounds when receiving a message
|
||||||
define(['queue','mediator'], function (queue,mediator) {
|
define(['queue','castrato','templates'], function (queue,mediator,templates) {
|
||||||
|
|
||||||
var ac = false,
|
var
|
||||||
|
// Private variables
|
||||||
|
ac = false,
|
||||||
enabled = true,
|
enabled = true,
|
||||||
|
muted = false,
|
||||||
|
|
||||||
// Recursive function for playing tones, takes an array of [tone,start_ms,duration_ms] - entries
|
// Recursive function for playing tones
|
||||||
// i is only used for recursion
|
// accepts an array of [tone,start_ms,duration_ms] - entries
|
||||||
playTones = function (tones, i) {
|
playTones = function (tones, i) {
|
||||||
|
|
||||||
// Parameter defaults
|
// Parameter defaults
|
||||||
i = (i === undefined) ? 0 : i;
|
i = (i === undefined) ? 0 : i;
|
||||||
|
|
||||||
// Stop if we've reached the end of iteration, and require ac
|
// Stop if we've reached the end of iteration, and require ac, also stop if we're muted
|
||||||
if (!ac || !enabled || !(i < Object.keys(tones).length)) {
|
if (!ac || !enabled || !(i < Object.keys(tones).length) || muted) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,14 +61,28 @@ define(['queue','mediator'], function (queue,mediator) {
|
||||||
|
|
||||||
off = function() {
|
off = function() {
|
||||||
enabled = false;
|
enabled = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
mute = function() {
|
||||||
|
muted = true;
|
||||||
|
mediator.emit('console:info',templates.messages.muted);
|
||||||
|
},
|
||||||
|
|
||||||
|
unmute = function() {
|
||||||
|
muted = false;
|
||||||
|
mediator.emit('console:info',templates.messages.unmuted);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Find audio context
|
||||||
if (window.AudioContext || window.webkitAudioContext) {
|
if (window.AudioContext || window.webkitAudioContext) {
|
||||||
ac = new (window.AudioContext || window.webkitAudioContext);
|
ac = new (window.AudioContext || window.webkitAudioContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
mediator.on('audio:play', function (message) { playTones(message); });
|
// Connect events
|
||||||
mediator.on('audio:on', function (message) { on(); });
|
mediator.on('audio:play', function(tones) {playTones(tones); } );
|
||||||
mediator.on('audio:off', function (message) { off(); });
|
mediator.on('audio:on', on );
|
||||||
|
mediator.on('audio:off', off );
|
||||||
|
mediator.on('audio:mute', mute );
|
||||||
|
mediator.on('audio:unmute', unmute );
|
||||||
|
|
||||||
});
|
});
|
|
@ -0,0 +1,3 @@
|
||||||
|
// Licenced under MIT - castrato - ©2014 Pehr Boman <github.com/unkelpehr>
|
||||||
|
(function(f,g){"function"===typeof define&&define.amd?define([],g()):"object"===typeof exports?module.exports=g:f.castrato=g})(this,function(){function f(e,a,b,c){var d=[e,b,1<b.length];(l[a]||(l[a]=[])).push(d);if(m[a])for(e=0,d=[d];(b=m[a][e++])&&(k(0,0,b[0],b[1],d),!c););}function g(e,a,b){var c=0;if(toSubs=l[a])for(;a=toSubs[c++];)a[0]!==e||b&&b!==a[1]||toSubs.splice(--c,1)}function k(e,a,b,c,d){var g=d||l[a]||[],h=g.length,f=h,k=h,n=[],p;if(k)for(p=c?function(a){a&&n.push(a);--f||(c(n,h),c=0)}:
|
||||||
|
q;d=g[--k];)d[1](b,d[2]?p:f--);!f&&c&&c(n,h);e&&(m[a]||(m[a]=[])).push([b,c])}var r=0,l={},m={},q=function(){};return function(){var e=r++;return{emit:function(a,b,c,d){!0!==a&&!1!==a&&(d=c,c=b,b=a,a=!1);k(a,b,c,d);return this},on:function(a,b){f(e,a,b);return this},once:function(a,b){f(e,a,function d(f,h){g(e,a,d);b(f,1<b.length?h:h())},!0);return this},off:function(a,b){g(e,a,b);return this}}}}());
|
|
@ -0,0 +1,85 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
Accepts:
|
||||||
|
mediator.on('command:help', ...);
|
||||||
|
mediator.on('command:nick', ...);
|
||||||
|
mediator.on('command:key', ...);
|
||||||
|
mediator.on('command:clear', ...);
|
||||||
|
|
||||||
|
Emits:
|
||||||
|
mediator.emit('nick:changed',...);
|
||||||
|
mediator.emit('key:changed',...);
|
||||||
|
mediator.emit('console:clear',...);
|
||||||
|
mediator.emit('console:info',...);
|
||||||
|
mediator.emit('console:error',...);
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
|
define(
|
||||||
|
{
|
||||||
|
compiles: ['$'],
|
||||||
|
requires: ['castrato','settings','templates']
|
||||||
|
}, function ($, requires, data) {
|
||||||
|
|
||||||
|
var
|
||||||
|
// Private properties
|
||||||
|
nick,
|
||||||
|
key,
|
||||||
|
|
||||||
|
// Require shortcuts
|
||||||
|
mediator = requires.castrato,
|
||||||
|
settings = requires.settings,
|
||||||
|
templates = requires.templates,
|
||||||
|
|
||||||
|
setKey = function(payload) {
|
||||||
|
/*if (!host) {
|
||||||
|
return post('error', templates.messages.key_no_host);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
// Make sure the key meets the length requirements
|
||||||
|
if (payload.length > settings.key.maxLen) {
|
||||||
|
return mediator.emit('console:error',templates.messages.key_to_long);
|
||||||
|
} else if (payload.length < settings.key.minLen) {
|
||||||
|
return mediator.emit('console:error',templates.messages.key_to_short);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set key
|
||||||
|
key = payload;
|
||||||
|
|
||||||
|
// Keep other modules informed
|
||||||
|
mediator.emit('key:changed',key);
|
||||||
|
|
||||||
|
// Inform that the key has been set
|
||||||
|
return mediator.emit('console:info', templates.messages.key_ok );
|
||||||
|
},
|
||||||
|
|
||||||
|
help = function (payload, done) { mediator.emit('console:motd', templates.help); },
|
||||||
|
|
||||||
|
clear = function () { mediator.emit('console:clear'); },
|
||||||
|
|
||||||
|
nick = function (payload) {
|
||||||
|
|
||||||
|
// Make sure the nick meets the length requirements
|
||||||
|
if (payload.length > settings.nick.maxLen) {
|
||||||
|
return mediator('console:error', $.template(templates.messages.nick_to_long, { nick_maxLen: settings.nick.maxLen } ));
|
||||||
|
} else if (payload.length < settings.nick.minLen) {
|
||||||
|
return mediator('console:error', $.template(templates.messages.nick_to_short, {nick_minLen: settings.nick.minLen } ));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set nick
|
||||||
|
nick = payload;
|
||||||
|
|
||||||
|
// Keep other modules informed
|
||||||
|
mediator.emit('nick:changed',nick);
|
||||||
|
|
||||||
|
// Inform that the nick has been set
|
||||||
|
mediator.emit('console:info', $.template(templates.messages.nick_set, { nick: $.escapeHtml(nick)}));
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
mediator.on('command:help', help);
|
||||||
|
mediator.on('command:clear', clear);
|
||||||
|
mediator.on('command:nick', nick);
|
||||||
|
mediator.on('command:key', setKey);
|
||||||
|
|
||||||
|
});
|
|
@ -0,0 +1,194 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
Accepts:
|
||||||
|
mediator.on('console:clear', clear);
|
||||||
|
mediator.on('console:motd', motd);
|
||||||
|
mediator.on('console:info', info);
|
||||||
|
mediator.on('console:error', error);
|
||||||
|
mediator.on('console:server', server);
|
||||||
|
mediator.on('console:message', message);
|
||||||
|
mediator.on('console:lockinput', lockInput);
|
||||||
|
mediator.on('console:unlockinput', unlockInput);
|
||||||
|
mediator.on('console:param', param);
|
||||||
|
|
||||||
|
Emits:
|
||||||
|
mediator.emit('notification:send',...);
|
||||||
|
mediator.emit('audio:play',...);
|
||||||
|
ToDo
|
||||||
|
*/
|
||||||
|
define(
|
||||||
|
{
|
||||||
|
compiles: ['$'],
|
||||||
|
requires: ['castrato','fandango','settings','templates','sounds','room','notifications','audio']
|
||||||
|
}, function ($, requires, data) {
|
||||||
|
|
||||||
|
var
|
||||||
|
|
||||||
|
// Require shortcuts
|
||||||
|
fandango = requires.fandango,
|
||||||
|
mediator = requires.castrato,
|
||||||
|
settings = requires.settings,
|
||||||
|
templates = requires.templates,
|
||||||
|
sounds = requires.sounds,
|
||||||
|
|
||||||
|
// Collection of DOM components
|
||||||
|
components = {
|
||||||
|
chat: $('#chat'),
|
||||||
|
input: $('#input'),
|
||||||
|
inputWrapper: $('#input_wrapper')
|
||||||
|
},
|
||||||
|
|
||||||
|
// Collection of parameters
|
||||||
|
parameters = {},
|
||||||
|
|
||||||
|
// Adds a new message to the DOM
|
||||||
|
post = function (type, text, nick) {
|
||||||
|
|
||||||
|
var tpl = templates.post[type],
|
||||||
|
post,
|
||||||
|
data = fandango.merge({}, settings, {
|
||||||
|
nick: nick
|
||||||
|
});
|
||||||
|
|
||||||
|
data.text = $.template(text, data);
|
||||||
|
post = $.template(tpl, data);
|
||||||
|
|
||||||
|
// Request a notification
|
||||||
|
showNotification(type, nick, text);
|
||||||
|
|
||||||
|
// Append the post to the chat DOM element
|
||||||
|
components.chat['append'](post);
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
param = function (p) {
|
||||||
|
parameters = fandango.merge({}, parameters, p );
|
||||||
|
},
|
||||||
|
|
||||||
|
showNotification = function (type, nick, text) {
|
||||||
|
|
||||||
|
var title = (type!='message') ? 'Cryptalk' : nick,
|
||||||
|
icon = (type == 'message') ? 'gfx/icon_128x128.png' : (type == 'error') ? 'gfx/icon_128x128_error.png' : 'gfx/icon_128x128_info.png';
|
||||||
|
|
||||||
|
// Emit notification
|
||||||
|
mediator.emit('notification:send',
|
||||||
|
{
|
||||||
|
title: title.substring(0, 20),
|
||||||
|
body: text.substring(0, 80),
|
||||||
|
icon: icon
|
||||||
|
});
|
||||||
|
|
||||||
|
// Emit sound
|
||||||
|
if ( type == 'message' ) mediator.emit('audio:play',sounds.message);
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
motd = function (payload, done) { post('motd', payload); },
|
||||||
|
info = function (payload, done) { post('info', payload); },
|
||||||
|
error = function (payload, done) { post('error', payload); },
|
||||||
|
message = function (payload, done) { post('message', payload.message , payload.nick ); },
|
||||||
|
server = function (payload, done) { post('server', payload); },
|
||||||
|
|
||||||
|
clear = function () {
|
||||||
|
fandango.subordinate(function () {
|
||||||
|
components.input[0].value = '';
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
lockInput = function () {
|
||||||
|
components.input[0].setAttribute('disabled', 'disabled');
|
||||||
|
components.inputWrapper[0].className = 'loading';
|
||||||
|
},
|
||||||
|
|
||||||
|
unlockInput = function () {
|
||||||
|
components.input[0].removeAttribute('disabled');
|
||||||
|
components.inputWrapper[0].className = '';
|
||||||
|
components.input.focus();
|
||||||
|
},
|
||||||
|
|
||||||
|
// Handler for the document`s keyDown-event.
|
||||||
|
onKeyDown = function (e) {
|
||||||
|
var buffer,
|
||||||
|
parts,
|
||||||
|
payload,
|
||||||
|
command,
|
||||||
|
save;
|
||||||
|
|
||||||
|
// The Document object is bound to this element.
|
||||||
|
// If the active element is not the input, focus on it and exit the function.
|
||||||
|
// Ignore this when ctrl and/or alt is pressed!
|
||||||
|
if (!e.ctrlKey && !e.altKey && components.input[0] !== $.activeElement()) {
|
||||||
|
return components.input.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return immediatly if the buffer is empty or if the hit key was not <enter>
|
||||||
|
if (e.keyCode !== 13 || !(buffer = components.input[0].value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle command
|
||||||
|
if ((buffer[0] || buffer.slice(0, 1)) === '/') {
|
||||||
|
parts = $.ssplit(buffer.slice(1), ' ');
|
||||||
|
command = parts[0];
|
||||||
|
payload = parts[1];
|
||||||
|
|
||||||
|
// Shout this command to all modules
|
||||||
|
mediator.emit(
|
||||||
|
'command:'+command,
|
||||||
|
payload,
|
||||||
|
function(retvals,recipients) {
|
||||||
|
if(recipients == 0) {
|
||||||
|
return post('error', $.template(templates.messages.unrecognized_command, { commandName: command }));
|
||||||
|
} else {
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
} else /* Handle ordinary message */ {
|
||||||
|
|
||||||
|
if(!parameters.room || !parameters.key ) {
|
||||||
|
// Make sure that the user has joined a room and the key is set
|
||||||
|
return (!parameters.room) ? post('error', templates.messages.msg_no_room) : post('error', templates.messages.msg_no_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(parameters.room);
|
||||||
|
|
||||||
|
// Before sending the message.
|
||||||
|
// Encrypt message using room UUID as salt and key as pepper.
|
||||||
|
mediator.emit(
|
||||||
|
'socket:emit',
|
||||||
|
{
|
||||||
|
data: 'message:send',
|
||||||
|
payload: {
|
||||||
|
room: $.SHA1(parameters.room),
|
||||||
|
msg: $.AES.encrypt(buffer, $.SHA1(parameters.room) + parameters.key).toString(),
|
||||||
|
nick: parameters.nick ? $.AES.encrypt(parameters.nick, $.SHA1(parameters.room) + parameters.key).toString() : false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// And clear the the buffer
|
||||||
|
clear();
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Bind the necessary DOM events
|
||||||
|
$(document).on('keydown', onKeyDown);;
|
||||||
|
|
||||||
|
// Put focus on the message input
|
||||||
|
components.input.focus();
|
||||||
|
|
||||||
|
// Connect events
|
||||||
|
mediator.on('console:clear', clear);
|
||||||
|
mediator.on('console:motd', motd);
|
||||||
|
mediator.on('console:info', info);
|
||||||
|
mediator.on('console:error', error);
|
||||||
|
mediator.on('console:server', server);
|
||||||
|
mediator.on('console:message', message);
|
||||||
|
mediator.on('console:lockinput', lockInput);
|
||||||
|
mediator.on('console:unlockinput', unlockInput);
|
||||||
|
mediator.on('console:param', param);
|
||||||
|
|
||||||
|
});
|
|
@ -1,554 +1,49 @@
|
||||||
// Main cryptalk module
|
// Main cryptalk module
|
||||||
define({
|
define({
|
||||||
compiles: ['$'],
|
compiles: ['$'],
|
||||||
requires: ['mediator', 'hosts', 'templates', 'audio', 'fandango','notifications', 'sounds', 'window']
|
requires: ['castrato','console','host','client']
|
||||||
}, function ($, requires, data) {
|
}, function ($, requires, data) {
|
||||||
|
|
||||||
var socket,
|
// Require shortcut
|
||||||
key,
|
var mediator = requires.castrato;
|
||||||
host,
|
|
||||||
room,
|
|
||||||
room_raw,
|
|
||||||
hash,
|
|
||||||
nick,
|
|
||||||
mute = false,
|
|
||||||
|
|
||||||
settings = {},
|
|
||||||
|
|
||||||
history = [],
|
|
||||||
history_pos = -1,
|
|
||||||
history_keep = 4,
|
|
||||||
history_timer,
|
|
||||||
|
|
||||||
// Collection of DOM components
|
|
||||||
components = {
|
|
||||||
chat: $('#chat'),
|
|
||||||
input: $('#input'),
|
|
||||||
inputWrapper: $('#input_wrapper')
|
|
||||||
},
|
|
||||||
|
|
||||||
// Shortcut
|
|
||||||
hosts = requires.hosts,
|
|
||||||
fandango = requires.fandango,
|
|
||||||
mediator = requires.mediator,
|
|
||||||
templates = requires.templates,
|
|
||||||
sounds = requires.sounds,
|
|
||||||
win = requires.window,
|
|
||||||
|
|
||||||
lockInput = function () {
|
|
||||||
components.input[0].setAttribute('disabled', 'disabled');
|
|
||||||
components.inputWrapper[0].className = 'loading';
|
|
||||||
},
|
|
||||||
|
|
||||||
unlockInput = function () {
|
|
||||||
components.input[0].removeAttribute('disabled');
|
|
||||||
components.inputWrapper[0].className = '';
|
|
||||||
components.input.focus();
|
|
||||||
},
|
|
||||||
|
|
||||||
showNotification = function (type, nick, text) {
|
|
||||||
|
|
||||||
var title = (type!='message') ? 'Cryptalk' : nick,
|
|
||||||
icon = (type == 'message') ? 'gfx/icon_128x128.png' : (type == 'error') ? 'gfx/icon_128x128_error.png' : 'gfx/icon_128x128_info.png';
|
|
||||||
|
|
||||||
// Emit notification
|
|
||||||
mediator.emit('notification:send',
|
|
||||||
{
|
|
||||||
title: title.substring(0, 20),
|
|
||||||
body: text.substring(0, 80),
|
|
||||||
icon: icon
|
|
||||||
});
|
|
||||||
|
|
||||||
// Emit sound
|
|
||||||
if ( type == 'message' ) mediator.emit('audio:play',sounds.message);
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
// Adds a new message to the DOM
|
|
||||||
post = function (type, text, clearChat, clearBuffer, nick) {
|
|
||||||
|
|
||||||
var tpl = templates.post[type],
|
|
||||||
post,
|
|
||||||
data = fandango.merge({}, settings, {
|
|
||||||
nick: nick,
|
|
||||||
room: room
|
|
||||||
});
|
|
||||||
|
|
||||||
data.text = $.template(text, data);
|
|
||||||
post = $.template(tpl, data);
|
|
||||||
|
|
||||||
// Always clear the input after a post
|
|
||||||
if (clearBuffer) {
|
|
||||||
clearInput();
|
|
||||||
}
|
|
||||||
|
|
||||||
showNotification(type, nick, text);
|
|
||||||
|
|
||||||
// Append the post to the chat DOM element
|
|
||||||
components.chat[clearChat ? 'html' : 'append'](post);
|
|
||||||
},
|
|
||||||
|
|
||||||
// Chat related commands
|
|
||||||
commands = {
|
|
||||||
help: function (payload, done) {
|
|
||||||
post('motd', templates.help);
|
|
||||||
done();
|
|
||||||
},
|
|
||||||
|
|
||||||
host: function () {
|
|
||||||
post('info', JSON.stringify(host || {}));
|
|
||||||
},
|
|
||||||
|
|
||||||
hosts: function (force, done) {
|
|
||||||
var i = 0,
|
|
||||||
left = hosts.hosts.length,
|
|
||||||
host,
|
|
||||||
strhosts = '\n',
|
|
||||||
callback = function (host, index, isUp) {
|
|
||||||
return function (hostSettings) {
|
|
||||||
host.settings = (isUp ? hostSettings : 0);
|
|
||||||
|
|
||||||
strhosts += $.template(templates.messages[(isUp ? 'host_available' : 'host_unavailable')], {
|
|
||||||
name: host.name,
|
|
||||||
path: host.path,
|
|
||||||
index: index
|
|
||||||
});
|
|
||||||
|
|
||||||
if (--left === 0) {
|
|
||||||
post('info', strhosts);
|
|
||||||
done();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
|
||||||
force = (force && force.toLowerCase() === 'force');
|
|
||||||
|
|
||||||
// Loop through all the hosts
|
|
||||||
while ((host = hosts.hosts[i])) {
|
|
||||||
if (!force && host.settings !== undefined) {
|
|
||||||
if (host.settings) {
|
|
||||||
callback(host, i, 1)();
|
|
||||||
} else {
|
|
||||||
callback(host, i, 0)();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
require([host.path], callback(host, i, 1), callback(host, i, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
connect: function (toHost, done) {
|
|
||||||
var request;
|
|
||||||
|
|
||||||
if (host && host.connected) {
|
|
||||||
done();
|
|
||||||
post('error', $.template(templates.messages.already_connected, {
|
|
||||||
host: host.name || 'localhost'
|
|
||||||
}));
|
|
||||||
return done();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($.isDigits(toHost)) {
|
|
||||||
if ((host = hosts.hosts[+toHost])) {
|
|
||||||
if (host.settings) {
|
|
||||||
settings = host.settings;
|
|
||||||
} else {
|
|
||||||
request = host.path;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
post('error', 'Undefined host index: ' + toHost);
|
|
||||||
return done();
|
|
||||||
}
|
|
||||||
} else if (fandango.is(toHost, 'untyped')) {
|
|
||||||
settings = toHost.settings;
|
|
||||||
} else { // Assume string
|
|
||||||
request = toHost;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (request) {
|
|
||||||
return require([request], function (settings) {
|
|
||||||
host.settings = settings;
|
|
||||||
commands.connect(toHost, done);
|
|
||||||
}, function () {
|
|
||||||
post('error', 'Could not fetch host settings: ' + request);
|
|
||||||
return done();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Push 'Connecting...' message
|
|
||||||
post('info', $.template(templates.messages.connecting, {
|
|
||||||
host: host.name || 'localhost'
|
|
||||||
}));
|
|
||||||
|
|
||||||
// The one and only socket
|
|
||||||
socket = $.Websocket.connect(host.host, {
|
|
||||||
forceNew: true,
|
|
||||||
'force new connection': true
|
|
||||||
});
|
|
||||||
|
|
||||||
// Set window title
|
|
||||||
win.setTitle(settings.client.title);
|
|
||||||
|
|
||||||
// Bind socket events
|
|
||||||
socket
|
|
||||||
|
|
||||||
.on('room:joined', function (data) {
|
|
||||||
room = $.escapeHtml(data);
|
|
||||||
|
|
||||||
post('info', $.template(templates.messages.joined_room, { roomName: $.escapeHtml(room_raw) }));
|
|
||||||
|
|
||||||
// Automatically count persons on join
|
|
||||||
socket.emit('room:count');
|
|
||||||
})
|
|
||||||
|
|
||||||
.on('room:left', function () {
|
|
||||||
post('info', $.template(templates.messages.left_room, { roomName: $.escapeHtml(room_raw) }));
|
|
||||||
|
|
||||||
// Clear history on leaving room
|
|
||||||
clearHistory();
|
|
||||||
|
|
||||||
room = false;
|
|
||||||
room_raw = "";
|
|
||||||
})
|
|
||||||
|
|
||||||
.on('message:send', function (data) {
|
|
||||||
var decrypted = $.AES.decrypt(data.msg, room + key),
|
|
||||||
sanitized = $.escapeHtml(decrypted),
|
|
||||||
nick = !data.nick ? templates.default_nick : $.escapeHtml($.AES.decrypt(data.nick, room + key));
|
|
||||||
|
|
||||||
if (!decrypted) {
|
|
||||||
post('error', templates.messages.unable_to_decrypt);
|
|
||||||
} else {
|
|
||||||
post('message', sanitized, false, false, nick);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
.on('message:server', function (data) {
|
|
||||||
if( data.msg ) {
|
|
||||||
var sanitized = $.escapeHtml(data.msg);
|
|
||||||
if( templates.server[sanitized] ) {
|
|
||||||
if( data.payload !== undefined ) {
|
|
||||||
var sanitized_payload = $.escapeHtml(data.payload);
|
|
||||||
post('server', $.template(templates.server[sanitized], { payload: sanitized_payload }));
|
|
||||||
} else {
|
|
||||||
post('server', templates.server[sanitized]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
post('error', templates.server.bogus);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
post('error', templates.server.bogus);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
.on('connect', function () {
|
|
||||||
// Tell the user that the chat is ready to interact with
|
|
||||||
post('info', $.template(templates.messages.connected, {
|
|
||||||
host: host.name || 'localhost'
|
|
||||||
}));
|
|
||||||
|
|
||||||
host.connected = 1;
|
|
||||||
|
|
||||||
done();
|
|
||||||
})
|
|
||||||
|
|
||||||
.on('disconnect', function () {
|
|
||||||
room = 0;
|
|
||||||
key = 0;
|
|
||||||
host.connected = 0;
|
|
||||||
|
|
||||||
// Tell the user that the chat is ready to interact with
|
|
||||||
post('info', $.template(templates.messages.disconnected, {
|
|
||||||
host: host.name || 'localhost'
|
|
||||||
}));
|
|
||||||
|
|
||||||
// Revert title
|
|
||||||
win.setTitle(templates.client.title);
|
|
||||||
})
|
|
||||||
|
|
||||||
.on('error', function () {
|
|
||||||
room = 0;
|
|
||||||
key = 0;
|
|
||||||
host.connected = 0;
|
|
||||||
post('error', templates.messages.socket_error);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
reconnect: function (foo, done) {
|
|
||||||
if (host) {
|
|
||||||
if (host.connected) {
|
|
||||||
commands.disconnect();
|
|
||||||
commands.connect(host, done);
|
|
||||||
} else {
|
|
||||||
commands.connect(host, done);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
done();
|
|
||||||
return post('error', templates.messages.reconnect_no_host);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
disconnect: function () {
|
|
||||||
socket.disconnect();
|
|
||||||
},
|
|
||||||
|
|
||||||
clear: function () {
|
|
||||||
components.chat.html('');
|
|
||||||
|
|
||||||
// Clear command history on clearing buffer
|
|
||||||
clearHistory();
|
|
||||||
},
|
|
||||||
|
|
||||||
leave: function () {
|
|
||||||
if (room) {
|
|
||||||
socket.emit('room:leave', room);
|
|
||||||
} else {
|
|
||||||
post('error', templates.messages.leave_from_nowhere);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
count: function () {
|
|
||||||
if (room) {
|
|
||||||
socket.emit('room:count');
|
|
||||||
} else {
|
|
||||||
post('error', templates.messages.not_in_room);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
key: function (payload) {
|
|
||||||
if (!host) {
|
|
||||||
return post('error', templates.messages.key_no_host);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure the key meets the length requirements
|
|
||||||
if (payload.length > settings.key.maxLen) {
|
|
||||||
return post('error', $.template(templates.messages.key_to_long, { key_maxLen: settings.key_maxLen } ));
|
|
||||||
} else if (payload.length < settings.key.minLen) {
|
|
||||||
return post('error', $.template(templates.messages.key_to_short, { key_maxLen: settings.key_minLen } ));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set key
|
|
||||||
key = payload;
|
|
||||||
|
|
||||||
// Inform that the key has been set
|
|
||||||
post('info', (room ? templates.messages.key_ok_ready : templates.messages.key_ok_but_no_room));
|
|
||||||
},
|
|
||||||
|
|
||||||
nick: function (payload) {
|
|
||||||
// Make sure the key meets the length requirements
|
|
||||||
if (payload.length > settings.nick.maxLen) {
|
|
||||||
return post('error', $.template(templates.messages.nick_to_long, { nick_maxLen: settings.nick.maxLen } ));
|
|
||||||
} else if (payload.length < settings.nick.minLen) {
|
|
||||||
return post('error', $.template(templates.messages.nick_to_short, {nick_minLen: settings.nick.minLen } ));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set nick
|
|
||||||
nick = payload;
|
|
||||||
|
|
||||||
// Inform that the key has been set
|
|
||||||
post('info', $.template(templates.messages.nick_set, { nick: $.escapeHtml(nick)}));
|
|
||||||
},
|
|
||||||
|
|
||||||
mute: function () {
|
|
||||||
mute = true;
|
|
||||||
return post('info', templates.messages.muted);
|
|
||||||
},
|
|
||||||
|
|
||||||
unmute: function () {
|
|
||||||
mute = false;
|
|
||||||
return post('info', templates.messages.unmuted);
|
|
||||||
},
|
|
||||||
|
|
||||||
title: function (payload) {
|
|
||||||
win.setTitle(payload);
|
|
||||||
return post('info', $.template(templates.messages.title_set, { title: $.escapeHtml(payload)}));
|
|
||||||
},
|
|
||||||
|
|
||||||
join: function (payload) {
|
|
||||||
if (!host) {
|
|
||||||
return post('error', templates.messages.join_no_host);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (room) {
|
|
||||||
return post('error', templates.messages.already_in_room);
|
|
||||||
} else {
|
|
||||||
room_raw = payload;
|
|
||||||
return socket.emit('room:join', $.SHA1(payload))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
// Push input buffer to history
|
|
||||||
pushHistory = function (b) {
|
|
||||||
history.push(b);
|
|
||||||
|
|
||||||
// Shift oldest buffer if we have more than we should keep
|
|
||||||
if (history.length > history_keep) {
|
|
||||||
history.shift();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// Clear input buffer history
|
|
||||||
clearHistory = function() {
|
|
||||||
history = [];
|
|
||||||
history_pos = -1;
|
|
||||||
},
|
|
||||||
|
|
||||||
// Clear input buffer
|
|
||||||
clearInput = function() {
|
|
||||||
fandango.subordinate(function () {
|
|
||||||
components.input[0].value = '';
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
// Handler for the document`s keyDown-event.
|
|
||||||
onKeyDown = function (e) {
|
|
||||||
var buffer,
|
|
||||||
parts,
|
|
||||||
payload,
|
|
||||||
command,
|
|
||||||
save;
|
|
||||||
|
|
||||||
// The Document object is bound to this element.
|
|
||||||
// If the active element is not the input, focus on it and exit the function.
|
|
||||||
// Ignore this when ctrl and/or alt is pressed!
|
|
||||||
if (!e.ctrlKey && !e.altKey && components.input[0] !== $.activeElement()) {
|
|
||||||
return components.input.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset command history clear timer
|
|
||||||
clearTimeout(history_timer);
|
|
||||||
history_timer = setTimeout(clearHistory, 60000);
|
|
||||||
|
|
||||||
// Check for escape key, this does nothing but clear the input buffer and reset history position
|
|
||||||
if (e.keyCode == 27) {
|
|
||||||
history_pos = -1;
|
|
||||||
clearInput();
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for up or down-keys, they handle the history position
|
|
||||||
if (e.keyCode == 38 || e.keyCode == 40) {
|
|
||||||
|
|
||||||
if (e.keyCode == 38 ) { history_pos = (history_pos > history.length - 2) ? -1 : history_pos = history_pos + 1; }
|
|
||||||
else { history_pos = (history_pos <= 0) ? -1 : history_pos = history_pos - 1; }
|
|
||||||
|
|
||||||
var input = components.input[0];
|
|
||||||
input.value = (history_pos == -1) ? '' : history[history.length-1-history_pos];
|
|
||||||
|
|
||||||
// Wierd hack to move caret to end of input-box
|
|
||||||
setTimeout(function() {if(input.setSelectionRange) input.setSelectionRange(input.value.length, input.value.length);}, 0);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return immediatly if the buffer is empty or if the hit key was not <enter>
|
|
||||||
if (e.keyCode !== 13 || !(buffer = components.input[0].value)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset current history position to 0 (last command)
|
|
||||||
history_pos = -1;
|
|
||||||
|
|
||||||
// Handle command
|
|
||||||
if ((buffer[0] || buffer.slice(0, 1)) === '/') {
|
|
||||||
parts = $.ssplit(buffer.slice(1), ' ');
|
|
||||||
command = parts[0];
|
|
||||||
payload = parts[1];
|
|
||||||
|
|
||||||
// Check that there is an handler for this command
|
|
||||||
if (!commands[command]) {
|
|
||||||
pushHistory(buffer);
|
|
||||||
return post('error', $.template(templates.messages.unrecognized_command, { commandName: command }));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Some commands are asynchrounous;
|
|
||||||
// If the command expects more than one argument, the second argument is a callback that is called when the command is done.
|
|
||||||
if (commands[command].length > 1) {
|
|
||||||
// Lock the input from further interaction
|
|
||||||
lockInput();
|
|
||||||
|
|
||||||
// Execute command handler with callback function.
|
|
||||||
commands[command](payload, unlockInput);
|
|
||||||
} else {
|
|
||||||
// Execute normally.
|
|
||||||
commands[command](payload);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear input field
|
|
||||||
clearInput();
|
|
||||||
|
|
||||||
// Save to history
|
|
||||||
if(command !== 'key') {
|
|
||||||
pushHistory(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else /* Handle ordinary message */ {
|
|
||||||
|
|
||||||
if (!room || !key) {
|
|
||||||
// Push buffer to history and clear input field
|
|
||||||
pushHistory(buffer); clearInput();
|
|
||||||
|
|
||||||
// Make sure that the user has joined a room and the key is set
|
|
||||||
return (!room) ? post('error', templates.messages.msg_no_room) : post('error', templates.messages.msg_no_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Before sending the message.
|
|
||||||
// Encrypt message using room UUID as salt and key as pepper.
|
|
||||||
socket.emit('message:send', {
|
|
||||||
room: room,
|
|
||||||
msg: $.AES.encrypt(buffer, room + key).toString(),
|
|
||||||
nick: nick ? $.AES.encrypt(nick, room + key).toString() : false
|
|
||||||
});
|
|
||||||
|
|
||||||
// And clear the the buffer
|
|
||||||
clearInput();
|
|
||||||
|
|
||||||
// Save to history
|
|
||||||
pushHistory(buffer);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Bind the necessary DOM events
|
|
||||||
$(document).on('keydown', onKeyDown);
|
|
||||||
|
|
||||||
// Put focus on the message input
|
|
||||||
components.input.focus();
|
|
||||||
|
|
||||||
// Post the help/welcome message
|
|
||||||
post('motd', templates.motd, true);
|
|
||||||
|
|
||||||
// Route mediator messages
|
// Route mediator messages
|
||||||
mediator.on('window:focused',function() {
|
mediator.on('window:focused',function() {
|
||||||
mediator.emit('audio:off');
|
mediator.emit('audio:off');
|
||||||
mediator.emit('notification:off');
|
mediator.emit('notification:off');
|
||||||
});
|
});
|
||||||
|
|
||||||
mediator.on('window:blurred',function() {
|
mediator.on('window:blurred',function() {
|
||||||
if( !mute ) mediator.emit('audio:on');
|
mediator.emit('audio:on');
|
||||||
mediator.emit('notification:on');
|
mediator.emit('notification:on');
|
||||||
});
|
});
|
||||||
|
|
||||||
unlockInput();
|
mediator.on('command:mute', function () { mediator.emit('audio:mute'); } );
|
||||||
|
mediator.on('command:unmute', function () { mediator.emit('audio:unmute'); } );
|
||||||
|
|
||||||
// Revert title
|
// Help console and host keep track of current states
|
||||||
win.setTitle(templates.client.title);
|
mediator.on('room:changed', function(room) {
|
||||||
|
mediator.emit('console:param',{ room: room});
|
||||||
// It's possible to provide room and key using the hashtag.
|
mediator.emit('host:param',{ room: room});
|
||||||
// The room and key is then seperated by semicolon (room:key).
|
});
|
||||||
// If there is no semicolon present, the complete hash will be treated as the room name and the key has to be set manually.
|
mediator.on('nick:changed', function(nick) {
|
||||||
commands.connect(hosts.autoconnect, function() {
|
mediator.emit('console:param',{ nick: nick});
|
||||||
if (host && (hash = window.location.hash)) {
|
});
|
||||||
parts = hash.slice(1).split(':');
|
mediator.on('key:changed', function(key) {
|
||||||
|
mediator.emit('console:param',{ key: key});
|
||||||
parts[0] && commands.join(parts[0]);
|
mediator.emit('host:param',{ key: key});
|
||||||
parts[1] && commands.key(parts[1]);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
// Connect to the default host
|
||||||
|
mediator.emit('command:connect', undefined, function() {
|
||||||
|
// Join room and set key if a hash in the format #Room:Key has been provided
|
||||||
|
if (hash = window.location.hash) {
|
||||||
|
parts = hash.slice(1).split(':');
|
||||||
|
|
||||||
|
parts[0] && mediator.emit('command:join',parts[0]);
|
||||||
|
parts[1] && mediator.emit('command:key',parts[1]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -0,0 +1,269 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
Accepts:
|
||||||
|
mediator.on('command:host', host);
|
||||||
|
mediator.on('command:hosts', hosts);
|
||||||
|
mediator.on('command:connect', connect);
|
||||||
|
mediator.on('command:disconnect', disconnect);
|
||||||
|
mediator.on('command:reconnect', disconnect);
|
||||||
|
|
||||||
|
Emits:
|
||||||
|
mediator.on('socket:emit', emit);
|
||||||
|
*/
|
||||||
|
define(
|
||||||
|
{
|
||||||
|
compiles: ['$'],
|
||||||
|
requires: ['fandango','castrato','settings','templates','hosts','window']
|
||||||
|
}, function ($, requires, data) {
|
||||||
|
|
||||||
|
var
|
||||||
|
|
||||||
|
// Private properties
|
||||||
|
socket,
|
||||||
|
host,
|
||||||
|
|
||||||
|
// Require shortcuts
|
||||||
|
fandango = requires.fandango,
|
||||||
|
mediator = requires.castrato,
|
||||||
|
settings = requires.settings,
|
||||||
|
templates = requires.templates,
|
||||||
|
hostconfig = requires.hosts,
|
||||||
|
|
||||||
|
// Collection of parameters
|
||||||
|
parameters = {},
|
||||||
|
|
||||||
|
emit = function(payload) {
|
||||||
|
// Route message from mediator to socket
|
||||||
|
console.log('EMIT:',payload.data,payload.payload);
|
||||||
|
if(socket) socket.emit(payload.data,payload.payload);
|
||||||
|
},
|
||||||
|
|
||||||
|
host = function () {
|
||||||
|
mediator.emit('info', JSON.stringify(host || {}));
|
||||||
|
},
|
||||||
|
|
||||||
|
hosts = function (force, done) {
|
||||||
|
|
||||||
|
var i = 0,
|
||||||
|
left = hostconfig.hosts.length,
|
||||||
|
host,
|
||||||
|
strhosts = '\n',
|
||||||
|
callback = function (host, index, isUp) {
|
||||||
|
return function (hostSettings) {
|
||||||
|
host.settings = (isUp ? hostSettings : 0);
|
||||||
|
|
||||||
|
strhosts += $.template(templates.messages[(isUp ? 'host_available' : 'host_unavailable')], {
|
||||||
|
name: host.name,
|
||||||
|
path: host.path,
|
||||||
|
index: index
|
||||||
|
});
|
||||||
|
|
||||||
|
if (--left === 0) {
|
||||||
|
mediator.emit('info', strhosts);
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
force = (force && force.toLowerCase() === 'force');
|
||||||
|
|
||||||
|
// Loop through all the hosts
|
||||||
|
while ((host = hostconfig.hosts[i])) {
|
||||||
|
if (!force && host.settings !== undefined) {
|
||||||
|
if (host.settings) {
|
||||||
|
callback(host, i, 1)();
|
||||||
|
} else {
|
||||||
|
callback(host, i, 0)();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
require([host.path], callback(host, i, 1), callback(host, i, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
connect = function (toHost, done) {
|
||||||
|
|
||||||
|
mediator.emit('console:lockinput');
|
||||||
|
|
||||||
|
var
|
||||||
|
request,
|
||||||
|
|
||||||
|
// Use hostconfig.autoconnect as default host
|
||||||
|
toHost = (toHost == undefined) ? hostconfig.autoconnect : toHost;
|
||||||
|
|
||||||
|
if (host && host.connected) {
|
||||||
|
mediator.emit('console:error', $.template(templates.messages.already_connected, {
|
||||||
|
host: host.name || 'localhost'
|
||||||
|
}));
|
||||||
|
mediator.emit('console:unlockinput');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($.isDigits(toHost)) {
|
||||||
|
if ((host = hostconfig.hosts[+toHost])) {
|
||||||
|
if (host.settings) {
|
||||||
|
settings = host.settings;
|
||||||
|
} else {
|
||||||
|
request = host.path;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mediator.emit('console:error', 'Undefined host index: ' + toHost);
|
||||||
|
mediator.emit('console:unlockinput');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (fandango.is(toHost, 'untyped')) {
|
||||||
|
settings = toHost.settings;
|
||||||
|
} else { // Assume string
|
||||||
|
request = toHost;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request) {
|
||||||
|
return require([request], function (settings) {
|
||||||
|
host.settings = settings;
|
||||||
|
return connect(toHost, done);
|
||||||
|
}, function () {
|
||||||
|
mediator.emit('console:error', 'Could not fetch host settings: ' + request);
|
||||||
|
mediator.emit('console:unlockinput');
|
||||||
|
return;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push 'Connecting...' message
|
||||||
|
mediator.emit('console:info', $.template(templates.messages.connecting, {host: host.name || 'localhost'}));
|
||||||
|
|
||||||
|
// Show motd (placed here to enable server specific motds in future)
|
||||||
|
mediator.emit('console:motd', host.settings.motd);
|
||||||
|
|
||||||
|
// The one and only socket
|
||||||
|
socket = $.Websocket.connect(host.host, {
|
||||||
|
forceNew: true,
|
||||||
|
'force new connection': true
|
||||||
|
});
|
||||||
|
|
||||||
|
// Bind socket events
|
||||||
|
socket
|
||||||
|
.on('room:joined', function (data) {
|
||||||
|
|
||||||
|
mediator.emit('console:info', $.template(templates.messages.joined_room, { roomName: $.escapeHtml(parameters.room) } ));
|
||||||
|
|
||||||
|
// Automatically count persons on join
|
||||||
|
socket.emit('room:count');
|
||||||
|
})
|
||||||
|
.on('room:left', function () {
|
||||||
|
mediator.emit('console:info', $.template(templates.messages.left_room, { roomName: $.escapeHtml(parameters.room) } ));
|
||||||
|
mediator.emit('room:changed',false);
|
||||||
|
})
|
||||||
|
|
||||||
|
.on('message:send', function (data) {
|
||||||
|
var decrypted = $.AES.decrypt(data.msg, $.SHA1(parameters.room) + parameters.key),
|
||||||
|
sanitized = $.escapeHtml(decrypted),
|
||||||
|
nick = !data.nick ? templates.default_nick : $.escapeHtml($.AES.decrypt(data.nick, $.SHA1(parameters.room) + parameters.key));
|
||||||
|
|
||||||
|
if (!decrypted) {
|
||||||
|
mediator.emit('console:error', templates.messages.unable_to_decrypt);
|
||||||
|
} else {
|
||||||
|
mediator.emit('console:message', { message: sanitized, nick: nick } );
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
.on('message:server', function (data) {
|
||||||
|
if( data.msg ) {
|
||||||
|
var sanitized = $.escapeHtml(data.msg);
|
||||||
|
if( templates.server[sanitized] ) {
|
||||||
|
if( data.payload !== undefined ) {
|
||||||
|
var sanitized_payload = $.escapeHtml(data.payload);
|
||||||
|
mediator.emit('console:server', $.template(templates.server[sanitized], { payload: sanitized_payload }));
|
||||||
|
} else {
|
||||||
|
mediator.emit('console:server', templates.server[sanitized]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mediator.emit('console:error', templates.server.bogus);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mediator.emit('console:error', templates.server.bogus);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
.on('connect', function () {
|
||||||
|
// Tell the user that the chat is ready to interact with
|
||||||
|
mediator.emit('console:info', $.template(templates.messages.connected, {
|
||||||
|
host: host.name || 'localhost'
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Set window title
|
||||||
|
mediator.emit('window:title', host.settings.title);
|
||||||
|
|
||||||
|
// Unlock input
|
||||||
|
mediator.emit('console:unlockinput');
|
||||||
|
|
||||||
|
done();
|
||||||
|
|
||||||
|
host.connected = 1;
|
||||||
|
})
|
||||||
|
|
||||||
|
.on('disconnect', function () {
|
||||||
|
room = 0;
|
||||||
|
key = 0;
|
||||||
|
host.connected = 0;
|
||||||
|
|
||||||
|
// Tell the user that the chat is ready to interact with
|
||||||
|
mediator.emit('console:info', $.template(templates.messages.disconnected, {
|
||||||
|
host: host.name || 'localhost'
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Revert title
|
||||||
|
mediator.emit('room:changed',undefined);
|
||||||
|
mediator.emit('window:title',templates.client.title);
|
||||||
|
})
|
||||||
|
|
||||||
|
.on('error', function () {
|
||||||
|
room = 0;
|
||||||
|
key = 0;
|
||||||
|
host.connected = 0;
|
||||||
|
mediator.emit('console:error', templates.messages.socket_error);
|
||||||
|
|
||||||
|
// Unlock input
|
||||||
|
mediator.emit('console:unlockinput');
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
|
||||||
|
reconnect = function (foo, done) {
|
||||||
|
if (host) {
|
||||||
|
if (host.connected) {
|
||||||
|
disconnect();
|
||||||
|
connect(host, done);
|
||||||
|
} else {
|
||||||
|
connect(host, done);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
done();
|
||||||
|
return mediator.emit('console:error', templates.messages.reconnect_no_host);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
disconnect = function () {
|
||||||
|
socket.disconnect();
|
||||||
|
},
|
||||||
|
|
||||||
|
param = function (p) {
|
||||||
|
parameters = fandango.merge({}, parameters, p );
|
||||||
|
console.log(p);
|
||||||
|
console.log(parameters);
|
||||||
|
};
|
||||||
|
|
||||||
|
mediator.on('command:host', host);
|
||||||
|
mediator.on('command:hosts', hosts);
|
||||||
|
mediator.on('command:connect', connect);
|
||||||
|
mediator.on('command:disconnect', disconnect);
|
||||||
|
mediator.on('command:reconnect', disconnect);
|
||||||
|
|
||||||
|
mediator.on('socket:emit', emit);
|
||||||
|
mediator.on('host:param', param);
|
||||||
|
|
||||||
|
|
||||||
|
});
|
|
@ -1,188 +0,0 @@
|
||||||
(function (self, factory) {
|
|
||||||
if (typeof define === 'function' && define.amd) {
|
|
||||||
// AMD. Register as an anonymous module.
|
|
||||||
define([], factory);
|
|
||||||
} else if (typeof exports === 'object') { // Node
|
|
||||||
module.exports = factory();
|
|
||||||
} else {
|
|
||||||
// Attaches to the current context
|
|
||||||
self.castrato = factory;
|
|
||||||
}
|
|
||||||
}(this, (function () {
|
|
||||||
var
|
|
||||||
/**
|
|
||||||
* Contains the next unique node id.
|
|
||||||
*
|
|
||||||
* @property index
|
|
||||||
* @type {Integer}
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
index = 0,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Contains all subscriptions
|
|
||||||
*
|
|
||||||
* @property subs
|
|
||||||
* @type {Object}
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
subs = {},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An empty function.
|
|
||||||
* This method does not accept any arguments.
|
|
||||||
*
|
|
||||||
* @property noop
|
|
||||||
* @type {function}
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
noop = function () {};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new entry in the `subs` object.
|
|
||||||
*
|
|
||||||
* @method on
|
|
||||||
* @private
|
|
||||||
* @param {Integer} fromId The unique subscriber ID.
|
|
||||||
* @param {String} event The event to subscribe to.
|
|
||||||
* @param {Function} func A function to execute when the event is triggered.
|
|
||||||
*/
|
|
||||||
function on (fromId, event, func) {
|
|
||||||
(subs[event] || (subs[event] = [])).push([fromId, func, func.length]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes all event handlers originating from `fromId` and optionally filter by handler.
|
|
||||||
*
|
|
||||||
* @method off
|
|
||||||
* @private
|
|
||||||
* @param {Integer} fromId The unique subscriber ID.
|
|
||||||
* @param {String} event The event to unsubscribe from.
|
|
||||||
* @param {Function} [func=null] The original handler that was attached to this event. If not passed, all subscriptions will be removed.
|
|
||||||
*/
|
|
||||||
function off (fromId, event, func) {
|
|
||||||
var sub,
|
|
||||||
i = 0,
|
|
||||||
toSubs = subs[event];
|
|
||||||
|
|
||||||
if (toSubs) {
|
|
||||||
while ((sub = toSubs[i++])) {
|
|
||||||
if (sub[0] === fromId && (!func || func === sub[1])) {
|
|
||||||
toSubs.splice(--i, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loops through all subscriptions, calling all handlers attached to given `event`.
|
|
||||||
*
|
|
||||||
* @method emit
|
|
||||||
* @private
|
|
||||||
* @param {Integer} fromId The unique subscriber ID.
|
|
||||||
* @param {String} event The event to emit
|
|
||||||
* @param {Object} [data=undefined] Parameters to pass along to the event handler.
|
|
||||||
* @param {Function} [func=undefined] A function to execute when all event handlers has returned.
|
|
||||||
*/
|
|
||||||
function emit (persistent, event, data, func) {
|
|
||||||
var sub,
|
|
||||||
toSubs = subs[event] || [],
|
|
||||||
total = toSubs.length,
|
|
||||||
left = total,
|
|
||||||
loop = total,
|
|
||||||
answers = [],
|
|
||||||
done;
|
|
||||||
|
|
||||||
if (loop) {
|
|
||||||
done = !func ? noop : function (data) {
|
|
||||||
if (data) {
|
|
||||||
answers.push(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!--left) {
|
|
||||||
func(answers, total);
|
|
||||||
func = 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
while ((sub = toSubs[--loop])) {
|
|
||||||
sub[1](data, (sub[2] > 1) ? done : left--);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// `func` get destructed when called.
|
|
||||||
// It has to be called at least once - even if no one was subscribing.
|
|
||||||
// Execute it if it still exists.
|
|
||||||
if (func) {
|
|
||||||
func(answers, total);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return function () {
|
|
||||||
var nodeId = index++;
|
|
||||||
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* Execute all handlers attached to the given event.
|
|
||||||
*
|
|
||||||
* @method emit
|
|
||||||
* @param {String} event The event to emit
|
|
||||||
* @param {Object} [data=undefined] Parameters to pass along to the event handler.
|
|
||||||
* @param {Function} [func=undefined] A function to execute when all event handlers has returned.
|
|
||||||
* @return {Object} `this`
|
|
||||||
* @example
|
|
||||||
* $.emit('something');
|
|
||||||
* $.emit('something', { foo: 'bar' });
|
|
||||||
* $.emit('something', { foo: 'bar' }, function (data, subscribers) {
|
|
||||||
* console.log('Emit done, a total of ' + subscribers + ' subscribers returned: ', data);
|
|
||||||
* });
|
|
||||||
*/
|
|
||||||
emit: function (persistent, event, data, func) {
|
|
||||||
// emit('something', { data: true }, function () {});
|
|
||||||
if (persistent !== true || persistent !== false) {
|
|
||||||
func = data;
|
|
||||||
data = event;
|
|
||||||
event = persistent;
|
|
||||||
persistent = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
emit(persistent, event, data, func);
|
|
||||||
|
|
||||||
return this;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attach an event handler function for one event.
|
|
||||||
*
|
|
||||||
* @method on
|
|
||||||
* @param {String} event The event to subscribe to.
|
|
||||||
* @param {Function} func A function to execute when the event is triggered.
|
|
||||||
* @return {Object} `this`
|
|
||||||
* @example
|
|
||||||
* $.on('something', function (data) {
|
|
||||||
* console.log('Got something!', data);
|
|
||||||
* });
|
|
||||||
*/
|
|
||||||
on: function (event, func) {
|
|
||||||
on(nodeId, event, func);
|
|
||||||
return this;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes an event handler function for one event.
|
|
||||||
*
|
|
||||||
* @method off
|
|
||||||
* @param {String} event The event to unsubscribe from.
|
|
||||||
* @param {Function} [func=null] The original handler that was attached to this event. If not passed, all subscriptions will be removed.
|
|
||||||
* @return {Object} `this`
|
|
||||||
* @example
|
|
||||||
* $.off('something');
|
|
||||||
* $.off('something else', handler);
|
|
||||||
*/
|
|
||||||
off: function (event) {
|
|
||||||
off(nodeId, event);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}())));
|
|
|
@ -15,7 +15,7 @@ Usage
|
||||||
mediator.emit('notification:off');
|
mediator.emit('notification:off');
|
||||||
|
|
||||||
*/
|
*/
|
||||||
define(['mediator','window','settings'], function (mediator, win, settings) {
|
define(['castrato','window','settings'], function (mediator, win, settings) {
|
||||||
|
|
||||||
var enabled = true,
|
var enabled = true,
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
Accepts:
|
||||||
|
mediator.on('command:join', ...);
|
||||||
|
mediator.on('command:leave', ...);
|
||||||
|
mediator.on('command:key', ...);
|
||||||
|
|
||||||
|
Emits:
|
||||||
|
mediator.emit('room:changed',...);
|
||||||
|
mediator.emit('console:error',...);
|
||||||
|
mediator.emit('socket:emit',...);
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
define(
|
||||||
|
{
|
||||||
|
compiles: ['$'],
|
||||||
|
requires: ['castrato','settings','templates']
|
||||||
|
}, function ($, requires, data) {
|
||||||
|
|
||||||
|
var
|
||||||
|
|
||||||
|
// Private properties
|
||||||
|
room=false,
|
||||||
|
|
||||||
|
// Require shortcuts
|
||||||
|
mediator = requires.castrato,
|
||||||
|
settings = requires.settings,
|
||||||
|
templates = requires.templates,
|
||||||
|
|
||||||
|
join = function(payload) {
|
||||||
|
if (room !== false) {
|
||||||
|
mediator.emit('console:error',$.template(templates.messages.already_in_room, { room: room }));
|
||||||
|
} else {
|
||||||
|
room = payload;
|
||||||
|
mediator.emit('room:changed', room );
|
||||||
|
mediator.emit('socket:emit',{ data: 'room:join' , payload: $.SHA1(room) } );
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
leave = function() {
|
||||||
|
if (room !== false) {
|
||||||
|
mediator.emit('socket:emit',{ data: 'room:leave' , payload: $.SHA1(room) } );
|
||||||
|
room = false;
|
||||||
|
} else {
|
||||||
|
mediator.emit('console:error',templates.messages.leave_from_nowhere);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
count = function() {
|
||||||
|
if (room) {
|
||||||
|
mediator.emit('socket:emit','room:count');
|
||||||
|
} else {
|
||||||
|
mediator.emit('console:error', templates.messages.not_in_room);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Connect events
|
||||||
|
mediator.on('command:join', join);
|
||||||
|
mediator.on('command:leave', leave);
|
||||||
|
mediator.on('command:count', count);
|
||||||
|
|
||||||
|
});
|
|
@ -1,8 +1,23 @@
|
||||||
define({
|
define({
|
||||||
|
|
||||||
client: {
|
title: "Cryptalk - Online",
|
||||||
title: "Cryptalk - Online"
|
|
||||||
},
|
motd: '<pre>\n\n' +
|
||||||
|
'▄████▄ ██▀███ ▓██ ██▓ ██▓███ ▄▄▄█████▓ ▄▄▄ ██▓ ██ ▄█▀ \n' +
|
||||||
|
'▒██▀ ▀█ ▓██ ▒ ██▒▒██ ██▒▓██░ ██▒▓ ██▒ ▓▒▒████▄ ▓██▒ ██▄█▒ \n' +
|
||||||
|
'▒▓█ ▄ ▓██ ░▄█ ▒ ▒██ ██░▓██░ ██▓▒▒ ▓██░ ▒░▒██ ▀█▄ ▒██░ ▓███▄░ \n' +
|
||||||
|
'▒▓▓▄ ▄██▒▒██▀▀█▄ ░ ▐██▓░▒██▄█▓▒ ▒░ ▓██▓ ░ ░██▄▄▄▄██ ▒██░ ▓██ █▄ \n' +
|
||||||
|
'▒ ▓███▀ ░░██▓ ▒██▒ ░ ██▒▓░▒██▒ ░ ░ ▒██▒ ░ ▓█ ▓██▒░██████▒▒██▒ █▄ \n' +
|
||||||
|
'░ ░▒ ▒ ░░ ▒▓ ░▒▓░ ██▒▒▒ ▒▓▒░ ░ ░ ▒ ░░ ▒▒ ▓▒█░░ ▒░▓ ░▒ ▒▒ ▓▒ \n' +
|
||||||
|
' ░ ▒ ░▒ ░ ▒░▓██ ░▒░ ░▒ ░ ░ ▒ ▒▒ ░░ ░ ▒ ░░ ░▒ ▒░ \n' +
|
||||||
|
'░ ░░ ░ ▒ ▒ ░░ ░░ ░ ░ ▒ ░ ░ ░ ░░ ░ \n' +
|
||||||
|
'░ ░ ░ ░ ░ ░ ░ ░ ░░ ░ \n' +
|
||||||
|
'░ ░ ░ \n' +
|
||||||
|
' https://github.com/hexagon/cryptalk \n' +
|
||||||
|
' \n' +
|
||||||
|
' Tip of the day: /help \n' +
|
||||||
|
'----------------------------------------------------------------------' +
|
||||||
|
'</pre>',
|
||||||
|
|
||||||
nick: {
|
nick: {
|
||||||
maxLen: 20,
|
maxLen: 20,
|
||||||
|
@ -16,6 +31,6 @@ define({
|
||||||
|
|
||||||
notifications: {
|
notifications: {
|
||||||
maxOnePerMs: 3000
|
maxOnePerMs: 3000
|
||||||
}
|
},
|
||||||
|
|
||||||
});
|
});
|
|
@ -1,22 +1,6 @@
|
||||||
// The templating function only supports variables.
|
// The templating function only supports variables.
|
||||||
// Define a variable as so: {variable_name}
|
// Define a variable as so: {variable_name}
|
||||||
define({
|
define({
|
||||||
motd: '<pre>\n\n' +
|
|
||||||
'▄████▄ ██▀███ ▓██ ██▓ ██▓███ ▄▄▄█████▓ ▄▄▄ ██▓ ██ ▄█▀ \n' +
|
|
||||||
'▒██▀ ▀█ ▓██ ▒ ██▒▒██ ██▒▓██░ ██▒▓ ██▒ ▓▒▒████▄ ▓██▒ ██▄█▒ \n' +
|
|
||||||
'▒▓█ ▄ ▓██ ░▄█ ▒ ▒██ ██░▓██░ ██▓▒▒ ▓██░ ▒░▒██ ▀█▄ ▒██░ ▓███▄░ \n' +
|
|
||||||
'▒▓▓▄ ▄██▒▒██▀▀█▄ ░ ▐██▓░▒██▄█▓▒ ▒░ ▓██▓ ░ ░██▄▄▄▄██ ▒██░ ▓██ █▄ \n' +
|
|
||||||
'▒ ▓███▀ ░░██▓ ▒██▒ ░ ██▒▓░▒██▒ ░ ░ ▒██▒ ░ ▓█ ▓██▒░██████▒▒██▒ █▄ \n' +
|
|
||||||
'░ ░▒ ▒ ░░ ▒▓ ░▒▓░ ██▒▒▒ ▒▓▒░ ░ ░ ▒ ░░ ▒▒ ▓▒█░░ ▒░▓ ░▒ ▒▒ ▓▒ \n' +
|
|
||||||
' ░ ▒ ░▒ ░ ▒░▓██ ░▒░ ░▒ ░ ░ ▒ ▒▒ ░░ ░ ▒ ░░ ░▒ ▒░ \n' +
|
|
||||||
'░ ░░ ░ ▒ ▒ ░░ ░░ ░ ░ ▒ ░ ░ ░ ░░ ░ \n' +
|
|
||||||
'░ ░ ░ ░ ░ ░ ░ ░ ░░ ░ \n' +
|
|
||||||
'░ ░ ░ \n' +
|
|
||||||
' https://github.com/hexagon/cryptalk \n' +
|
|
||||||
' \n' +
|
|
||||||
' Tip of the day: /help \n' +
|
|
||||||
'----------------------------------------------------------------------' +
|
|
||||||
'</pre>',
|
|
||||||
|
|
||||||
help: '<pre> \n' +
|
help: '<pre> \n' +
|
||||||
'Cryptalk, encrypted instant chat. \n' +
|
'Cryptalk, encrypted instant chat. \n' +
|
||||||
|
@ -70,8 +54,7 @@ define({
|
||||||
messages: {
|
messages: {
|
||||||
key_to_short: 'Hmm, that\'s a weak key, try again...',
|
key_to_short: 'Hmm, that\'s a weak key, try again...',
|
||||||
key_to_long: 'Man that\'s a long key. Make it a tad short, \'kay?',
|
key_to_long: 'Man that\'s a long key. Make it a tad short, \'kay?',
|
||||||
key_ok_ready: 'Key set, you can now start communicating.',
|
key_ok: 'Key set, you can now start communicating.',
|
||||||
key_ok_but_no_room: 'Key set, you can now join a room and start communicating.',
|
|
||||||
key_no_host: 'You have to connect to a host before setting the key.',
|
key_no_host: 'You have to connect to a host before setting the key.',
|
||||||
|
|
||||||
join_no_host: 'You have to connect to a host before joining a room.',
|
join_no_host: 'You have to connect to a host before joining a room.',
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
/*
|
/*
|
||||||
|
Accepts:
|
||||||
|
'window:title'
|
||||||
|
|
||||||
Emits:
|
Emits:
|
||||||
'window:focused'
|
'window:focused'
|
||||||
|
@ -9,7 +11,7 @@
|
||||||
window.setTitle(title);
|
window.setTitle(title);
|
||||||
|
|
||||||
*/
|
*/
|
||||||
define(['mediator'],function (mediator){
|
define(['castrato'],function (mediator){
|
||||||
|
|
||||||
var exports = {},
|
var exports = {},
|
||||||
|
|
||||||
|
@ -34,6 +36,9 @@ define(['mediator'],function (mediator){
|
||||||
window.observe("focusin", focusCallback);
|
window.observe("focusin", focusCallback);
|
||||||
window.observe("focusout", blurCallback);
|
window.observe("focusout", blurCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mediator.on('window:title',exports.setTitle);
|
||||||
|
|
||||||
return exports;
|
return exports;
|
||||||
|
|
||||||
});
|
});
|
Loading…
Reference in New Issue