Mediator awareness

This commit is contained in:
Hexagon 2014-09-23 19:54:36 +02:00
parent 29d1799d56
commit c74d265579
6 changed files with 245 additions and 195 deletions

View File

@ -0,0 +1,67 @@
/* Usage:
channel.emit('audio:play',message);
channel.emit('audio:on');
channel.emit('audio:off');
*/
// Sounds module, used for emitting those annoying bl-up sounds when receiving a message
define(['queue','mediator'], function (queue,mediator) {
var ac = false,
enabled = true,
channel = mediator(),
// Recursive function for playing tones, takes an array of [tone,start_ms,duration_ms] - entries
// i is only used for recursion
playTones = function (tones, i) {
// Parameter defaults
i = (i === undefined) ? 0 : i;
// Stop if we've reached the end of iteration, and require ac
if( !(i < Object.keys(tones).length) || !ac || !enabled ) return;
// Add tones to execution queue
var current_tones = tones[i],
freqs = current_tones[0],
start = current_tones[1],
duration = current_tones[2];
var o = ac.createOscillator();
var g = ac.createGain();
o.frequency.value = freqs;
o.connect(g);
g.gain.value = 0.25;
g.connect(ac.destination);
queue.add_function_delayed(start,function() { o.noteOn(0); });
queue.add_function_delayed(start+duration,function() { o.noteOff(0); });
// Iterate, or start playing
i++;
if( i < Object.keys(tones).length ) {
playTones(tones,i);
} else {
queue.run();
}
},
on = function() {
enabled = true;
},
off = function() {
enabled = false;
};
if( window.AudioContext || window.webkitAudioContext ) ac = new ( window.AudioContext || window.webkitAudioContext );
channel.on('audio:play',function(message) { playTones(message) });
channel.on('audio:on',function(message) { on(); });
channel.on('audio:off',function(message) { off(); });
});

View File

