commit
1b86e1feb6
Binary file not shown.
After Width: | Height: | Size: 8.7 KiB |
Binary file not shown.
After Width: | Height: | Size: 8.2 KiB |
Binary file not shown.
After Width: | Height: | Size: 7.8 KiB |
Binary file not shown.
After Width: | Height: | Size: 628 B |
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
Binary file not shown.
After Width: | Height: | Size: 3.3 KiB |
|
@ -5,6 +5,11 @@
|
||||||
<title>Cryptalk</title>
|
<title>Cryptalk</title>
|
||||||
|
|
||||||
<link rel="stylesheet" type="text/css" href="css/default.css">
|
<link rel="stylesheet" type="text/css" href="css/default.css">
|
||||||
|
|
||||||
|
<head profile="http://www.w3.org/2005/10/profile">
|
||||||
|
<link rel="icon"
|
||||||
|
type="image/png"
|
||||||
|
href="gfx/icon_32x32.png">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// Main cryptalk module
|
// Main cryptalk module
|
||||||
define({
|
define({
|
||||||
compiles: ['$'],
|
compiles: ['$'],
|
||||||
requires: ['hosts', 'templates', 'sound', 'fandango']
|
requires: ['hosts', 'templates', 'sound', 'fandango','notifications']
|
||||||
}, function ($, requires, data) {
|
}, function ($, requires, data) {
|
||||||
var socket,
|
var socket,
|
||||||
key,
|
key,
|
||||||
|
@ -26,10 +26,11 @@ define({
|
||||||
},
|
},
|
||||||
|
|
||||||
// Shortcut
|
// Shortcut
|
||||||
hosts = requires.hosts.hosts;
|
hosts = requires.hosts.hosts,
|
||||||
fandango = requires.fandango;
|
fandango = requires.fandango,
|
||||||
templates = requires.templates;
|
templates = requires.templates,
|
||||||
sound = requires.sound;
|
sound = requires.sound,
|
||||||
|
notifications = requires.notifications,
|
||||||
|
|
||||||
lockInput = function () {
|
lockInput = function () {
|
||||||
components.input[0].setAttribute('disabled', 'disabled');
|
components.input[0].setAttribute('disabled', 'disabled');
|
||||||
|
@ -42,8 +43,22 @@ define({
|
||||||
components.input.focus();
|
components.input.focus();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
showNotification = function (type, nick, text) {
|
||||||
|
if (!mute) {
|
||||||
|
if ( type == 'message') {
|
||||||
|
notifications.notify(nick.substring(0, 20), text.substring(0, 80),'gfx/icon_128x128.png',true);
|
||||||
|
} else if ( type == 'error' ) {
|
||||||
|
notifications.notify('Cryptalk', text.substring(0, 80),'gfx/icon_128x128_error.png',true);
|
||||||
|
} else {
|
||||||
|
notifications.notify('Cryptalk', text.substring(0, 80),'gfx/icon_128x128_info.png',true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
// Adds a new message to the DOM
|
// Adds a new message to the DOM
|
||||||
post = function (type, text, clearChat, clearBuffer, nick) {
|
post = function (type, text, clearChat, clearBuffer, nick) {
|
||||||
|
|
||||||
var tpl = templates.post[type],
|
var tpl = templates.post[type],
|
||||||
post,
|
post,
|
||||||
data = fandango.merge({}, settings, {
|
data = fandango.merge({}, settings, {
|
||||||
|
@ -60,6 +75,9 @@ define({
|
||||||
clearInput();
|
clearInput();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showNotification(type, nick, text)
|
||||||
|
|
||||||
|
|
||||||
// Append the post to the chat DOM element
|
// Append the post to the chat DOM element
|
||||||
components.chat[clearChat ? 'html' : 'append'](post);
|
components.chat[clearChat ? 'html' : 'append'](post);
|
||||||
},
|
},
|
||||||
|
@ -196,7 +214,7 @@ define({
|
||||||
post('error', templates.messages.unable_to_decrypt);
|
post('error', templates.messages.unable_to_decrypt);
|
||||||
} else {
|
} else {
|
||||||
post('message', sanitized, false, false, nick);
|
post('message', sanitized, false, false, nick);
|
||||||
if( !mute ) sound.playTones(sound.messages.message);
|
//if( !mute && !notifications.windowActive()) sound.playTones(sound.messages.message);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -212,7 +230,7 @@ define({
|
||||||
}
|
}
|
||||||
|
|
||||||
// Play sound
|
// Play sound
|
||||||
if (sound.messages[sanitized] !== undefined && !mute ) sound.playTones(sound.messages[sanitized]);
|
//if (sound.messages[sanitized] !== undefined && !mute && !notifications.windowActive() ) sound.playTones(sound.messages[sanitized]);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
post('error', templates.server.bogus);
|
post('error', templates.server.bogus);
|
||||||
|
@ -500,13 +518,18 @@ define({
|
||||||
|
|
||||||
unlockInput();
|
unlockInput();
|
||||||
|
|
||||||
|
notifications.enableNative();
|
||||||
|
|
||||||
// It's possible to provide room and key using the hashtag.
|
// It's possible to provide room and key using the hashtag.
|
||||||
// The room and key is then seperated by semicolon (room:key).
|
// 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.
|
// If there is no semicolon present, the complete hash will be treated as the room name and the key has to be set manually.
|
||||||
if (host && (hash = window.location.hash)) {
|
commands.connect(0, function() {
|
||||||
parts = hash.slice(1).split(':');
|
if (host && (hash = window.location.hash)) {
|
||||||
|
parts = hash.slice(1).split(':');
|
||||||
|
|
||||||
|
parts[0] && commands.join(parts[0]);
|
||||||
|
parts[1] && commands.key(parts[1]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
parts[0] && commands.join(parts[0]);
|
|
||||||
parts[1] && commands.key(parts[1]);
|
|
||||||
}
|
|
||||||
});
|
});
|
|
@ -0,0 +1,133 @@
|
||||||
|
/*
|
||||||
|
Usage
|
||||||
|
|
||||||
|
Native notifications without fallback:
|
||||||
|
notification.enableNative(); // Once
|
||||||
|
notification.notify("Woop Woop");
|
||||||
|
|
||||||
|
Native notifications with fallback:
|
||||||
|
notification.enableNative(); // Once
|
||||||
|
notification.notify("Woop Woop",true); // True in 2nd parameter enables fallback
|
||||||
|
|
||||||
|
Title blink only:
|
||||||
|
notifications.blinkTitleUntilFocus("Woop Woop",1000);
|
||||||
|
|
||||||
|
*/
|
||||||
|
define(function (){
|
||||||
|
|
||||||
|
var exports = {},
|
||||||
|
|
||||||
|
window_active,
|
||||||
|
blur_delay_timer,
|
||||||
|
native_supported = false,
|
||||||
|
|
||||||
|
new_title,
|
||||||
|
original_title,
|
||||||
|
blink_timer,
|
||||||
|
interval,
|
||||||
|
|
||||||
|
now = function () {
|
||||||
|
return performance.now() || Date.now();
|
||||||
|
},
|
||||||
|
|
||||||
|
focusCallback = function() {
|
||||||
|
/* Reset everything after regaining focus */
|
||||||
|
resetState();
|
||||||
|
},
|
||||||
|
|
||||||
|
resetState = function() {
|
||||||
|
clearTimeout(blur_delay_timer);
|
||||||
|
clearTimeout(blink_timer);
|
||||||
|
if (original_title !== undefined) setTitle(original_title);
|
||||||
|
original_title = undefined;
|
||||||
|
new_title = undefined;
|
||||||
|
window_active = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
blurCallback = function() {
|
||||||
|
/* Apply a slight delay to prevent notifications from popping when the notifications
|
||||||
|
cause the windows to lose focus */
|
||||||
|
clearTimeout(blur_delay_timer);
|
||||||
|
blur_delay_timer = setTimeout(function() { window_active = false; },1000);
|
||||||
|
},
|
||||||
|
|
||||||
|
setTitle = function(t) { document.title = t; },
|
||||||
|
getTitle = function() { return document.title; },
|
||||||
|
|
||||||
|
doBlink = function() {
|
||||||
|
if(!window_active) {
|
||||||
|
if( getTitle() == original_title )
|
||||||
|
setTitle( new_title );
|
||||||
|
else
|
||||||
|
setTitle( original_title);
|
||||||
|
|
||||||
|
blink_timer = setTimeout(doBlink,interval);
|
||||||
|
} else {
|
||||||
|
resetState();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.enableNative = function() {
|
||||||
|
if( native_supported && Notification.permission !== 'denied' ) {
|
||||||
|
Notification.requestPermission(function (status) {
|
||||||
|
Notification.permission = status;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.windowActive = function() {
|
||||||
|
return window_active;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.blinkTitleUntilFocus = function(t,i) {
|
||||||
|
interval = (i == undefined) ? 1000 : i;
|
||||||
|
if (!window_active) {
|
||||||
|
new_title = t;
|
||||||
|
original_title = getTitle();
|
||||||
|
doBlink();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.notify = function(title,body,icon,fallback) {
|
||||||
|
// Only notify while in background
|
||||||
|
if( !window_active ) {
|
||||||
|
|
||||||
|
// Set default value for fallback parameter
|
||||||
|
if ( fallback === undefined) fallback = false;
|
||||||
|
|
||||||
|
if ( native_supported && Notification.permission === "granted") {
|
||||||
|
|
||||||
|
// Create notification
|
||||||
|
var n = new Notification(title, {body: body, icon:icon});
|
||||||
|
|
||||||
|
// Handle on show event
|
||||||
|
n.onshow = function () {
|
||||||
|
// Automatically close the notification after 5000ms
|
||||||
|
setTimeout(function(){n.close();},3000);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if ( fallback ) {
|
||||||
|
exports.blinkTitleUntilFocus("Attention",1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
native_supported = (window.Notification !== undefined);
|
||||||
|
|
||||||
|
// Keep track of document focus/blur
|
||||||
|
if (window.addEventListener){
|
||||||
|
// Normal browsers
|
||||||
|
window.addEventListener("focus", focusCallback, true);
|
||||||
|
window.addEventListener("blur", blurCallback, true);
|
||||||
|
} else {
|
||||||
|
// IE
|
||||||
|
window.observe("focusin", focusCallback);
|
||||||
|
window.observe("focusout", blurCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure we are at square one
|
||||||
|
resetState();
|
||||||
|
|
||||||
|
return exports;
|
||||||
|
|
||||||
|
});
|
|
@ -79,8 +79,8 @@ define({
|
||||||
leave_from_nowhere: 'How are you supposed to leave, while being nowhere?',
|
leave_from_nowhere: 'How are you supposed to leave, while being nowhere?',
|
||||||
|
|
||||||
// Sounds
|
// Sounds
|
||||||
muted: 'Notification sounds is now muted.',
|
muted: 'Notifications and sounds are now muted.',
|
||||||
unmuted: 'Notifications sounds is now on.',
|
unmuted: 'Notifications and sounds are now on.',
|
||||||
|
|
||||||
// Extra variables: 'commandName'
|
// Extra variables: 'commandName'
|
||||||
unrecognized_command: 'Unrecognized command: "{commandName}"',
|
unrecognized_command: 'Unrecognized command: "{commandName}"',
|
||||||
|
|
37
server.js
37
server.js
|
@ -1,7 +1,7 @@
|
||||||
var express = require('express.io'),
|
var express = require('express.io'),
|
||||||
uuid = require('node-uuid');
|
uuid = require('node-uuid'),
|
||||||
|
|
||||||
app = express();app.http().io();
|
app = express();app.http().io();
|
||||||
|
|
||||||
app.use(express.static(__dirname + '/public'));
|
app.use(express.static(__dirname + '/public'));
|
||||||
|
|
||||||
|
@ -43,9 +43,38 @@ app.io.route('room', {
|
||||||
|
|
||||||
app.io.route('message', {
|
app.io.route('message', {
|
||||||
send: function(req) {
|
send: function(req) {
|
||||||
if(req.data && req.data.room) req.socket.broadcast.to(req.data.room).emit('message:send', { msg: req.data.msg, nick: req.data.nick} );
|
|
||||||
req.socket.emit('message:send', { msg: req.data.msg, nick: req.data.nick} );
|
// Check that the user is in a room
|
||||||
|
if(req.data && req.data.room) {
|
||||||
|
|
||||||
|
// Check that the message size is within bounds
|
||||||
|
var total_msg_size = (req.data.msg) ? req.data.msg.length : 0 + (req.data.nick) ? req.data.nick.length : 0;
|
||||||
|
if( total_msg_size <= 4096) {
|
||||||
|
|
||||||
|
// Check that at least 100ms has passed since last message
|
||||||
|
if( req.socket.last_message === undefined || new Date().getTime() - req.socket.last_message > 100 ) {
|
||||||
|
|
||||||
|
req.socket.broadcast.to(req.data.room).emit('message:send', { msg: req.data.msg, nick: req.data.nick} );
|
||||||
|
req.socket.emit('message:send', { msg: req.data.msg, nick: req.data.nick} );
|
||||||
|
|
||||||
|
req.socket.last_message = new Date().getTime();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Do not complain if message rate is too fast, that would only generate more traffic
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Message size is out of bounds, complain
|
||||||
|
req.socket.emit('message:server', {msg:'command_failed'} );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
app.io.sockets.on('connection', function(socket) {
|
app.io.sockets.on('connection', function(socket) {
|
||||||
|
|
Loading…
Reference in New Issue