1
0
Fork 0
mirror of https://github.com/YunoHost-Apps/jappix_ynh.git synced 2024-09-03 19:26:19 +02:00
jappix_ynh/source/app/javascripts/muji.js

1845 lines
60 KiB
JavaScript
Raw Normal View History

2014-11-25 20:12:58 +01:00
/*
Jappix - An open social platform
These are the Muji helpers & launchers
-------------------------------------------------
License: AGPL
Author: Valérian Saliou
*/
// Bundle
var Muji = (function() {
/**
* Alias of this
* @private
*/
var self = {};
2014-11-25 23:42:38 +01:00
/* Constants */
self.INVITE_MAX_DELAY = 60;
2014-11-25 20:12:58 +01:00
/* Variables */
self._session = null;
self._caller_xid = null;
/**
* Opens the Muji interface (depending on the state)
* @public
* @return {boolean}
*/
self.open = function() {
try {
var call_tool_sel = $('#top-content .tools.call');
if(call_tool_sel.is('.active')) {
Console.info('Opened call notification drawer');
} else if(call_tool_sel.is('.streaming')) {
self._show_interface();
Console.info('Opened Muji box');
} else {
Console.warn('Could not open any Muji tool (race condition on state)');
}
} catch(e) {
Console.error('Muji.open', e);
} finally {
return false;
}
};
/**
* Returns the Muji session arguments (used to configure it)
* @private
* @param connection
* @param xid
* @param hash
* @param local_view
* @return {object}
*/
self._args = function(connection, xid, hash, media, local_view) {
args = {};
try {
// Network configuration
var ice_servers = Call.generate_ice_servers();
// Muji arguments
args = {
// Configuration (required)
connection: connection,
to: xid,
media: media,
local_view: local_view,
stun: ice_servers.stun,
turn: ice_servers.turn,
resolution: 'sd',
debug: Call._consoleAdapter,
// Safety options (optional)
password_protect: true,
// Custom handlers (optional)
room_message_in: function(muji, stanza) {
var from = muji.utils.stanza_from(stanza);
var username = muji.utils.extract_username(from);
var body = stanza.getBody();
var muji_sel = $('#muji');
var mode = (username === $('#muji').attr('data-username')) ? 'me' : 'him';
if(username && body && muji_sel.size()) {
var avatar_html = '';
if(mode === 'him') {
2014-11-25 23:42:38 +01:00
avatar_html =
'<div class="message_avatar avatar-container">' +
'<img class="avatar" src="' + './images/others/default-avatar.png' + '" alt="" />' +
2014-11-25 20:12:58 +01:00
'</div>';
}
muji_sel.find('.chatroom .chatroom_view').append(
2014-11-25 23:42:38 +01:00
'<div class="room_message ' + mode + ' ' + hex_md5(from) + '">' +
avatar_html +
2014-11-25 20:12:58 +01:00
2014-11-25 23:42:38 +01:00
'<div class="message_content">' +
'<span class="message_bubble">' + body.htmlEnc() + '</span>' +
'<span class="message_author">' + username.htmlEnc() + '</span>' +
'</div>' +
2014-11-25 20:12:58 +01:00
2014-11-25 23:42:38 +01:00
'<div class="clear"></div>' +
2014-11-25 20:12:58 +01:00
'</div>'
);
if($('#muji').is(':visible')) {
self._message_scroll();
} else {
self._message_notify();
}
Console.log('Muji._args > room_message_in', 'Displayed Muji message from: ' + username);
}
Console.log('Muji._args', 'room_message_in');
},
room_message_out: function(muji, stanza) {
Console.log('Muji._args', 'room_message_out');
},
room_presence_in: function(muji, stanza) {
Console.log('Muji._args', 'room_presence_in');
},
room_presence_out: function(muji, stanza) {
Console.log('Muji._args', 'room_presence_out');
},
2014-11-25 23:42:38 +01:00
2014-11-25 20:12:58 +01:00
session_prepare_pending: function(muji, stanza) {
// Temporary username
$('#muji').attr('data-username', muji.get_username());
// Notify user about preparing call
Call.notify(
JSJAC_JINGLE_SESSION_MUJI,
muji.get_to(),
'preparing',
muji.get_media(),
self.get_caller_xid()
);
Console.log('Muji._args', 'session_prepare_pending');
},
2014-11-25 23:42:38 +01:00
2014-11-25 20:12:58 +01:00
session_prepare_success: function(muji, stanza) {
// Final username
$('#muji').attr('data-username', muji.get_username());
Console.log('Muji._args', 'session_prepare_success');
},
2014-11-25 23:42:38 +01:00
2014-11-25 20:12:58 +01:00
session_prepare_error: function(muji, stanza) {
self._reset();
Call.notify(
JSJAC_JINGLE_SESSION_MUJI,
muji.get_to(),
'error',
muji.get_media(),
self.get_caller_xid()
);
Console.log('Muji._args', 'session_prepare_error');
},
2014-11-25 23:42:38 +01:00
2014-11-25 20:12:58 +01:00
session_initiate_pending: function(muji) {
Call.notify(
JSJAC_JINGLE_SESSION_MUJI,
muji.get_to(),
'waiting',
muji.get_media(),
self.get_caller_xid()
);
Console.log('Muji._args', 'session_initiate_pending');
},
2014-11-25 23:42:38 +01:00
2014-11-25 20:12:58 +01:00
session_initiate_success: function(muji, stanza) {
Call._unnotify();
// Start call! Go Go Go!
Call.start_session(muji.get_media());
self._show_interface();
Call.start_counter();
Console.log('Muji._args', 'session_initiate_success');
},
2014-11-25 23:42:38 +01:00
2014-11-25 20:12:58 +01:00
session_initiate_error: function(muji, stanza) {
self._reset();
Call.notify(
JSJAC_JINGLE_SESSION_MUJI,
muji.get_to(),
'error',
muji.get_media(),
self.get_caller_xid()
);
Console.log('Muji._args', 'session_initiate_error');
},
2014-11-25 23:42:38 +01:00
2014-11-25 20:12:58 +01:00
session_leave_pending: function(muji) {
self._reset();
Call.notify(
JSJAC_JINGLE_SESSION_MUJI,
muji.get_to(),
'ending',
muji.get_media(),
self.get_caller_xid()
);
Console.log('Muji._args', 'session_leave_pending');
},
2014-11-25 23:42:38 +01:00
2014-11-25 20:12:58 +01:00
session_leave_success: function(muji, stanza) {
self._reset();
Call.notify(
JSJAC_JINGLE_SESSION_MUJI,
muji.get_to(),
'ended',
muji.get_media(),
self.get_caller_xid()
);
Console.log('Muji._args', 'session_leave_success');
},
2014-11-25 23:42:38 +01:00
2014-11-25 20:12:58 +01:00
session_leave_error: function(muji, stanza) {
self._reset();
if(typeof muji.parent != 'undefined') {
muji = muji.parent;
}
Call.notify(
JSJAC_JINGLE_SESSION_MUJI,
muji.get_to(),
'ended',
muji.get_media(),
self.get_caller_xid()
);
Console.log('Muji._args', 'session_leave_error');
},
2014-11-25 23:42:38 +01:00
2014-11-25 20:12:58 +01:00
participant_prepare: function(muji, stanza) {
Console.log('Muji._args', 'participant_prepare');
},
2014-11-25 23:42:38 +01:00
2014-11-25 20:12:58 +01:00
participant_initiate: function(muji, stanza) {
Console.log('Muji._args', 'participant_initiate');
},
2014-11-25 23:42:38 +01:00
2014-11-25 20:12:58 +01:00
participant_leave: function(muji, stanza) {
Console.log('Muji._args', 'participant_leave');
},
2014-11-25 23:42:38 +01:00
2014-11-25 20:12:58 +01:00
participant_session_initiate_pending: function(muji, session) {
Console.log('Muji._args', 'participant_session_initiate_pending');
},
2014-11-25 23:42:38 +01:00
2014-11-25 20:12:58 +01:00
participant_session_initiate_success: function(muji, session, stanza) {
Console.log('Muji._args', 'participant_session_initiate_success');
},
2014-11-25 23:42:38 +01:00
2014-11-25 20:12:58 +01:00
participant_session_initiate_error: function(muji, session, stanza) {
Console.log('Muji._args', 'participant_session_initiate_error');
},
2014-11-25 23:42:38 +01:00
2014-11-25 20:12:58 +01:00
participant_session_initiate_request: function(muji, session, stanza) {
Console.log('Muji._args', 'participant_session_initiate_request');
},
2014-11-25 23:42:38 +01:00
2014-11-25 20:12:58 +01:00
participant_session_accept_pending: function(muji, session) {
Console.log('Muji._args', 'participant_session_accept_pending');
},
2014-11-25 23:42:38 +01:00
2014-11-25 20:12:58 +01:00
participant_session_accept_success: function(muji, session, stanza) {
Console.log('Muji._args', 'participant_session_accept_success');
},
2014-11-25 23:42:38 +01:00
2014-11-25 20:12:58 +01:00
participant_session_accept_error: function(muji, session, stanza) {
Console.log('Muji._args', 'participant_session_accept_error');
},
2014-11-25 23:42:38 +01:00
2014-11-25 20:12:58 +01:00
participant_session_accept_request: function(muji, session, stanza) {
Console.log('Muji._args', 'participant_session_accept_request');
},
2014-11-25 23:42:38 +01:00
2014-11-25 20:12:58 +01:00
participant_session_info_pending: function(muji, session) {
Console.log('Muji._args', 'participant_session_info_pending');
},
2014-11-25 23:42:38 +01:00
2014-11-25 20:12:58 +01:00
participant_session_info_success: function(muji, session, stanza) {
Console.log('Muji._args', 'participant_session_info_success');
},
2014-11-25 23:42:38 +01:00
2014-11-25 20:12:58 +01:00
participant_session_info_error: function(muji, session, stanza) {
Console.log('Muji._args', 'participant_session_info_error');
},
2014-11-25 23:42:38 +01:00
2014-11-25 20:12:58 +01:00
participant_session_info_request: function(muji, session, stanza) {
Console.log('Muji._args', 'participant_session_info_request');
},
2014-11-25 23:42:38 +01:00
2014-11-25 20:12:58 +01:00
participant_session_terminate_pending: function(muji, session) {
Console.log('Muji._args', 'participant_session_terminate_pending');
},
2014-11-25 23:42:38 +01:00
2014-11-25 20:12:58 +01:00
participant_session_terminate_success: function(muji, session, stanza) {
Console.log('Muji._args', 'participant_session_terminate_success');
},
2014-11-25 23:42:38 +01:00
2014-11-25 20:12:58 +01:00
participant_session_terminate_error: function(muji, session, stanza) {
Console.log('Muji._args', 'participant_session_terminate_error');
},
2014-11-25 23:42:38 +01:00
2014-11-25 20:12:58 +01:00
participant_session_terminate_request: function(muji, session, stanza) {
Console.log('Muji._args', 'participant_session_terminate_request');
},
2014-11-25 23:42:38 +01:00
2014-11-25 20:12:58 +01:00
add_remote_view: function(muji, username, media) {
Console.log('Muji._args', 'add_remote_view');
var muji_sel = $('#muji');
var nobody_sel = muji_sel.find('.empty_message');
var remote_container_sel = $('#muji .remote_container');
var remote_video_shaper_sel = remote_container_sel.find('.remote_video_shaper');
var view_sel = null;
var container_sel = remote_video_shaper_sel.filter(function() {
return ($(this).attr('data-username') + '') === (username + '');
});
var count_participants = remote_video_shaper_sel.filter(':has(video)').size();
// Not already in view?
if(!container_sel.size()) {
// Select first empty view
var first_empty_view_sel = remote_video_shaper_sel.filter(':not(:has(video)):first');
if(first_empty_view_sel.size()) {
container_sel = first_empty_view_sel;
// Remote poster
var remote_poster = './images/placeholders/jingle_video_remote.png';
if(media === 'audio') {
remote_poster = './images/placeholders/jingle_audio_remote.png';
}
// Append view
view_sel = $('<video src="" alt="" poster="' + remote_poster + '"></video>');
container_sel.attr('data-username', username);
view_sel.appendTo(container_sel);
// Append username label
container_sel.append(
'<span class="label_username">' + username.htmlEnc() + '</span>'
);
// Update counter
muji_sel.attr(
'data-count',
++count_participants
);
} else {
// Room is full...
muji_sel.find('.chatroom_participants .participants_full:hidden').show();
}
}
nobody_sel.hide();
Muji._update_count_participants(count_participants);
Muji._update_invite_participants();
// IMPORTANT: return view selector
return (view_sel !== null) ? view_sel[0] : view_sel;
},
2014-11-25 23:42:38 +01:00
2014-11-25 20:12:58 +01:00
remove_remote_view: function(muji, username) {
Console.log('Muji._args', 'remove_remote_view');
var muji_sel = $('#muji');
var nobody_sel = muji_sel.find('.empty_message');
var remote_container_sel = $('#muji .remote_container');
var remote_video_shaper_sel = remote_container_sel.find('.remote_video_shaper');
var container_sel = remote_video_shaper_sel.filter(function() {
return ($(this).attr('data-username') + '') === (username + '');
});
var count_participants = remote_video_shaper_sel.filter(':has(video)').size();
// Exists in view?
if(container_sel.size()) {
var view_sel = container_sel.find('video');
// Remove video
view_sel.stop(true).fadeOut(250, function() {
container_sel.empty();
// Update counter
muji_sel.attr(
'data-count',
--count_participants
);
// Nobody left in the room?
if(!remote_video_shaper_sel.find('video').size()) {
nobody_sel.show();
muji_sel.removeAttr('data-count');
}
// Update participants counter
muji_sel.find('.chatroom_participants .participants_full:visible').hide();
Muji._update_count_participants(count_participants);
Muji._update_invite_participants();
});
// IMPORTANT: return view selector
if(view_sel.size()) {
return view_sel[0];
}
}
return null;
}
};
} catch(e) {
Console.error('Muji._args', e);
} finally {
return args;
}
};
/**
* Launch a new Muji session with given buddy
* @private
* @param room
* @param mode
* @param args_invite
* @return {boolean}
*/
self._new = function(room, mode, stanza, args_invite) {
var status = false;
try {
if(!room) {
throw 'No room to be joined given!';
}
var hash = hex_md5(room);
// Create interface for video containers
$('body').addClass('in_muji_call');
var muji_sel = self._create_interface(room, mode);
// Filter media
var media = null;
switch(mode) {
case 'audio':
media = JSJAC_JINGLE_MEDIA_AUDIO; break;
case 'video':
media = JSJAC_JINGLE_MEDIA_VIDEO; break;
}
// Start the Jingle negotiation
var args = self._args(
con,
room,
hash,
media,
muji_sel.find('.local_video video')[0]
);
if(typeof args_invite == 'object') {
if(args_invite.password) {
args.password = args_invite.password;
}
args.media = (args_invite.media == JSJAC_JINGLE_MEDIA_VIDEO) ? JSJAC_JINGLE_MEDIA_VIDEO
: JSJAC_JINGLE_MEDIA_AUDIO;
self._session = new JSJaCJingle.session(JSJAC_JINGLE_SESSION_MUJI, args);
self._caller_xid = Common.bareXID(args_invite.from);
Console.debug('Receive Muji call: ' + room);
} else {
self._session = new JSJaCJingle.session(JSJAC_JINGLE_SESSION_MUJI, args);
self._caller_xid = Common.getXID();
self._session.join();
Console.debug('Create Muji call: ' + room);
}
Console.debug('Join Muji conference: ' + room);
status = true;
} catch(e) {
Console.error('Muji._new', e);
} finally {
return status;
}
};
/**
* Updates the participants counter value
* @private
* @param {number} count_participants
* @return {undefined}
*/
self._update_count_participants = function(count_participants) {
try {
count_participants = (count_participants || 0);
var participants_counter_sel = $('#muji .chatroom_participants .participants_counter');
if(count_participants === 1) {
participants_counter_sel.text(
Common.printf(Common._e("%s participant"), count_participants)
);
} else {
participants_counter_sel.text(
Common.printf(Common._e("%s participants"), count_participants)
);
}
} catch(e) {
Console.error('Muji._update_count_participants', e);
}
};
/**
* Updates the participants invite tool
* @private
* @return {undefined}
*/
self._update_invite_participants = function() {
try {
var chatroom_participants_sel = $('#muji .chatroom_participants');
var participants_invite_sel = chatroom_participants_sel.find('.participants_invite');
var participants_invite_box_sel = chatroom_participants_sel.find('.participants_invite_box');
if(self.is_full()) {
if(participants_invite_box_sel.is(':visible')) {
participants_invite_box_sel.stop(true);
participants_invite_sel.click();
}
participants_invite_sel.filter(':visible').hide();
} else {
participants_invite_sel.filter(':hidden').show();
}
} catch(e) {
Console.error('Muji._update_invite_participants', e);
}
};
/**
* Resets the participants invite filter
* @private
* @return {undefined}
*/
self._reset_participants_invite_filter = function() {
try {
// Selectors
var chatroom_sel = $('#muji .chatroom');
var invite_form_sel = chatroom_sel.find('form.participants_invite_form');
var invite_search_sel = chatroom_sel.find('.participants_invite_search');
// Apply
invite_form_sel.find('input.invite_xid').val('');
invite_search_sel.empty();
} catch(e) {
Console.error('Muji._reset_participants_invite_filter', e);
}
};
/**
* Engages the participants invite filter
* @private
* @param {string} value
* @return {undefined}
*/
self._engage_participants_invite_filter = function(value) {
try {
// Selectors
var chatroom_sel = $('#muji .chatroom');
var invite_input_sel = chatroom_sel.find('form.participants_invite_form input.invite_xid');
var invite_search_sel = chatroom_sel.find('.participants_invite_search');
// Reset UI
invite_search_sel.empty();
// Proceed search
var results_arr = Search.processBuddy(value);
var results_html = '';
var bold_regex = new RegExp('((^)|( ))' + value, 'gi');
// Exclude already selected buddies
var exclude_obj = self._list_participants_invite_list();
if(results_arr && results_arr.length) {
var i, j,
cur_xid, cur_full_xid, cur_hash, cur_support, cur_name, cur_title,
cur_name_bolded, cur_support_class;
for(i = 0; i < results_arr.length; i++) {
// Generate result data
cur_xid = results_arr[i];
if(exclude_obj[cur_xid] !== 1) {
cur_hash = hex_md5(cur_xid);
cur_name = Name.getBuddy(cur_xid);
// Get target's full XID
cur_full_xid = Caps.getFeatureResource(cur_xid, NS_MUJI);
cur_support = null;
if(cur_full_xid) {
if(Caps.getFeatureResource(cur_xid, NS_JINGLE_APPS_RTP_VIDEO)) {
cur_support = 'video';
} else {
cur_support = 'audio';
}
}
// Generate a hint title & a class
if(cur_support) {
cur_title = Common.printf(Common._e("%s is able to receive group calls."), cur_name);
cur_support_class = 'participant_search_has_' + cur_support;
} else {
cur_title = Common.printf(Common._e("%s may not support group calls."), cur_name);
cur_support_class = 'participant_search_unsupported';
}
// Bold matches in name
cur_name_bolded = cur_name.htmlEnc().replace(bold_regex, '<b>$&</b>');
// Generate result HTML
2014-11-25 23:42:38 +01:00
results_html +=
'<a class="participant_search_one ' + cur_support_class + ' ' + cur_hash + '" href="#" title="' + Common.encodeQuotes(cur_title) + '" data-xid="' + Common.encodeQuotes(cur_full_xid || cur_xid) + '" data-support="' + Common.encodeQuotes(cur_support) + '">' +
'<span class="avatar-container">' +
'<img class="avatar" src="' + './images/others/default-avatar.png' + '" alt="" />' +
'</span>' +
'<span class="details">' +
'<span class="name">' + cur_name_bolded + '</span>' +
'<span class="feature call-images"></span>' +
'</span>' +
2014-11-25 20:12:58 +01:00
'</a>';
}
}
// Add to DOM
invite_search_sel.append(results_html);
var search_one_sel = invite_search_sel.find('a.participant_search_one');
search_one_sel.filter(':first').addClass('hover');
// Apply avatars
for(j = 0; j < results_arr.length; j++) {
Avatar.get(results_arr[j], 'cache', 'true', 'forget');
}
// Apply events
search_one_sel.click(function() {
var this_sel = $(this);
self._add_participants_invite_list(
this_sel.attr('data-xid'),
this_sel.text(),
this_sel.attr('data-support')
);
self._reset_participants_invite_filter();
invite_input_sel.focus();
});
search_one_sel.hover(function() {
search_one_sel.filter('.hover').removeClass('hover');
$(this).addClass('hover');
}, function() {
$(this).removeClass('hover');
});
}
} catch(e) {
Console.error('Muji._engage_participants_invite_filter', e);
}
};
/**
* Sends participant actual Muji invite
* @private
* @param {string|object} xid
* @return {undefined}
*/
self._send_participants_invite_list = function(xid) {
try {
if(self.in_call()) {
self._session.invite(xid);
}
} catch(e) {
Console.error('Muji._send_participants_invite_list', e);
}
};
/**
* Adds a participant to the invite list
* @private
* @param {string} xid
* @param {string} name
* @param {string} support
* @return {undefined}
*/
self._add_participants_invite_list = function(xid, name, support) {
try {
// Selectors
var chatroom_sel = $('#muji .chatroom');
var invite_form_sel = chatroom_sel.find('form.participants_invite_form');
var invite_list_sel = chatroom_sel.find('.participants_invite_list');
var pre_invite_one_sel = invite_list_sel.find('.invite_one').filter(function() {
return (xid === $(this).attr('data-xid')) && true;
});
if(pre_invite_one_sel.size()) {
throw 'Already existing for: ' + xid;
}
var title;
var _class = [];
switch(support) {
case 'audio':
case 'video':
title = Common.printf(Common._e("%s is able to receive group calls."), name); break;
default:
title = Common.printf(Common._e("%s may not support group calls."), name);
_class.push('invite_unsupported');
}
// Append element
var invite_one_sel = $('<span class="invite_one ' + _class.join(' ') + '" data-xid="' + Common.encodeQuotes(xid) + '" title="' + title + '">' + name.htmlEnc() + '<a class="invite_one_remove call-images" href="#"></a></span>');
invite_one_sel.appendTo(invite_list_sel);
// Events
invite_one_sel.find('a.invite_one_remove').click(function() {
self._remove_participants_invite_list(invite_one_sel);
});
if(invite_list_sel.find('.invite_one').size() >= 1) {
invite_form_sel.find('.invite_validate').show();
invite_list_sel.filter(':hidden').show();
}
} catch(e) {
Console.error('Muji._add_participants_invite_list', e);
}
};
/**
* Removes a participant from the invite list
* @private
* @param {object} participant_sel
* @return {undefined}
*/
self._remove_participants_invite_list = function(participant_sel) {
try {
// Selectors
var chatroom_sel = $('#muji .chatroom');
var invite_form_sel = chatroom_sel.find('form.participants_invite_form');
var invite_list_sel = chatroom_sel.find('.participants_invite_list');
participant_sel.remove();
if(invite_list_sel.find('.invite_one').size() === 0) {
invite_form_sel.find('.invite_validate').hide();
invite_list_sel.filter(':visible').hide();
}
invite_form_sel.find('input.invite_xid').focus();
} catch(e) {
Console.error('Muji._remove_participants_invite_list', e);
}
};
/**
* Hovers either the next or previous participant
* @private
* @param {string} direction
* @return {undefined}
*/
self._hover_participants_invite_list = function(direction) {
try {
// Up/down: navigate through results
var chatroom_sel = $('#muji .chatroom');
var participants_invite_search_sel = chatroom_sel.find('.participants_invite_search');
var participant_search_one_sel = chatroom_sel.find('.participant_search_one');
if(participant_search_one_sel.size()) {
var hover_index = participant_search_one_sel.index($('.hover'));
2014-11-25 23:42:38 +01:00
2014-11-25 20:12:58 +01:00
// Up (decrement) or down (increment)?
if(direction === 'up') {
hover_index--;
} else {
hover_index++;
}
2014-11-25 23:42:38 +01:00
2014-11-25 20:12:58 +01:00
if(!hover_index) {
hover_index = 0;
}
2014-11-25 23:42:38 +01:00
2014-11-25 20:12:58 +01:00
// Nobody before/after?
if(participant_search_one_sel.eq(hover_index).size() === 0) {
if(direction === 'up') {
hover_index = participant_search_one_sel.filter(':last').index();
} else {
hover_index = 0;
}
}
2014-11-25 23:42:38 +01:00
2014-11-25 20:12:58 +01:00
// Hover the previous/next user
participant_search_one_sel.removeClass('hover');
participant_search_one_sel.eq(hover_index).addClass('hover');
// Scroll to the hovered user (if out of limits)
participants_invite_search_sel.scrollTo(
participant_search_one_sel.filter('.hover:first'), 0, { margin: true }
);
}
} catch(e) {
Console.error('Muji._hover_participants_invite_list', e);
}
};
/**
* Lists the participants in the invite list
* @private
* @return {object}
*/
self._list_participants_invite_list = function() {
var participants_obj = {};
try {
$('#muji .chatroom .participants_invite_list .invite_one').each(function() {
participants_obj[$(this).attr('data-xid')] = 1;
});
} catch(e) {
Console.error('Muji._list_participants_invite_list', e);
} finally {
return participants_obj;
}
};
/**
* Adapts the Muji view to the window size
* @private
* @return {undefined}
*/
self._adapt = function() {
try {
if(self.in_call() && Common.exists('#muji')) {
Call.adapt_local(
$('#muji .local_video')
);
Call.adapt_remote(
$('#muji .videoroom')
);
}
} catch(e) {
Console.error('Muji._adapt', e);
}
};
/**
* Scrolls down to last received message
* @private
* @return {undefined}
*/
self._message_scroll = function() {
try {
var chatroom_view_sel = $('#muji .chatroom .chatroom_view');
// Scroll down to message
if(chatroom_view_sel.size() && chatroom_view_sel.is(':visible')) {
chatroom_view_sel[0].scrollTop = chatroom_view_sel[0].scrollHeight;
}
} catch(e) {
Console.error('Muji._message_scroll', e);
}
};
/**
* Notifies that a new message has been received
* @private
* @return {undefined}
*/
self._message_notify = function() {
try {
// Selectors
var tools_call_sel = $('#top-content .tools.call');
var notify_sel = tools_call_sel.find('.notify');
if(!notify_sel.size()) {
notify_sel = $(
'<div class="notify one-counter" data-counter="0">0</div>'
);
notify_sel.appendTo(tools_call_sel);
}
// Count & update
var count_notifications = parseInt((notify_sel.attr('data-counter') || 0), 10);
count_notifications++;
notify_sel.text(count_notifications);
notify_sel.attr('data-counter', count_notifications);
// Update general interface
Interface.updateTitle();
} catch(e) {
Console.error('Muji._message_notify', e);
}
};
/**
* Removes displayed message notifications
* @private
* @return {undefined}
*/
self._message_unnotify = function() {
try {
$('#top-content .tools.call .notify').remove();
// Update general interface
Interface.updateTitle();
} catch(e) {
Console.error('Muji._message_unnotify', e);
}
};
/**
* Receive a Muji call
* @public
* @param {object} args
* @param {object} stanza
* @return {boolean}
*/
self.receive = function(args, stanza) {
try {
if(!Call.is_ongoing()) {
2014-11-25 23:42:38 +01:00
// Outdated invite?
var invite_delay = DateUtils.readMessageDelay(stanza.getNode(), true);
var date_now = DateUtils.getTimeStamp();
if(invite_delay &&
(date_now - DateUtils.extractStamp(invite_delay)) >= self.INVITE_MAX_DELAY) {
Console.warn('Muji.receive', 'Discarded outdated invite from: ' + Common.getStanzaFrom(stanza));
return;
}
2014-11-25 20:12:58 +01:00
// Create call session
self._new(
args.jid,
(args.media || JSJAC_JINGLE_MEDIA_VIDEO),
stanza,
args
);
// Notify user
Call.notify(
JSJAC_JINGLE_SESSION_MUJI,
args.jid,
('call_' + (args.media || 'video')),
args.media,
Common.bareXID(args.from)
);
2014-11-25 23:42:38 +01:00
2014-11-25 20:12:58 +01:00
Audio.play('incoming-call', true);
}
} catch(e) {
Console.error('Muji.receive', e);
} finally {
return false;
}
};
/**
* Start a Muji call
* @public
* @param {string} room
* @param {string} mode
* @return {boolean}
*/
self.start = function(room, mode) {
try {
if(!Call.is_ongoing()) {
self._new(room, mode);
}
} catch(e) {
Console.error('Muji.start', e);
} finally {
return false;
}
};
/**
* Reset current Muji call
* @public
* @return {boolean}
*/
self._reset = function() {
try {
// Trash interface
Call.stop_counter();
Call.stop_session();
self._destroy_interface();
$('body').removeClass('in_muji_call');
// Clean notifications
self._message_unnotify();
// Hack: stop audio in case it is still ringing
Audio.stop('incoming-call');
Audio.stop('outgoing-call');
} catch(e) {
Console.error('Muji._reset', e);
} finally {
return false;
}
};
/**
* Stops current Muji call
* @public
2014-11-25 23:42:38 +01:00
* @param {boolean} abort
2014-11-25 20:12:58 +01:00
* @return {boolean}
*/
2014-11-25 23:42:38 +01:00
self.stop = function(abort) {
2014-11-25 20:12:58 +01:00
try {
// Reset interface
self._reset();
// Stop Muji session
if(self._session !== null) {
2014-11-25 23:42:38 +01:00
if(abort === true) {
self._session.abort();
self._session.get_session_leave_error(self._session, null);
} else {
self._session.leave();
}
2014-11-25 20:12:58 +01:00
Console.debug('Stopping current Muji call...');
} else {
Console.warn('No Muji call to be terminated!');
}
} catch(e) {
Console.error('Muji.stop', e);
} finally {
return false;
}
};
/**
* Mutes current Muji call
* @public
* @return {undefined}
*/
self.mute = function() {
try {
Call.mute(
$('#muji .videoroom .topbar .controls a')
);
} catch(e) {
Console.error('Muji.mute', e);
}
};
/**
* Unmutes current Muji call
* @public
* @return {undefined}
*/
self.unmute = function() {
try {
Call.unmute(
$('#muji .videoroom .topbar .controls a')
);
} catch(e) {
Console.error('Muji.mute', e);
}
};
/**
* Checks whether room given is Muji room or not
* @public
* @param {string} room
* @return {boolean}
*/
self.is_room = function(room) {
is_room = false;
try {
if(self.in_call() && self._session.get_to()) {
is_room = (room === self._session.get_to());
}
} catch(e) {
Console.error('Muji.is_room', e);
} finally {
return is_room;
}
};
/**
* Checks whether room is full or not (over-capacity)
* @public
* @return {boolean}
*/
self.is_full = function() {
is_full = false;
try {
if($('#muji .chatroom_participants .participants_full').is(':visible')) {
is_full = true;
}
} catch(e) {
Console.error('Muji.is_full', e);
} finally {
return is_full;
}
};
/**
* Checks whether user is in call or not
* @public
* @return {boolean}
*/
self.in_call = function() {
in_call = false;
try {
2014-11-25 23:42:38 +01:00
if(self._session &&
(self._session.get_status() === JSJAC_JINGLE_MUJI_STATUS_PREPARING ||
self._session.get_status() === JSJAC_JINGLE_MUJI_STATUS_PREPARED ||
self._session.get_status() === JSJAC_JINGLE_MUJI_STATUS_INITIATING ||
2014-11-25 20:12:58 +01:00
self._session.get_status() === JSJAC_JINGLE_MUJI_STATUS_INITIATED ||
self._session.get_status() === JSJAC_JINGLE_MUJI_STATUS_LEAVING)) {
in_call = true;
}
} catch(e) {
Console.error('Muji.in_call', e);
} finally {
return in_call;
}
};
/**
* Checks if the given call SID is the same as the current call's one
* @public
* @param {object}
* @return {boolean}
*/
self.is_same_sid = function(muji) {
try {
return Call.is_same_sid(self._session, muji);
} catch(e) {
Console.error('Muji.is_same_sid', e);
}
};
/**
* Returns if current Muji call is audio
* @public
* @return {boolean}
*/
self.is_audio = function() {
try {
return Call.is_audio(self._session);
} catch(e) {
Console.error('Muji.is_audio', e);
}
};
/**
* Returns if current Muji call is video
* @public
* @return {boolean}
*/
self.is_video = function() {
try {
return Call.is_video(self._session);
} catch(e) {
Console.error('Muji.is_video', e);
}
};
/**
* Returns the caller XID
* @public
* @return {string}
*/
self.get_caller_xid = function() {
try {
return self._caller_xid || Common.getXID();
} catch(e) {
Console.error('Muji.get_caller_xid', e);
}
};
/**
* Get the notification map
* @private
* @return {object}
*/
self._notify_map = function() {
try {
return {
'call_audio': {
'text': Common._e("Incoming group call"),
'buttons': {
'accept': {
'text': Common._e("Accept"),
'color': 'green',
'cb': function(xid, mode) {
self._session.join();
Audio.stop('incoming-call');
}
},
'decline': {
'text': Common._e("Decline"),
'color': 'red',
'cb': function(xid, mode) {
2014-11-25 23:42:38 +01:00
self.stop(true);
2014-11-25 20:12:58 +01:00
Audio.stop('incoming-call');
}
}
}
},
'call_video': {
'text': Common._e("Incoming group call"),
'buttons': {
'accept': {
'text': Common._e("Accept"),
'color': 'green',
'cb': function(xid, mode) {
self._session.join();
Audio.stop('incoming-call');
}
},
'decline': {
'text': Common._e("Decline"),
'color': 'red',
'cb': function(xid, mode) {
2014-11-25 23:42:38 +01:00
self.stop(true);
2014-11-25 20:12:58 +01:00
Audio.stop('incoming-call');
}
}
}
},
'preparing': {
'text': Common._e("Preparing group call..."),
'buttons': {
'cancel': {
'text': Common._e("Cancel"),
'color': 'red',
'cb': function(xid, mode) {
2014-11-25 23:42:38 +01:00
self.stop(true);
2014-11-25 20:12:58 +01:00
}
}
}
},
'waiting': {
'text': Common._e("Preparing group call..."),
'buttons': {
'cancel': {
'text': Common._e("Cancel"),
'color': 'red',
'cb': function(xid, mode) {
self._session.leave();
}
}
}
},
'connecting': {
'text': Common._e("Connecting to group call..."),
'buttons': {
'cancel': {
'text': Common._e("Cancel"),
'color': 'red',
'cb': function(xid, mode) {
self._session.leave();
}
}
}
},
'error': {
'text': Common._e("Group call error"),
'buttons': {
'retry': {
'text': Common._e("Retry"),
'color': 'blue',
'cb': function(xid, mode) {
self.start(xid, mode);
}
},
'cancel': {
'text': Common._e("Cancel"),
'color': 'red',
'cb': function(xid, mode) {
self._reset();
}
}
}
},
'ending': {
'text': Common._e("Ending group call...")
},
'ended': {
'text': Common._e("Group call ended"),
'buttons': {
'okay': {
'text': Common._e("Okay"),
'color': 'blue',
'cb': function(xid, mode) {
self._reset();
}
}
}
}
};
} catch(e) {
Console.error('Muji._notify_map', e);
return {};
}
};
/**
* Create the Muji interface
* @public
* @param {string} room
* @param {string} mode
* @return {object}
*/
self._create_interface = function(room, mode) {
try {
// Jingle interface already exists?
if(Common.exists('#muji')) {
throw 'Muji interface already exist!';
}
// Local poster
var local_poster = './images/placeholders/jingle_video_local.png';
if(mode === 'audio') {
local_poster = './images/placeholders/jingle_audio_local.png';
}
// Create DOM
$('body').append(
2014-11-25 23:42:38 +01:00
'<div id="muji" class="videochat_box lock removable ' + hex_md5(room) + '" data-room="' + Common.encodeQuotes(room) + '" data-mode="' + Common.encodeQuotes(mode) + '">' +
'<div class="videochat_items">' +
'<div class="videoroom">' +
'<div class="topbar">' +
'<div class="controls">' +
'<a href="#" class="leave control-button" data-type="leave"><span class="icon call-images"></span>' + Common._e("Leave") + '</a>' +
'<a href="#" class="mute control-button" data-type="mute"><span class="icon call-images"></span>' + Common._e("Mute") + '</a>' +
'<a href="#" class="unmute control-button" data-type="unmute"><span class="icon call-images"></span>' + Common._e("Unmute") + '</a>' +
'</div>' +
'<div class="elapsed">00:00:00</div>' +
'<div class="actions">' +
'<a href="#" class="close action-button call-images" data-type="close"></a>' +
'</div>' +
'</div>' +
'<div class="local_video">' +
'<video src="" alt="" poster="' + local_poster + '"></video>' +
'</div>' +
'<div class="remote_container">' +
'<div class="remote_video_shaper remote_video"></div>' +
'<div class="remote_video_shaper remote_video"></div>' +
'<div class="remote_video_shaper remote_video"></div>' +
'<div class="remote_video_shaper remote_video"></div>' +
'<div class="remote_video_shaper remote_video"></div>' +
'<div class="remote_video_shaper remote_video"></div>' +
'</div>' +
'<div class="empty_message">' +
'<span class="text">' + Common._e("Nobody there. Invite some people!") + '</span>' +
'</div>' +
'</div>' +
'<div class="chatroom">' +
'<div class="chatroom_participants">' +
'<div class="participants_default_view">' +
'<div class="participants_default_details">' +
'<span class="participants_counter">' + Common.printf(Common._e("%s participants"), 0) + '</span>' +
'<span class="participants_full">' + Common._e("(full)") + '</span>' +
'</div>' +
'<a class="participants_invite call-images" href="#" title="' + Common._e("Invite people...") + '"></a>' +
'</div>' +
'<div class="participants_invite_box">' +
'<div class="participants_invite_list"></div>' +
'<form class="participants_invite_form" action="#" method="post">' +
'<div class="invite_input_container">' +
'<input class="invite_xid input-reset" name="xid" type="text" placeholder="' + Common._e("Enter people names...") + '" autocomplete="off" />' +
'</div>' +
'<a class="invite_validate" href="#">' +
'<span class="invite_validate_icon call-images"></span>' +
'</a>' +
'</form>' +
'<div class="participants_invite_search"></div>' +
'</div>' +
'</div>' +
'<div class="chatroom_view"></div>' +
'<form class="chatroom_form" action="#" method="post">' +
'<span class="message_icon call-images"></span>' +
'<span class="message_separator"></span>' +
'<div class="message_input_container">' +
'<input class="message_input input-reset" name="message" type="text" placeholder="' + Common._e("Send a message...") + '" autocomplete="off" />' +
'</div>' +
'</form>' +
'</div>' +
'</div>' +
2014-11-25 20:12:58 +01:00
'</div>'
);
// Apply events
self._events_interface();
// Apply user avatar
Avatar.get(xid, 'cache', 'true', 'forget');
} catch(e) {
Console.error('Muji._create_interface', e);
} finally {
return $('#muji');
}
};
/**
* Destroy the Muji interface
* @public
* @return {undefined}
*/
self._destroy_interface = function() {
try {
Call.destroy_interface(
$('#muji')
);
} catch(e) {
Console.error('Muji._destroy_interface', e);
}
};
/**
* Show the Muji interface
* @private
* @return {boolean}
*/
self._show_interface = function() {
try {
Call.show_interface(
self,
$('#muji'),
$('#muji .videoroom')
);
self._message_scroll();
self._message_unnotify();
} catch(e) {
Console.error('Muji._show_interface', e);
} finally {
return false;
}
};
/**
* Hide the Muji interface
* @private
* @return {boolean}
*/
self._hide_interface = function() {
try {
Call.hide_interface(
$('#muji'),
$('#muji .videoroom')
);
} catch(e) {
Console.error('Muji._hide_interface', e);
} finally {
return false;
}
};
/**
* Attaches interface events
* @private
* @return {boolean}
*/
self._events_interface = function() {
try {
// Common selectors
var muji_chatroom = $('#muji .chatroom');
var chatroom_form = muji_chatroom.find('form.chatroom_form');
var chatroom_participants = muji_chatroom.find('.chatroom_participants');
var participants_invite = chatroom_participants.find('.participants_default_view .participants_invite');
var participants_invite_box = chatroom_participants.find('.participants_invite_box');
var participants_invite_list = participants_invite_box.find('.participants_invite_list');
var participants_invite_form = participants_invite_box.find('.participants_invite_form');
var participants_invite_input = participants_invite_form.find('input[name="xid"]');
var participants_invite_validate = participants_invite_form.find('.invite_validate');
var participants_invite_search = participants_invite_box.find('.participants_invite_search');
// Apply events
Call.events_interface(
self,
$('#muji'),
$('#muji .videoroom')
);
// People invite event
participants_invite.click(function() {
try {
if(!participants_invite_box.is(':animated')) {
if(participants_invite_box.is(':hidden')) {
participants_invite_box.stop(true).slideDown(250, function() {
participants_invite_input.focus();
});
} else {
participants_invite_input.blur();
participants_invite_box.stop(true).slideUp(250, function() {
// Reset everything
participants_invite_list.empty().hide();
participants_invite_validate.hide();
participants_invite_input.val('');
self._reset_participants_invite_filter();
});
}
}
} catch(_e) {
Console.error('Muji._show_interface[event]', _e);
} finally {
return false;
}
});
// Invite input key events
participants_invite_input.keydown(function(e) {
try {
if(e.keyCode == 9) {
self._hover_participants_invite_list('down');
return false;
}
} catch(_e) {
Console.error('Muji._show_interface[event]', _e);
}
});
participants_invite_input.keyup(function(e) {
try {
var this_sel = $(this);
if(e.keyCode == 27) {
// Escape: close interface
if(!this_sel.val().trim()) {
participants_invite.click();
} else {
self._reset_participants_invite_filter();
}
return false;
} else if(e.keyCode == 9) {
// Tabulate: skip there (see keydown above)
return false;
} else if(e.keyCode == 38 || e.keyCode == 40) {
var direction = (e.keyCode == 38) ? 'up' : 'down';
self._hover_participants_invite_list(direction);
return false;
} else {
// Other keys: assume something has been typed
self._engage_participants_invite_filter(
this_sel.val()
);
}
} catch(_e) {
Console.error('Muji._show_interface[event]', _e);
}
});
// Input auto-focus
chatroom_form.click(function() {
chatroom_form.find('input[name="message"]').focus();
});
// Invite form send event
participants_invite_form.submit(function() {
try {
if(participants_invite_search.find('.participant_search_one.hover').size()) {
// Add the hovered user
var participant_search_one_hover_sel = participants_invite_search.find('.participant_search_one.hover:first');
if(participant_search_one_hover_sel.size() >= 1) {
participant_search_one_hover_sel.click();
return false;
}
} else {
var invite_arr = Object.keys(self._list_participants_invite_list());
if(invite_arr && invite_arr.length) {
self._send_participants_invite_list(invite_arr);
}
participants_invite.click();
}
} catch(_e) {
Console.error('Muji._show_interface[event]', _e);
} finally {
return false;
}
});
// Invite form validate event
2014-11-25 23:42:38 +01:00
participants_invite_validate.click(function() {
2014-11-25 20:12:58 +01:00
try {
participants_invite_form.submit();
} catch(_e) {
Console.error('Muji._show_interface[event]', _e);
} finally {
return false;
}
});
// Message send event
chatroom_form.submit(function() {
try {
if(self._session === null) {
throw 'Muji session unavailable';
}
var input_sel = $(this).find('input[name="message"]');
var body = input_sel.val();
if(body) {
self._session.send_message(body);
input_sel.val('');
}
} catch(_e) {
Console.error('Muji._show_interface[event]', _e);
} finally {
return false;
}
});
} catch(e) {
Console.error('Muji._events_interface', e);
} finally {
return false;
}
};
/**
* Plugin launcher
* @public
* @return {undefined}
*/
self.launch = function() {
try {
$(window).resize(self._adapt());
} catch(e) {
Console.error('Muji.launch', e);
}
2014-11-25 23:42:38 +01:00
2014-11-25 20:12:58 +01:00
};
/**
* Return class scope
*/
return self;
})();
Muji.launch();