Rediseño de interfaz

This commit is contained in:
Joan Sanchez 2018-01-16 20:31:19 +01:00
parent b802418546
commit 0eb3f30b6f
24 changed files with 917 additions and 812 deletions

View File

@ -6,4 +6,19 @@ router.get('/', function(request, response) {
view.render('home', {id: request.user.id}, response); view.render('home', {id: request.user.id}, response);
}); });
router.get('/history', function(request, response) {
let number = request.query.number;
view.render('history', {id: request.user.id, call: number}, response);
});
router.get('/dialpad', function(request, response) {
let number = request.query.number;
view.render('dialpad', {id: request.user.id, call: number}, response);
});
router.get('/call', function(request, response) {
let number = request.query.number;
view.render('call', {id: request.user.id, call: number}, response);
});
module.exports = router; module.exports = router;

View File

@ -1,206 +1,221 @@
body { body {
font-family: Arial, Helvetica, sans-serif; font-family: Arial, Verdana, Helvetica, sans-serif;
background-color: #292929; background-color: #292929;
font-size: 14px; font-size: 14px;
padding: 65.5px 0 0 0; padding: 0;
margin: 0 margin: 0;
}
}
html, body {
min-height: 100%; html, body {
height: 100% min-height: 100%;
} height: 100%
}
* {
-webkit-box-sizing: border-box; * {
-moz-box-sizing: border-box; -webkit-box-sizing: border-box;
box-sizing: border-box -moz-box-sizing: border-box;
} box-sizing: border-box
}
a {
color: #FFF a {
} color: #FFF;
font-family: inherit;
.container { }
min-height: 100%;
height: 100% .navigation {
} background-color: #3C393B;
position: fixed;
.quickbar { padding: 15px;
background-color: #3C393B; width: 100%;
position: absolute; z-index: 2;
padding: 15px; top: 0
width: 100%; }
top: 0
} .navigation a {
text-decoration: none;
.quickbar a { margin-left: 10px;
text-decoration: none; color: #FFF
margin-left: 10px; }
color: #FFF
} .navigation a:hover {
color: #ff6e40
.quickbar a:hover { }
color: #ff6e40
} .navigation .pull-right a i {
font-size: 32px;
.quickbar .pull-right a i { }
font-size: 32px;
} #container {
position: fixed;
.side { padding-left: 80px;
background: #2C2C2C; top: 65.5px;
height: 100%; bottom: 0;
width: 15%; width: 100%;
float: left float: left
} }
.side .user { #container.side-display {
padding: 15px; padding-left: 335px
color: #FFF }
}
.quickbar {
.side .user .extension { background: #232323;
font-size: 12px position: fixed;
} width: 80px;
top: 65.5px;
.side .user:after { bottom: 0;
display: block; left: 0
content: ' '; }
clear: both
} .quickbar ul {
padding: 0;
.side .user .name { margin: 0
font-weight: bold; }
color: #FFF
} .quickbar ul li {
position: relative;
.side .title { list-style: none
background-color: #333333; }
text-transform: uppercase;
padding: 15px 10px; .quickbar ul li a {
font-weight: bold; padding: 20px 0;
color: #111111 text-align: center;
display: block
} }
.side .navigation a { .quickbar ul li a i {
background-color: #ff9e00; font-size: 32px
text-decoration: none; }
transition: 0.2s all;
text-align: center; .quickbar ul li a:hover {
font-size: 24px; background-color: #383838
display: block; }
padding: 15px;
color: #FFF .quickbar ul li a.active {
} background-color: #2C2C2C
}
.side .navigation a.active, .side .navigation a.active:hover {
background-color: #FFF; .quickbar .audioControls {
color: #FFA410 position:absolute;
} bottom: 0;
color: #FFF
.side .navigation a:hover { }
background-color: #ffb030;
} .profile .status {
position:absolute;
.side .navigation a i { width: 10px;
margin-right: 10px height: 10px;
} top: 15px;
left: 15px;
.side .audioControls { border-radius: 50%
position:absolute; }
bottom: 0;
padding: 15px; .profile .status.offline {
color: #FFF background-color: #CCC
} }
.profile .status.online {
background-color: #95D600
.chatbox .search { }
margin-bottom: 15px
} .profile .status.error {
background-color: #d81212
.chatbox .search .control { }
-webkit-border-radius: 15px;
-moz-border-radius: 15px; #side {
border-radius: 15px; background-color: #2C2C2C;
background: #232323; position: fixed;
padding: 10px padding: 15px;
} display: none;
height: 100%;
.chatbox .search input[type=text] { width: 255px;
background-color: transparent; left: 80px
font-family: inherit; }
font-size: 18px;
color: #FFF; #content {
border: 0px; position:relative;
width: 100%;
width:100% height: 100%;
} float:left
}
.chatbox .callTimer {
text-align: center; .call {
padding: 15px background-color: #111;
} height: 100%;
width: 100%;
.chatbox .callTimer span { float: left
font-size: 18px; }
color: #FFF
} .chatbox {
position: relative
.chatbox { }
background-color: #292929;
height: 100%; .chatbox {
width: 85%; background-color: #292929;
float: left height: 100%;
} width: 100%;
margin-left: 80px;
.chatbox .navigation { float: left
padding: 15px; }
color: #FFF
} #notifications {
position: fixed;
#notifications { overflow: hidden;
position: fixed; left: 50%;
overflow: hidden; max-height: 200px;
left: 50%; width: 500px;
max-height: 200px; margin-left: -250px;
width: 500px; top: 80px
margin-left: -250px; }
top: 80px
} #notifications .dialog {
background-color: rgba(0, 0, 0, 0.5);
#notifications .dialog { text-align:center;
background-color: rgba(0, 0, 0, 0.5); -moz-border-radius:3px;
text-align:center; -webkit-border-radius:3px;
-moz-border-radius:3px; border-radius:3px;
-webkit-border-radius:3px; margin-bottom: 15px;
border-radius:3px; padding: 10px;
margin-bottom: 15px; color: #FFF
padding: 10px; }
color: #FFF
} .dial .search {
margin-bottom: 15px
.dial { }
width: 500px;
margin: 100px auto .dial .search .control {
} -webkit-border-radius: 15px;
-moz-border-radius: 15px;
.dial .callStatus { border-radius: 15px;
font-size: 18px; background: #232323;
text-align: center; padding: 10px
color: #FFF }
}
.dial .search input[type=text] {
.dial .btn { background-color: transparent;
margin-bottom: 10px font-family: inherit;
} font-size: 18px;
color: #FFF;
.dial .columns .column { border: 0px;
padding-right: 10px
} width:100%
}
.dial .columns .column:last-child {
padding-right: 0 .dial .callStatus {
font-size: 18px;
text-align: center;
color: #FFF
}
.dial .btn {
margin-bottom: 10px
}
.dial .columns .column {
padding-right: 10px
}
.dial .columns .column:last-child {
padding-right: 0
} }

View File

@ -1,76 +1,76 @@
let audio = { let audio = {
audioLoop: null, audioLoop: null,
init: function() { init: function() {
if (ua.audioInstance) if (ua.audioInstance)
return; return;
ua.audioInstance = document.createElement('audio'); ua.audioInstance = document.createElement('audio');
}, },
addTrack: function(track) { addTrack: function(track) {
if (ua.audioInstance) if (ua.audioInstance)
this.stop(); this.stop();
this.init(); this.init();
ua.audioInstance.src = this.getTrackPath(track); ua.audioInstance.src = this.getTrackPath(track);
}, },
addStream: function(stream) { addStream: function(stream) {
if (ua.audioInstance) if (ua.audioInstance)
this.stop(); this.stop();
this.init(); this.init();
ua.audioInstance.srcObject = stream; ua.audioInstance.srcObject = stream;
}, },
play: function(loop = false) { play: function(loop = false) {
if (!ua.audioInstance) if (!ua.audioInstance)
return; return;
ua.audioInstance.volume = Softphone.getVolume(); ua.audioInstance.volume = Softphone.getVolume();
ua.audioInstance.play(); ua.audioInstance.play();
if (loop) { if (loop) {
this.audioLoop = setInterval(function() { this.audioLoop = setInterval(function() {
ua.audioInstance.play(); ua.audioInstance.play();
}, 2000); }, 2000);
} }
}, },
stop: function() { stop: function() {
if (!ua.audioInstance) if (!ua.audioInstance)
return; return;
if (this.audioLoop) if (this.audioLoop)
clearInterval(this.audioLoop); clearInterval(this.audioLoop);
ua.audioInstance.pause(); ua.audioInstance.pause();
ua.audioInstance = null; ua.audioInstance = null;
}, },
isPlaying: function() { isPlaying: function() {
if (!ua.audioInstance.paused) if (!ua.audioInstance.paused)
return true; return true;
}, },
getTrackPath: function(track) { getTrackPath: function(track) {
return `/static/audio/${track}.wav`; return `/static/audio/${track}.wav`;
} }
} }

View File

@ -1,168 +1,65 @@
window.addEventListener('load', function() { $(window).on('load', function() {
/**
* Incoming/Outgoint calls
*/
/* if (!Softphone.isOnCall()) {
let number = Util.query('number');
Softphone.call(number);
} */
/** /**
* Make new call * Make new call
*/ */
$('call').addEventListener('click', function(event) { $(document).on('click', '#call', function() {
if (ua.sessionInstance && ua.sessionInstance.direction === 'incoming') let number = $('#callNumber').val();
ua.sessionInstance.answer(options);
let number = $('callNumber').value; if (number)
$('callNumber').value = ''; Softphone.call(number, options);
if (number != '') { return false;
Softphone.call(number);
} else {
notify('Introduce un destinatario para realizar la llamada');
}
event.preventDefault();
}); });
/** /**
* Reset call number field * Insert key on call field
*/ */
$('clear').addEventListener('click', function(event) { $(document).on('click', '#zero, #one, #two, #three, #four, '
$('callNumber').value = ''; + '#five, #six, #seven, #eight, #nine, #asterisk, #pad', padKey);
audio.addTrack('reset'); /**
audio.play(); * History
event.preventDefault(); */
$(document).on('click', '#history', function() {
Util.navigate('#content', '/history');
return false;
}); });
/** /**
* End a call * Show/Hide dialpad
*/ */
$('callHangup').addEventListener('click', function(event) { $(document).on('click', '#dial', function() {
Util.navigate('#side', '/dialpad');
return false;
});
/**
* Accept incoming call
*/
$(document).on('click', '#accept', function() {
Softphone.answer(options);
return false;
});
/**
* Decline incoming call
*/
$(document).on('click', '#decline', function() {
Softphone.hangup(); Softphone.hangup();
audio.addTrack('hangup'); return false;
audio.play();
event.preventDefault();
});
/* *
* Insert key on call field
*/
$('zero').addEventListener('click', padKey);
/**
* Insert key on call field
*/
$('one').addEventListener('click', padKey);
/**
* Insert key on call field
*/
$('two').addEventListener('click', padKey);
/**
* Insert key on call field
*/
$('three').addEventListener('click', padKey);
/**
* Insert key on call field
*/
$('four').addEventListener('click', padKey);
/**
* Insert key on call field
*/
$('five').addEventListener('click', padKey);
/**
* Insert key on call field
*/
$('six').addEventListener('click', padKey);
/**
* Insert key on call field
*/
$('seven').addEventListener('click', padKey);
/**
* Insert key on call field
*/
$('eight').addEventListener('click', padKey);
/**
* Insert key on call field
*/
$('nine').addEventListener('click', padKey);
/**
* Insert key on call field
*/
$('asterisk').addEventListener('click', padKey);
/**
* Insert key on call field
*/
$('pad').addEventListener('click', padKey);
/**
* Transfer current call
*/
$('callTransfer').addEventListener('click', function(event) {
let number = document.getElementById('callNumber').value;
if (number != '') {
Softphone.transfer(number);
}
event.preventDefault();
});
/**
* Hold current call
*/
$('callPause').addEventListener('click', function(event) {
if (Softphone.isOnHold()) {
Softphone.unhold();
} else {
Softphone.hold();
}
event.preventDefault();
});
/**
* Do not disturb
*/
$('doNotDisturb').addEventListener('click', function(event) {
event.preventDefault();
});
/**
* Call settings
*/
$('callConfig').addEventListener('click', function(event) {
event.preventDefault();
});
/**
* Change volume action
*/
$('volume').addEventListener('change', function(event) {
if (!ua.callInstance)
return;
ua.audioInstance.volume = this.value;
});
$('mic').addEventListener('click', function(event) {
if(Softphone.isMuted()) {
Softphone.unmute();
} else {
Softphone.mute();
}
event.preventDefault();
}); });
/** /**
@ -173,7 +70,7 @@ window.addEventListener('load', function() {
let key = event.target.innerHTML; let key = event.target.innerHTML;
let keyName = event.target.id; let keyName = event.target.id;
$('callNumber').value += key; document.getElementById('callNumber').value += key;
audio.addTrack(keyName); audio.addTrack(keyName);
audio.play(); audio.play();
@ -184,6 +81,6 @@ window.addEventListener('load', function() {
/** /**
* Prevent page reload without confirmation * Prevent page reload without confirmation
*/ */
window.addEventListener("beforeunload", function (event) { window.addEventListener("beforeunload", function (event) {
event.returnValue = "\o/"; event.returnValue = "\o/";
}); });

4
static/js/jquery.min.js vendored Normal file

File diff suppressed because one or more lines are too long

0
static/js/session.js Normal file
View File

View File

@ -1,9 +1,20 @@
let Softphone = { let Softphone = {
/**
* Check if has a call session
*/
isOnCall: function() {
if (ua.sessionInstance)
return true;
return false;
},
/** /**
* Make a new call * Make a new call
*/ */
call: function(number) { call: function(number) {
if (ua.sessionInstance) if (this.isOnCall())
return; return;
ua.sessionInstance = ua.call(`sip:${number}@${uriHost}`, options); ua.sessionInstance = ua.call(`sip:${number}@${uriHost}`, options);
@ -13,17 +24,27 @@ let Softphone = {
* Hang up current call * Hang up current call
*/ */
hangup: function() { hangup: function() {
if (!ua.sessionInstance) if (!this.isOnCall())
return; return;
ua.sessionInstance.terminate(); ua.sessionInstance.terminate();
}, },
/**
* Answer incoming call
*/
answer: function() {
if (!this.isOnCall())
return;
ua.sessionInstance.answer(options);
},
/** /**
* Mute current call * Mute current call
*/ */
mute: function() { mute: function() {
if (!ua.sessionInstance) if (!this.isOnCall())
return return
ua.sessionInstance.mute(); ua.sessionInstance.mute();
@ -33,7 +54,7 @@ let Softphone = {
* Unmute current call * Unmute current call
*/ */
unmute: function() { unmute: function() {
if (!ua.sessionInstance) if (!this.isOnCall())
return return
ua.sessionInstance.unmute(); ua.sessionInstance.unmute();
@ -43,7 +64,7 @@ let Softphone = {
* Get if current call is muted * Get if current call is muted
*/ */
isMuted: function() { isMuted: function() {
if (!ua.sessionInstance) if (!this.isOnCall())
return return
return ua.sessionInstance.isMuted(); return ua.sessionInstance.isMuted();
@ -53,7 +74,7 @@ let Softphone = {
* Hold current call * Hold current call
*/ */
hold: function() { hold: function() {
if (!ua.sessionInstance) if (!this.isOnCall())
return return
ua.sessionInstance.hold(); ua.sessionInstance.hold();
@ -73,7 +94,7 @@ let Softphone = {
* Get if current call is on hold * Get if current call is on hold
*/ */
isOnHold: function() { isOnHold: function() {
if (!ua.sessionInstance) if (!this.isOnCall())
return return
return ua.sessionInstance.isOnHold().local; return ua.sessionInstance.isOnHold().local;
@ -83,7 +104,7 @@ let Softphone = {
* Transfer current call * Transfer current call
*/ */
transfer: function(number) { transfer: function(number) {
if (!ua.sessionInstance) if (!this.isOnCall())
return return
ua.sessionInstance.refer(`sip:${number}@${uriHost}`); ua.sessionInstance.refer(`sip:${number}@${uriHost}`);
@ -107,5 +128,25 @@ let Softphone = {
setStatus: function() { setStatus: function() {
},
/**
* Returns a number from incoming calls
*/
getRemoteIdentity: function() {
if (!this.isOnCall())
return;
return ua.sessionInstance._remote_identity._uri._user;
},
/**
* Returns call direction
*/
getDirection: function() {
if (!this.isOnCall())
return;
return ua.sessionInstance.direction;
} }
} }

View File

@ -1,171 +1,172 @@
const socketHost = 'ws://pbx.dyn.verdnatura.es:8088/asterisk/ws'; const socketHost = 'ws://pbx.dyn.verdnatura.es:8088/asterisk/ws';
const uriHost = 'pbx.dyn.verdnatura.es'; const uriHost = 'pbx.dyn.verdnatura.es';
var options = { var options = {
mediaConstraints: { mediaConstraints: {
audio: true, audio: true,
video: false video: false
}, },
session_timers: false, session_timers: false,
volume: 0.5, volume: 0.5,
microphone: true microphone: true
}; };
let socket = new JsSIP.WebSocketInterface(socketHost); let socket = new JsSIP.WebSocketInterface(socketHost);
let configuration = { let configuration = {
sockets : [ socket ], sockets : [ socket ],
uri : 'sip:8000@pbx.dyn.verdnatura.es', uri : 'sip:8000@pbx.dyn.verdnatura.es',
password : '123456', password : '123456',
authorizationUser: '8000', authorizationUser: '8000',
hackIpInContact: true, hackIpInContact: true,
rtcpMuxPolicy: 'negotiate', rtcpMuxPolicy: 'negotiate',
hackWssInTransport: true hackWssInTransport: true
}; };
let ua = new JsSIP.UA(configuration); let ua = new JsSIP.UA(configuration);
/** /**
* Show event message * Show event message
* @param {Object} event * @param {Object} event
*/ */
function eventStatus(event) { function eventStatus(event) {
if (event.cause === JsSIP.C.causes.CONNECTION_ERROR) if (event.cause === JsSIP.C.causes.CONNECTION_ERROR)
return notify('Ha ocurrido un error de conexión'); return Util.notify('Ha ocurrido un error de conexión');
if (event.cause === JsSIP.C.causes.INTERNAL_ERROR) if (event.cause === JsSIP.C.causes.INTERNAL_ERROR)
return notify('Ha ocurrido un error inesperado'); return Util.notify('Ha ocurrido un error inesperado');
if (event.cause === JsSIP.C.causes.AUTHENTICATION_ERROR) if (event.cause === JsSIP.C.causes.AUTHENTICATION_ERROR)
return notify('No se ha podido autenticar la sesión'); return Util.notify('No se ha podido autenticar la sesión');
if (event.cause === JsSIP.C.causes.UNAVAILABLE) if (event.cause === JsSIP.C.causes.UNAVAILABLE)
return notify('El destinatario no está disponible'); return Util.notify('El destinatario no está disponible');
if (event.cause === JsSIP.C.causes.BUSY) if (event.cause === JsSIP.C.causes.BUSY)
return notify('El destinatario está ocupado'); return Util.notify('El destinatario está ocupado');
if (event.cause === JsSIP.C.causes.REJECTED) if (event.cause === JsSIP.C.causes.REJECTED)
return notify('La conexión ha sido rechazada') return Util.notify('La llamada ha sido rechazada')
if (event.cause === JsSIP.C.causes.NOT_FOUND) if (event.cause === JsSIP.C.causes.NOT_FOUND)
return notify('No se ha podido encontrar el destinatario'); return Util.notify('No se ha podido encontrar el destinatario');
if (event.cause === JsSIP.C.causes.REQUEST_TIMEOUT) if (event.cause === JsSIP.C.causes.REQUEST_TIMEOUT)
return notify('El destinatario no ha respondido la llamada'); return Util.notify('El destinatario no ha respondido la llamada');
if (event.cause === JsSIP.USER_DENIED_MEDIA_ACCESS) if (event.cause === JsSIP.USER_DENIED_MEDIA_ACCESS)
return notify('Es necesario permitir el acceso al micrófono'); return Util.notify('Es necesario permitir el acceso al micrófono');
} }
/** /**
* UA register * UA register
*/ */
ua.on('registered', function(event) { ua.on('registered', function(event) {
$('callStatus').innerHTML = 'Conectado'; $('.profile .status').removeClass('offline').addClass('online');
}); });
/** /**
* Client disconnection * Client disconnection
*/ */
ua.on('disconnected', function(event) { ua.on('disconnected', function(event) {
$('callStatus').innerHTML = 'Desconectado'; $('.profile .status').removeClass('online').addClass('offline');
}); eventStatus(event);
});
ua.on('registrationFailed', function(event) {
ua.on('registrationFailed', function(event) {
Softphone.notifyStatus(event); $('.profile .status').removeClass('offline').addClass('error');
eventStatus(event);
$('callStatus').innerHTML = 'Desconectado'; });
});
/**
/** * Call session
* Call session */
*/ ua.on('newRTCSession', function(event) {
ua.on('newRTCSession', function(event) { let session = event.session;
let session = event.session; ua.sessionInstance = session;
ua.sessionInstance = session;
session.on('confirmed', function() {
console.log(session); console.log('confirmed');
});
session.on('confirmed', function() {
console.log('confirmed'); session.on('reinvite', function() {
}) console.log('reinvite');
});
session.on('reinvite', function() {
console.log('reinvite'); session.on('update', function() {
}) console.log('update');
});
session.on('update', function() {
console.log('update'); /**
}) * Call in progress
/** */
* Call in progress session.on('progress', function(event) {
*/ if (session.direction === 'incoming') {
session.on('progress', function(event) { Util.load('#content', '/call', function() {
console.log('progress'); audio.addTrack('incoming');
if (session.direction === 'incoming') { audio.play(true);
audio.addTrack('incoming'); });
audio.play(true); } else {
$('callStatus').innerHTML = 'Llamada entrante...'; Util.load('#content', '/call', function() {
} else { audio.addTrack('outgoing');
audio.addTrack('outgoing'); audio.play(true);
audio.play(true); });
$('callStatus').innerHTML = 'Llamando...'; }
} });
});
/**
/** * Call accepted
* Call accepted */
*/ session.on('accepted', function(event) {
session.on('accepted', function(event) { console.log('accepted');
console.log('accepted'); document.getElementById('callStatus').innerHTML = 'Llamada conectada';
$('callStatus').innerHTML = 'Llamada conectada'; if (session.connection.getRemoteStreams().length > 0) {
if (session.connection.getRemoteStreams().length > 0) { let stream = session.connection.getRemoteStreams()[0];
let stream = session.connection.getRemoteStreams()[0];
audio.addStream(stream);
audio.addStream(stream); audio.play();
audio.play(); }
} Util.startTimer();
startTimer(); });
});
session.on('hold', function(event) {
session.on('hold', function(event) { $('callStatus').innerHTML = 'Llamada en espera';
$('callStatus').innerHTML = 'Llamada en espera'; });
});
session.on('unhold', function(event) {
session.on('unhold', function(event) { $('callStatus').innerHTML = 'Llamada conectada';
$('callStatus').innerHTML = 'Llamada conectada'; });
});
session.on('refer', function() {
session.on('refer', function() { $('callStatus').innerHTML = 'Llamada transferida';
$('callStatus').innerHTML = 'Llamada transferida'; });
});
/**
/** * Call ended
* Call ended */
*/ session.on('ended', function(event) {
session.on('ended', function(event) { audio.addTrack('hangup');
audio.addTrack('hangup'); audio.play();
audio.play();
Util.load('#content', '/', function() {
stopTimer();
});
$('callStatus').innerHTML = 'Conectado';
ua.sessionInstance = null; Util.stopTimer();
eventStatus(event);
}); ua.sessionInstance = null;
eventStatus(event);
/** });
* Call failed
*/ /**
session.on('failed', function(event) { * Call failed
audio.addTrack('hangup'); */
audio.play(); session.on('failed', function(event) {
audio.addTrack('hangup');
$('callStatus').innerHTML = 'Conectado'; audio.play();
ua.sessionInstance = null;
eventStatus(event); ua.sessionInstance = null;
}); eventStatus(event);
}); });
});
ua.start(); ua.start();

View File

@ -1,57 +1,105 @@
let timer; let Util = {
let timerSeconds = 1; timerSeconds: 1,
/** /**
* Object selector * Get URL query
*/ */
function $(object) { query: function(name) {
return document.getElementById(object); let queries = window.location.search.replace('?', '').split('&');
}
for(let i = 0; i < queries.length; i++) {
let query = queries[i].split('=');
let keyName = query[0];
let value = query[1];
if (keyName == name)
return value;
}
},
/**
* Notify
*/
notify: function(message) {
if (!document.getElementById('notifications')) {
let container = document.createElement('div');
container.setAttribute('id', 'notifications');
document.body.appendChild(container);
}
let dialog = document.createElement('div');
let text = document.createTextNode(message);
dialog.appendChild(text);
dialog.setAttribute('class', 'dialog');
setTimeout(function() {
dialog.remove();
}, 8000);
document.getElementById('notifications').insertBefore(dialog, document.getElementById('notifications').firstChild);
},
/** /**
* Start call timer * Start call timer
*/ */
function startTimer() { startTimer: function() {
timer = setInterval(function() { this.timer = setInterval(() => {
let date = new Date(null); let date = new Date(null);
date.setSeconds(timerSeconds); console.log(this.timerSeconds);
date.setSeconds(this.timerSeconds);
$('timer').innerHTML = date.toISOString().substr(11, 8); document.getElementById('timer').innerHTML = date.toISOString().substr(11, 8);
timerSeconds++; this.timerSeconds++;
}, 1000) }, 1000);
} },
/** /**
* Stop call timer * Stop call timer
*/ */
function stopTimer() { stopTimer: function() {
clearInterval(timer); clearInterval(this.timer);
timer = null; this.timer = null;
timerSeconds = 0; this.timerSeconds = 0;
$('timer').innerHTML = '00:00:00'; document.getElementById('timer').innerHTML = '00:00:00';
} },
/**
* Page navigation
*/
navigate: function(container, path) {
this.load(container, path, function() {
if ($('#side').css('display') == 'block') {
$('#side').css('display', 'none');
$('#container').removeClass('side-display');
} else {
$('#side').css('display', 'block');
$('#container').addClass('side-display');
}
});
},
/**
* Load view
* @param {String} container Container element
* @param {String} path Path to view
*/
load: function(container, path, cb) {
$(container).load(path + '/?token=' + this.query('token'), function(response, status) {
if (status == 'error')
alert(response);
cb();
});
},
showSpinner: function() {
},
hideSpinner: function() {
function notify(message) {
if (!$('notifications')) {
let container = document.createElement('div');
container.setAttribute('id', 'notifications');
document.body.appendChild(container);
} }
};
let dialog = document.createElement('div');
let text = document.createTextNode(message);
dialog.appendChild(text);
dialog.setAttribute('class', 'dialog');
setTimeout(function() {
dialog.remove();
}, 8000);
$('notifications').insertBefore(dialog, $('notifications').firstChild);
}
function showStatus(status) {
$('callStatus').innerHTML = 'Desconectado';
}

View File

@ -8,6 +8,9 @@ module.exports = {
render: function(view, args, response) { render: function(view, args, response) {
let instance = require(`./views/${view}/index.js`); let instance = require(`./views/${view}/index.js`);
if (!instance.partials)
return response.render(`${view}/index`, instance);
instance.init(args, () => { instance.init(args, () => {
this.getPartials(instance, args, (instance) => { this.getPartials(instance, args, (instance) => {
response.render(`${view}/index`, instance); response.render(`${view}/index`, instance);

84
views/call/index.html Normal file
View File

@ -0,0 +1,84 @@
<div class="call">
<div style="width:300px;margin: 50px auto 0 auto">
<div class="photo" style="background-color:#333;width:200px;height:200px;text-align:center;padding: 25px 0;margin:0 auto">
<i class="material-icons" style="font-size: 120px">person</i>
</div>
<div class="card">
<div>Nombre:</div>
<div>dd:</div>
</div>
<div class="dial">
<div class="callStatus" id="callStatus"></div>
<div class="callTimer">
<span id="timer">00:00:00</span>
</div>
<div class="controls">
<div class="columns">
<div class="column x25">
<a href="" class="btn big icon green" id="accept" title="Aceptar llamada">
<i class="material-icons">call</i>
</a>
</div>
<div class="column x25">
<a href="" class="btn big icon red" id="decline" title="Colgar">
<i class="material-icons">call_end</i>
</a>
</div>
<div class="column x25">
<a href="" class="btn big icon white" id="transfer" title="Transferir llamada">
<i class="material-icons">phone_forwarded</i>
</a>
</div>
<div class="column x25">
<a href="" class="btn big icon white" id="hold" title="Pausar llamada">
<i class="material-icons">phone_paused</i>
</a>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- <div style="width:300px;margin: 50px auto 0 auto">
<div class="photo" style="background-color:#333;width:200px;height:200px;text-align:center;padding: 25px 0;margin:0 auto">
<i class="material-icons" style="font-size: 120px">person</i>
</div>
<div class="card">
<div>Nombre:</div>
<div>dd:</div>
</div>
<div class="dial">
<div class="callStatus" id="callStatus"></div>
<div class="callTimer">
<span id="timer">00:00:00</span>
</div>
<div class="controls">
<div class="columns">
<div class="column x25">
<a href="" class="btn big icon green" id="accept" title="Aceptar llamada">
<i class="material-icons">call</i>
</a>
</div>
<div class="column x25">
<a href="" class="btn big icon red" id="hangup" title="Colgar">
<i class="material-icons">call_end</i>
</a>
</div>
<div class="column x25">
<a href="" class="btn big icon white" id="transfer" title="Transferir llamada">
<i class="material-icons">phone_forwarded</i>
</a>
</div>
<div class="column x25">
<a href="" class="btn big icon white" id="pause" title="Pausar llamada">
<i class="material-icons">phone_paused</i>
</a>
</div>
</div>
</div>
</div>
</div> -->

6
views/call/index.js Normal file
View File

@ -0,0 +1,6 @@
module.exports = {
init: function(args, cb) {
cb();
}
}

46
views/dialpad/index.html Normal file
View File

@ -0,0 +1,46 @@
<div class="dial">
<div class="search">
<div class="control">
<input type="text" placeholder="Introduce un número..." id="callNumber"/> <i class="material-icons" id="clear">close</i>
</div>
</div>
<!-- Controls block start -->
<div class="controls">
<div class="columns">
<div class="column x50">
<a href="" class="btn normal icon green" id="call" title="LLamar">
<i class="material-icons">call</i>
</a>
</div>
<div class="column x50">
<a href="" class="btn normal icon white" id="clear" title="Vaciar campo de llamada">
<i class="material-icons">DND</i>
</a>
</div>
</div>
<div class="columns">
<div class="column x33">
<a href="" class="btn normal white pad" id="one">1</a>
<a href="" class="btn normal white pad" id="four">4</a>
<a href="" class="btn normal white" id="seven">7</a>
<a href="" class="btn normal white" id="asterisk">*</a>
</div>
<div class="column x33">
<a href="" class="btn normal white pad" id="two">2</a>
<a href="" class="btn normal white pad" id="five">5</a>
<a href="" class="btn normal white pad" id="eight">8</a>
<a href="" class="btn normal white pad" id="zero">0</a>
</div>
<div class="column x33">
<a href="" class="btn normal white pad" id="three">3</a>
<a href="" class="btn normal white pad" id="six">6</a>
<a href="" class="btn normal white pad" id="nine">9</a>
<a href="" class="btn normal white pad" id="pad">#</a>
</div>
</div>
</div>
<!-- Controls block end -->
</div>

0
views/dialpad/index.js Normal file
View File

View File

@ -1,33 +1,17 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="es"> <html lang="es">
<head> <head>
<title>Softphone</title> <title>Softphone</title>
<meta charset="utf-8"/> <meta charset="utf-8"/>
<link rel="stylesheet" type="text/css" href="/static/css/app.css"/> <link rel="stylesheet" type="text/css" href="/static/css/app.css"/>
<link rel="stylesheet" type="text/css" href="/static/css/components.css"/> <link rel="stylesheet" type="text/css" href="/static/css/components.css"/>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<script type="text/javascript" src="/static/js/jssip.js?v=1"></script> <script type="text/javascript" src="/static/js/jquery.min.js"></script>
<script type="text/javascript" src="/static/js/ua.js?v=1"></script> <script type="text/javascript" src="/static/js/jssip.js?v=1"></script>
<script type="text/javascript" src="/static/js/audio.js?v=1"></script> <script type="text/javascript" src="/static/js/ua.js?v=1"></script>
<script type="text/javascript" src="/static/js/softphone.js?v=1"></script> <script type="text/javascript" src="/static/js/audio.js?v=1"></script>
<script type="text/javascript" src="/static/js/util.js?v=1"></script> <script type="text/javascript" src="/static/js/softphone.js?v=1"></script>
<script type="text/javascript" src="/static/js/event.js?v=1"></script> <script type="text/javascript" src="/static/js/util.js?v=1"></script>
</head> <script type="text/javascript" src="/static/js/event.js?v=1"></script>
<body> </head>
<!-- Quickbar block start --> <body>
<div class="quickbar">
<img src="http://salix.verdnatura.es/static/34777fb85a1496d64469bd8092a53ef6.svg"/>
<div class="pull-right">
<a href="">
<i class="material-icons">settings</i>
</a>
<a href="">
<i class="material-icons">language</i>
</a>
<a href="">
<i class="material-icons">exit_to_app</i>
</a>
</div>
</div>
<!-- Quickbar block end -->

1
views/history/index.html Normal file
View File

@ -0,0 +1 @@
Contactos

6
views/history/index.js Normal file
View File

@ -0,0 +1,6 @@
module.exports = {
init: function(args, cb) {
cb();
}
}

View File

@ -1,83 +1,3 @@
{{> header}} {{> header}}
{{> side}} {{> navigation}}
{{> quickbar}}
<!-- Chatbox block start -->
<div class="chatbox">
<div class="dial">
<div class="search">
<div class="control">
<input type="text" placeholder="Introduce un número..." id="callNumber"/>
</div>
</div>
<div class="callStatus" id="callStatus"></div>
<div class="callTimer">
<span id="timer">00:00:00</span>
</div>
<!-- Controls block start -->
<div class="controls">
<div class="columns">
<div class="column x33">
<a href="" class="btn big icon green" id="call" title="LLamar">
<i class="material-icons">call</i>
</a>
</div>
<div class="column x33">
<a href="" class="btn big icon white" id="clear" title="Vaciar campo de llamada">
<i class="material-icons">clear_all</i>
</a>
</div>
<div class="column x33">
<a href="" class="btn big icon red" id="callHangup" title="Colgar">
<i class="material-icons">call_end</i>
</a>
</div>
</div>
<div class="columns">
<div class="column x25">
<a href="" class="btn big white pad" id="one">1</a>
<a href="" class="btn big white pad" id="four">4</a>
<a href="" class="btn big white" id="seven">7</a>
<a href="" class="btn big white" id="asterisk">*</a>
</div>
<div class="column x25">
<a href="" class="btn big white pad" id="two">2</a>
<a href="" class="btn big white pad" id="five">5</a>
<a href="" class="btn big white pad" id="eight">8</a>
<a href="" class="btn big white pad" id="zero">0</a>
</div>
<div class="column x25">
<a href="" class="btn big white pad" id="three">3</a>
<a href="" class="btn big white pad" id="six">6</a>
<a href="" class="btn big white pad" id="nine">9</a>
<a href="" class="btn big white pad" id="pad">#</a>
</div>
<div class="column x25">
<a href="" class="btn big icon white" id="callTransfer" title="Transferir llamada">
<i class="material-icons">phone_forwarded</i>
</a>
<a href="" class="btn big icon white" id="callPause" title="Pausar llamada">
<i class="material-icons">phone_paused</i>
</a>
<a href="" class="btn big icon white" id="doNotDisturb" title="No molestar">
<i class="material-icons">phone_locked</i>
</a>
<a href="" class="btn big icon white" id="callConfig" title="Configuración">
<i class="material-icons">settings_phone</i>
</a>
</div>
</div>
</div>
<a href="" class="btn normal yellow">
<i class="material-icons">add</i> Nuevo contacto</a>
<a href="" class="btn normal yellow">
<i class="material-icons">search</i>Buscar contacto</a>
<a href="" class="btn normal yellow">Ver historial</a>
</div>
<!-- Controls block end -->
</div>
<!-- Chatbox block end -->

View File

@ -6,6 +6,7 @@ module.exports = {
partials: { partials: {
header: 'header', header: 'header',
side: 'side' navigation: 'navigation',
quickbar: 'quickbar'
} }
} }

View File

@ -0,0 +1,17 @@
<!-- Navigation block start -->
<div class="navigation">
<img src="http://salix.verdnatura.es/static/34777fb85a1496d64469bd8092a53ef6.svg"/>
<div class="pull-right">
<a href="">
<i class="material-icons">settings</i>
</a>
<a href="">
<i class="material-icons">language</i>
</a>
<a href="">
<i class="material-icons">exit_to_app</i>
</a>
</div>
</div>
<!-- Navigation block end -->

View File

@ -0,0 +1,5 @@
module.exports = {
init: function(args, cb) {
cb();
}
}

56
views/quickbar/index.html Normal file
View File

@ -0,0 +1,56 @@
<!-- Container block start -->
<div id="container">
<!-- Quickbar block start -->
<div class="quickbar">
<!-- Profile block start -->
<div class="profile">
<ul>
<li>
<a href="" title="{{name}} - SIP {{extension}}">
<span class="status offline" title="Estado"></span>
<i class="material-icons">account_circle</i>
</a>
</li>
</ul>
</div>
<!-- Profile block end -->
<!-- Navigation block start -->
<ul>
<li>
<a href="" id="history">
<i class="material-icons">phone</i>
</a>
</li>
<li>
<a href="" id="dial" class="active" title="Mostrar teclado">
<i class="material-icons">dialpad</i>
</a>
</li>
<!-- <li>
<a href="" title="Añadir llamada"><i class="material-icons">phone_in_talk</i></a>
</li>-->
</ul>
<!-- Navigation block end -->
<div class="audioControls">
<div>
<a href="" id="muteVolume" title="Silenciar volumen">
<i class="material-icons">volume_down</i>
</a>
<!--<input type="range" id="volume" min="0" max="1" step="0.1" value="0.5"/>-->
</div>
<div>
<a href="" id="muteMic" title="Silenciar micrófono"><i class="material-icons">mic</i></a>
</div>
</div>
</div>
<!-- Quickbar block end -->
<!-- Side block start -->
<div id="side"></div>
<!-- Side block end -->
<div id="content"></div>
</div>
<!-- Container block end -->

View File

@ -1,45 +0,0 @@
<!-- Side block start -->
<div class="side">
<!-- User block start -->
<div class="user">
<div class="pull-left">
<div class="name">{{name}}</div>
<spa class="extension">SIP {{extension}}</span>
</div>
<div class="pull-right">
<a href="">
<i class="material-icons">menu</i>
</a>
</div>
</div>
<!-- User block end -->
<!-- Navigation block start -->
<div class="navigation">
<a href="" class="active"><i class="material-icons">home</i></a>
<a href=""><i class="material-icons">contacts</i></a>
</div>
<!-- Navigation block end -->
<div class="title">
Historial de llamadas
</div>
<div class="callHistory">
</div>
<div class="audioControls">
<div>
<i class="material-icons">volume_down</i>
<input type="range" id="volume" min="0" max="1" step="0.1" value="0.5"/>
</div>
<div>
<a href="" id="mic"><i class="material-icons">mic</i></a>
</div>
</div>
<div class="contacts">
<i class="material-icons">load</i>
</div>
</div>
<!-- Side block end -->