mirror of
https://github.com/YunoHost-Apps/jappix_ynh.git
synced 2024-09-03 19:26:19 +02:00
705 lines
No EOL
20 KiB
JavaScript
705 lines
No EOL
20 KiB
JavaScript
/*
|
|
|
|
Jappix - An open social platform
|
|
These are the interface JS scripts for Jappix
|
|
|
|
-------------------------------------------------
|
|
|
|
License: AGPL
|
|
Author: Valérian Saliou
|
|
|
|
*/
|
|
|
|
// Bundle
|
|
var Interface = (function () {
|
|
|
|
/**
|
|
* Alias of this
|
|
* @private
|
|
*/
|
|
var self = {};
|
|
|
|
|
|
/* Variables */
|
|
self.chat_focus_hash = null;
|
|
|
|
|
|
/**
|
|
* Changes the title of the document
|
|
* @public
|
|
* @param {string} new_title
|
|
* @return {undefined}
|
|
*/
|
|
self.title = function(title_type) {
|
|
|
|
try {
|
|
// Anonymous mode?
|
|
var head_name = Name.get();
|
|
|
|
if(Utils.isAnonymous()) {
|
|
head_name = ANONYMOUS_ROOM + ' (' + Common._e("anonymous mode") + ')';
|
|
}
|
|
|
|
// We change the title to give essential informations
|
|
switch(title_type) {
|
|
case 'home':
|
|
document.title = SERVICE_NAME + ' • ' + SERVICE_DESC;
|
|
break;
|
|
|
|
case 'talk':
|
|
document.title = SERVICE_NAME + ' • ' + head_name;
|
|
break;
|
|
|
|
case 'new':
|
|
document.title = '[' + self.pendingEvents() + '] ' + SERVICE_NAME + ' • ' + head_name;
|
|
break;
|
|
|
|
case 'wait':
|
|
document.title = SERVICE_NAME + ' • ' + Common._e("Please wait...");
|
|
break;
|
|
}
|
|
} catch(e) {
|
|
Console.error('Interface.title', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Creates a general-wait item
|
|
* @public
|
|
* @return {boolean}
|
|
*/
|
|
self.showGeneralWait = function() {
|
|
|
|
try {
|
|
// Item exists?
|
|
if(Common.exists('#general-wait'))
|
|
return false;
|
|
|
|
// Generate the HTML code
|
|
var html =
|
|
'<div id="general-wait" class="removable">' +
|
|
'<div class="general-wait-content wait-big"></div>' +
|
|
'</div>';
|
|
|
|
// Append the HTML code
|
|
$('body').append(html);
|
|
|
|
return true;
|
|
} catch(e) {
|
|
Console.error('Interface.showGeneralWait', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Removes the general-wait item
|
|
* @public
|
|
* @return {undefined}
|
|
*/
|
|
self.removeGeneralWait = function() {
|
|
|
|
try {
|
|
$('#general-wait').remove();
|
|
} catch(e) {
|
|
Console.error('Interface.removeGeneralWait', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Generates a file upload valid form content
|
|
* @public
|
|
* @return {undefined}
|
|
*/
|
|
self.generateFileShare = function() {
|
|
|
|
try {
|
|
return '<input type="hidden" name="MAX_FILE_SIZE" value="' + Common.encodeQuotes(JAPPIX_MAX_FILE_SIZE) + '">' +
|
|
'<input type="hidden" name="user" value="' + Common.encodeQuotes(Common.getXID()) + '" />' +
|
|
'<input type="hidden" name="location" value="' + Common.encodeQuotes(Utils.generateURL(JAPPIX_LOCATION)) + '" />' +
|
|
'<input type="hidden" name="id" value="' + (new Date()).getTime() + '" />' +
|
|
'<input type="file" name="file" required="" />' +
|
|
'<input type="submit" value="' + Common._e("Send") + '" />';
|
|
} catch(e) {
|
|
Console.error('Interface.generateFileShare', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Switches to the given chan
|
|
* @public
|
|
* @param {string} id
|
|
* @return {boolean}
|
|
*/
|
|
self.switchChan = function(id) {
|
|
|
|
try {
|
|
if(Common.exists('#' + id)) {
|
|
// We show the page-engine content
|
|
$('.page-engine-chan').hide();
|
|
$('#' + id).show();
|
|
|
|
// We edit the tab switcher
|
|
$('#page-switch .switcher').removeClass('activechan').addClass('chan');
|
|
$('#page-switch .' + id).addClass('activechan').removeClass('chan');
|
|
|
|
// Scroll down to the last message
|
|
if(id != 'channel') {
|
|
self.autoScroll(id);
|
|
}
|
|
|
|
// Manage input focus
|
|
self.inputFocus();
|
|
}
|
|
} catch(e) {
|
|
Console.error('Interface.switchChan', e);
|
|
} finally {
|
|
return false;
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Loads the complete chat switcher
|
|
* @public
|
|
* @return {undefined}
|
|
*/
|
|
self.loadChatSwitch = function() {
|
|
|
|
try {
|
|
// Path
|
|
var more_content = '#page-switch .more-content';
|
|
|
|
// Yet displayed?
|
|
if(Common.exists(more_content))
|
|
return Bubble.close();
|
|
|
|
// Add the bubble
|
|
Bubble.show(more_content);
|
|
|
|
// Append the content
|
|
$('#page-switch .more').append(
|
|
'<div class="more-content bubble removable">' +
|
|
$('#page-switch .chans').html() +
|
|
'</div>'
|
|
);
|
|
} catch(e) {
|
|
Console.error('Interface.loadChatSwitch', e);
|
|
} finally {
|
|
return false;
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Loads the groupchat joiner
|
|
* @public
|
|
* @return {undefined}
|
|
*/
|
|
self.loadJoinGroupchat = function() {
|
|
|
|
try {
|
|
// Path
|
|
var join_content = '#page-switch .join-content';
|
|
var join_sel = $('#page-switch .join');
|
|
|
|
// Yet displayed?
|
|
if(Common.exists(join_content))
|
|
return Bubble.close();
|
|
|
|
// Add the bubble
|
|
Bubble.show(join_content);
|
|
|
|
// Append the content
|
|
join_sel.append(
|
|
'<div class="join-content bubble removable">' +
|
|
'<input type="text" class="join-groupchat-xid" required="" placeholder="' + Common._e("Groupchat name") + '" />' +
|
|
'</div>'
|
|
);
|
|
|
|
var input_sel = join_sel.find('input.join-groupchat-xid');
|
|
|
|
input_sel.keyup(function(e) {
|
|
// Enter: continue
|
|
if(e.keyCode == 13) {
|
|
var this_sel = $(this);
|
|
var xid = $.trim(this_sel.val());
|
|
|
|
if(xid) {
|
|
// Generate a correct XID
|
|
xid = Common.generateXID(xid, 'groupchat');
|
|
|
|
Bubble.close();
|
|
Chat.checkCreate(xid, 'groupchat');
|
|
} else {
|
|
this_sel.addClass('please-complete');
|
|
}
|
|
|
|
return false;
|
|
}
|
|
});
|
|
|
|
$(document).oneTime(10, function() {
|
|
input_sel.focus();
|
|
});
|
|
} catch(e) {
|
|
Console.error('Interface.loadJoinGroupchat', e);
|
|
} finally {
|
|
return false;
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Puts the selected smiley in the good page-engine input
|
|
* @public
|
|
* @param {string} smiley
|
|
* @param {string} hash
|
|
* @return {boolean}
|
|
*/
|
|
self.insertSmiley = function(smiley, hash) {
|
|
|
|
try {
|
|
// We define the variables
|
|
var selector = $('#' + hash + ' .message-area');
|
|
var oValue = selector.val();
|
|
|
|
// Any old value?
|
|
if(oValue && !oValue.match(/^(.+)(\s)+$/)) {
|
|
oValue += ' ';
|
|
}
|
|
|
|
var nValue = oValue + smiley + ' ';
|
|
|
|
// Put the new value and focus on it
|
|
$(document).oneTime(10, function() {
|
|
selector.val(nValue).focus();
|
|
});
|
|
} catch(e) {
|
|
Console.error('Interface.insertSmiley', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Deletes all the associated elements of the chat we want to remove
|
|
* @public
|
|
* @param {string} hash
|
|
* @return {undefined}
|
|
*/
|
|
self.deleteThisChat = function(hash) {
|
|
|
|
try {
|
|
$('#' + hash + ', #page-switch .' + hash).remove();
|
|
} catch(e) {
|
|
Console.error('Interface.deleteThisChat', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Closes the given chat
|
|
* @public
|
|
* @param {string} xid
|
|
* @param {string} hash
|
|
* @param {string} type
|
|
* @return {boolean}
|
|
*/
|
|
self.quitThisChat = function(xid, hash, type) {
|
|
|
|
try {
|
|
if(type == 'groupchat') {
|
|
// Send our unavailable presence
|
|
Presence.send(xid + '/' + Name.getMUCNick(hash), 'unavailable');
|
|
|
|
// Remove all presence database entries for this groupchat
|
|
var db_regex = new RegExp(('^' + Connection.desktop_hash + '_') + 'presence' + ('_(.+)'));
|
|
|
|
for(var i = 0; i < DataStore.storageDB.length; i++) {
|
|
// Get the pointer values
|
|
var current = DataStore.storageDB.key(i);
|
|
|
|
if(current.match(db_regex)) {
|
|
var cXID = RegExp.$1;
|
|
|
|
// If the pointer is on a presence from this groupchat
|
|
if(Common.bareXID(cXID) == xid) {
|
|
// Generate the hash for the current XID
|
|
var cHash = hex_md5(cXID);
|
|
|
|
// Disable the message textarea
|
|
$('#' + cHash + ' .message-area').attr('disabled', true);
|
|
|
|
// Remove the presence for this XID
|
|
DataStore.removeDB(Connection.desktop_hash, 'presence-stanza', cXID);
|
|
DataStore.removeDB(Connection.desktop_hash, 'presence-resources', cXID);
|
|
Presence.funnel(cXID, cHash);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
ChatState.send('gone', xid, hash);
|
|
}
|
|
|
|
// Clear MAM storage for this chat
|
|
if(xid in MAM.map_states) {
|
|
delete MAM.map_states[xid];
|
|
}
|
|
|
|
// Get the chat ID which is before
|
|
var previous = $('#' + hash).prev().attr('id');
|
|
|
|
// Remove the chat
|
|
self.deleteThisChat(hash);
|
|
|
|
// Reset the switcher
|
|
if(!Common.exists('#page-switch .switcher.activechan')) {
|
|
self.switchChan(previous);
|
|
}
|
|
|
|
// Reset the notifications
|
|
self.chanCleanNotify(hash);
|
|
} catch(e) {
|
|
Console.error('Interface.quitThisChat', e);
|
|
} finally {
|
|
return false;
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Generates the chat logs
|
|
* @public
|
|
* @param {string} xid
|
|
* @param {string} hash
|
|
* @return {boolean}
|
|
*/
|
|
self.generateChatLog = function(xid, hash) {
|
|
|
|
try {
|
|
// Get the main values
|
|
var path = '#' + hash + ' .';
|
|
var content = $(path + 'content').clone().contents();
|
|
var avatar = $(path + 'top .avatar-container:first').html();
|
|
var nick = $(path + 'top .bc-name').text();
|
|
var date = DateUtils.getXMPPTime('local');
|
|
var type = $('#' + hash).attr('data-type');
|
|
var direction = $('html').attr('dir') || 'ltr';
|
|
|
|
// Filter the content smileys
|
|
$(content).find('img.emoticon').each(function() {
|
|
$(this).replaceWith($(this).attr('alt'));
|
|
});
|
|
|
|
// Remove the useless attributes
|
|
$(content).removeAttr('data-type').removeAttr('data-stamp');
|
|
|
|
// Remove the content avatars
|
|
$(content).find('.avatar-container').remove();
|
|
|
|
// Remove the content click events
|
|
$(content).find('a').removeAttr('onclick');
|
|
|
|
// Extract the content HTML code
|
|
content = $(content).parent().html();
|
|
|
|
// No avatar?
|
|
if(!avatar || !avatar.match(/data:/))
|
|
avatar = 'none';
|
|
|
|
// POST the values to the server
|
|
$.post('./server/generate-chat.php', { 'content': content, 'xid': xid, 'nick': nick, 'avatar': avatar, 'date': date, 'type': type, 'direction': direction }, function(data) {
|
|
// Handled!
|
|
$(path + 'tooltip-waitlog').replaceWith('<a class="tooltip-actionlog" href="./server/download-chat.php?id=' + data + '" target="_blank">' + Common._e("Download file!") + '</a>');
|
|
});
|
|
} catch(e) {
|
|
Console.error('Interface.generateChatLog', e);
|
|
} finally {
|
|
return false;
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Notifies the user from a new incoming message
|
|
* @public
|
|
* @param {string} hash
|
|
* @param {string} type
|
|
* @return {undefined}
|
|
*/
|
|
self.messageNotify = function(hash, type) {
|
|
|
|
try {
|
|
// Initialize the vars
|
|
var chat_switch = '#page-switch .';
|
|
var tested = chat_switch + hash;
|
|
var active = $(tested).hasClass('activechan');
|
|
|
|
// We notify the user if he has not the focus on the chat
|
|
if(!active || !Common.isFocused() || (self.chat_focus_hash != hash)) {
|
|
if(!active) {
|
|
if(type == 'personal') {
|
|
$(tested + ', ' + chat_switch + 'more-button').addClass('chan-newmessage');
|
|
} else if(type == 'unread') {
|
|
$(tested).addClass('chan-unread');
|
|
}
|
|
}
|
|
|
|
// Count the number of pending messages
|
|
var pending = 1;
|
|
|
|
if(Common.exists('#' + hash + '[data-counter]')) {
|
|
pending = parseInt($('#' + hash).attr('data-counter')) + 1;
|
|
}
|
|
|
|
$('#' + hash).attr('data-counter', pending);
|
|
}
|
|
|
|
// Update the page title
|
|
self.updateTitle();
|
|
} catch(e) {
|
|
Console.error('Interface.messageNotify', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Returns the number of pending events
|
|
* @public
|
|
* @return {number}
|
|
*/
|
|
self.pendingEvents = function() {
|
|
|
|
try {
|
|
// Count the number of notifications
|
|
var number = 0;
|
|
|
|
$('.one-counter[data-counter]').each(function() {
|
|
number = number + parseInt($(this).attr('data-counter'));
|
|
});
|
|
|
|
return number;
|
|
} catch(e) {
|
|
Console.error('Interface.pendingEvents', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Updates the page title
|
|
* @public
|
|
* @return {undefined}
|
|
*/
|
|
self.updateTitle = function() {
|
|
|
|
try {
|
|
// Any pending events?
|
|
if(Common.exists('.one-counter[data-counter]'))
|
|
self.title('new');
|
|
else
|
|
self.title('talk');
|
|
} catch(e) {
|
|
Console.error('Interface.updateTitle', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Cleans the given chat notifications
|
|
* @public
|
|
* @param {string} hash
|
|
* @return {undefined}
|
|
*/
|
|
self.chanCleanNotify = function(hash) {
|
|
|
|
try {
|
|
// We remove the class that tell the user of a new message
|
|
var chat_switch = '#page-switch .';
|
|
$(chat_switch + hash).removeClass('chan-newmessage chan-unread');
|
|
|
|
// We reset the global notifications if no more unread messages
|
|
if(!$(chat_switch + 'chans .chan-newmessage').size())
|
|
$(chat_switch + 'more-button').removeClass('chan-newmessage');
|
|
|
|
// We reset the chat counter
|
|
$('#' + hash).removeAttr('data-counter');
|
|
|
|
// Update the page title
|
|
self.updateTitle();
|
|
} catch(e) {
|
|
Console.error('Interface.chanCleanNotify', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Scrolls to the last chat message
|
|
* @public
|
|
* @param {string} hash
|
|
* @return {undefined}
|
|
*/
|
|
self.autoScroll = function(hash) {
|
|
|
|
try {
|
|
// Avoid a JS error
|
|
if(Common.exists('#' + hash)) {
|
|
var container = document.getElementById('chat-content-' + hash);
|
|
|
|
// Scroll down!
|
|
container.scrollTop = container.scrollHeight;
|
|
}
|
|
} catch(e) {
|
|
Console.error('Interface.autoScroll', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Shows all the buddies in the roster
|
|
* @public
|
|
* @param {string} from
|
|
* @return {undefined}
|
|
*/
|
|
self.showAllBuddies = function(from) {
|
|
|
|
try {
|
|
// Put a marker
|
|
Roster.blist_all = true;
|
|
|
|
// We switch the two modes
|
|
$('.buddy-conf-more-display-unavailable').hide();
|
|
$('.buddy-conf-more-display-available').show();
|
|
|
|
// Security: reset all the groups toggle event
|
|
$('#roster .group-buddies').show();
|
|
$('#roster .group span').text('-');
|
|
|
|
// We show the disconnected buddies
|
|
$('.hidden-buddy').show();
|
|
|
|
// We show all the groups
|
|
$('#roster .one-group').show();
|
|
|
|
if(Search.search_filtered)
|
|
Search.funnelFilterBuddy();
|
|
|
|
// Store this in the options
|
|
if((from == 'roster') && Options.loaded()) {
|
|
DataStore.setDB(Connection.desktop_hash, 'options', 'roster-showall', '1');
|
|
Options.store();
|
|
}
|
|
} catch(e) {
|
|
Console.error('Interface.showAllBuddies', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Shows only the online buddies in the roster
|
|
* @public
|
|
* @param {string} from
|
|
* @return {undefined}
|
|
*/
|
|
self.showOnlineBuddies = function(from) {
|
|
|
|
try {
|
|
// Remove the marker
|
|
Roster.blist_all = false;
|
|
|
|
// We switch the two modes
|
|
$('.buddy-conf-more-display-available').hide();
|
|
$('.buddy-conf-more-display-unavailable').show();
|
|
|
|
// Security: reset all the groups toggle event
|
|
$('#roster .group-buddies').show();
|
|
$('#roster .group span').text('-');
|
|
|
|
// We hide the disconnected buddies
|
|
$('.hidden-buddy').hide();
|
|
|
|
// We check the groups to hide
|
|
Roster.updateGroups();
|
|
|
|
if(Search.search_filtered) {
|
|
Search.funnelFilterBuddy();
|
|
}
|
|
|
|
// Store this in the options
|
|
if((from == 'roster') && Options.loaded()) {
|
|
DataStore.setDB(Connection.desktop_hash, 'options', 'roster-showall', '0');
|
|
Options.store();
|
|
}
|
|
} catch(e) {
|
|
Console.error('Interface.showOnlineBuddies', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Focuses on the right input
|
|
* @public
|
|
* @return {undefined}
|
|
*/
|
|
self.inputFocus = function() {
|
|
|
|
try {
|
|
// No popup shown
|
|
if(!Common.exists('.popup')) {
|
|
$(document).oneTime(10, function() {
|
|
$('.focusable:visible:first').focus();
|
|
});
|
|
}
|
|
} catch(e) {
|
|
Console.error('Interface.inputFocus', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Plugin launcher
|
|
* @public
|
|
* @return {undefined}
|
|
*/
|
|
self.launch = function() {
|
|
|
|
try {
|
|
$(document).ready(function() {
|
|
// Focus on the first visible input
|
|
$(window).focus(self.inputFocus);
|
|
});
|
|
} catch(e) {
|
|
Console.error('Interface.launch', e);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Return class scope
|
|
*/
|
|
return self;
|
|
|
|
})();
|
|
|
|
Interface.launch(); |