@ -1,7 +1,7 @@
// Main cryptalk module
define({
compiles: ['$'],
requires: ['hosts', 'templates', 'sound', 'fandango','notifications']
requires: ['mediator','hosts', 'templates', 'audio', 'fandango','notifications','sounds']
}, function ($, requires, data) {
var socket,
key,
@ -9,7 +9,7 @@ define({
room,
hash,
nick,
mute,
mute = false,
settings = {},
@ -29,8 +29,8 @@ define({
hosts = requires.hosts,
fandango = requires.fandango,
templates = requires.templates,
sound = requires.sound,
notifications = requires.notifications,
sounds = requires.sounds,
channel = requires.mediator(),
lockInput = function () {
components.input[0].setAttribute('disabled', 'disabled');
@ -44,16 +44,21 @@ define({
},
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);
}
}
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
channel.emit('notification:send',
{
title: title.substring(0, 20),
body: text.substring(0, 80),
icon: icon
});
// Emit sound
if ( type == 'message' ) channel.emit('audio:play',sounds.message);
},
// Adds a new message to the DOM
@ -63,8 +68,7 @@ define({
post,
data = fandango.merge({}, settings, {
nick: nick,
room: room,
mute: mute
room: room
});
data.text = $.template(text, data);
@ -77,7 +81,6 @@ define({
showNotification(type, nick, text)
// Append the post to the chat DOM element
components.chat[clearChat ? 'html' : 'append'](post);
},
@ -214,7 +217,6 @@ define({
post('error', templates.messages.unable_to_decrypt);
} else {
post('message', sanitized, false, false, nick);
//if( !mute && !notifications.windowActive()) sound.playTones(sound.messages.message);
}
})
@ -228,10 +230,6 @@ define({
} else {
post('server', templates.server[sanitized]);
}
// Play sound
//if (sound.messages[sanitized] !== undefined && !mute && !notifications.windowActive() ) sound.playTones(sound.messages[sanitized]);
} else {
post('error', templates.server.bogus);
}
@ -347,11 +345,11 @@ define({
},
mute: function () {
// Invert mute
mute = !mute;
mute = true;
},
// Inform that the key has been set
post('info', $.template(templates.messages[mute ? 'muted' : 'unmuted']));
unmute: function () {
mute = false;
},
join: function (payload) {
@ -516,9 +514,17 @@ define({
// Post the help/welcome message
post('motd', templates.motd, true);
unlockInput();
// Route mediator messages
channel.on('window:focused',function() {
channel.emit('audio:off');
channel.emit('notification:off');
});
channel.on('window:blurred',function() {
if( !mute ) channel.emit('audio:on');
channel.emit('notification:on');
});
notifications.enableNative();
unlockInput();
// It's possible to provide room and key using the hashtag.
// The room and key is then seperated by semicolon (room:key).

View File

@ -1,24 +1,24 @@
/*
Usage
Native notifications without fallback:
notification.enableNative(); // Once
notification.notify("Woop Woop");
// Send an notification
channel.emit('notification:send',{
title: 'Woop',
body: 'Woop woop',
icon: 'gfx/icon.png'
});
Native notifications with fallback:
notification.enableNative(); // Once
notification.notify("Woop Woop",true); // True in 2nd parameter enables fallback
// Turn notifications on
channel.emit('notification:on');
Title blink only:
notifications.blinkTitleUntilFocus("Woop Woop",1000);
// Turn notifications off
channel.emit('notification:off');
*/
define(function (){
define(['mediator','window'],function (mediator,win){
var exports = {},
var enabled = true,
window_active,
blur_delay_timer,
native_supported = false,
new_title,
@ -26,17 +26,21 @@ define(function (){
blink_timer,
interval,
now = function () {
return performance.now() || Date.now();
},
channel = mediator(),
focusCallback = function() {
/* Reset everything after regaining focus */
resetState();
now = function () {
return performance.now() || Date.now();
},
on = function () {
enabled = true;
},
off = function () {
enabled = false;
},
resetState = function() {
clearTimeout(blur_delay_timer);
clearTimeout(blink_timer);
if (original_title !== undefined) setTitle(original_title);
original_title = undefined;
@ -44,90 +48,71 @@ define(function (){
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 );
if(enabled) {
if( win.getTitle() == original_title )
win.setTitle( new_title );
else
setTitle( original_title);
win.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);
enableNative = function() {
if( native_supported && Notification.permission !== 'denied' ) {
Notification.requestPermission(function (status) {
Notification.permission = status;
});
}
}
};
},
blinkTitleUntilFocus = function(t,i) {
interval = (i == undefined) ? 1000 : i;
if ( enabled ) {
new_title = t;
original_title = getTitle();
doBlink();
}
},
notify = function(title,body,icon,fallback) {
// Only notify while in background
if( enabled) {
// 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);
}
channel.on('notification:send',function(data) { notify(data.title,data.body,data.icon,true); });
channel.on('notification:on',function() { on(); });
channel.on('notification:off',function() { off(); });
enableNative();
off();
// Make sure we are at square one
resetState();
return exports;
});

View File

@ -1,69 +0,0 @@
// Sounds module, used for emitting those annoying bl-up sounds when receiving a message
define(['queue'], function (queue) {
var exports = { messages: {} },
ac = false;
if( window.AudioContext || window.webkitAudioContext ) ac = new ( window.AudioContext || window.webkitAudioContext );
// Recursive function for playing tones, takes an array of [tone,start_ms,duration_ms] - entries
// i is only used for recursion
exports.playTones = function (tones, i) {
// Parameter defaults
i = (i === undefined) ? 0 : i;
// Stop if we've reached the end of iteration, and require ac
if( ac && !(i < Object.keys(tones).length) || !ac ) return;
// Add tones to execution queue
var current_tones = tones[i],
freqs = current_tones[0],
start = current_tones[1],
duration = current_tones[2];
var o = ac.createOscillator();
var g = ac.createGain();
o.frequency.value = freqs;
o.connect(g);
g.gain.value = 0.25;
g.connect(ac.destination);
queue.add_function_delayed(start,function() { o.noteOn(0); });
queue.add_function_delayed(start+duration,function() { o.noteOff(0); });
// Iterate, or start playing
i++;
if( i < Object.keys(tones).length ) {
exports.playTones(tones,i);
} else {
queue.run();
}
};
exports.messages = {
message: [
[261.63*2,0,50],
[261.63*3,0,50],
[261.63*4,50,50],
[261.63*5,50,50]
],
person_joined: [
[261.63*3,0,200],
[261.63*1,0,200],
[261.63*3,200,500],
[261.63*2,200,500]
],
person_left: [
[261.63*3,0,200],
[261.63*2,0,200],
[261.63*3,200,500],
[261.63*1,200,500]
]
};
return exports;
});

View File

@ -0,0 +1,20 @@
define({
message: [
[261.63*2,0,50],
[261.63*3,0,50],
[261.63*4,50,50],
[261.63*5,50,50]
],
person_joined: [
[261.63*3,0,200],
[261.63*1,0,200],
[261.63*3,200,500],
[261.63*2,200,500]
],
person_left: [
[261.63*3,0,200],
[261.63*2,0,200],
[261.63*3,200,500],
[261.63*1,200,500]
]
});

View File

@ -0,0 +1,41 @@
/*
Emits:
'window:focused'
'window:blurred'
Exports:
title = window.getTitle();
window.setTitle(title);
*/
define(['mediator'],function (mediator){
var exports = {},
channel = mediator(),
focusCallback = function() {
channel.emit('window:focused');
},
blurCallback = function() {
channel.emit('window:blurred');
};
exports.getTitle = function(t) { document.title = t; },
exports.setTitle = function() { return document.title; };
// 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);
}
return exports;
});