jappixmini: include jappix source

This commit is contained in:
Leberwurscht 2012-04-18 01:12:24 +02:00
parent 61eb1f0d18
commit 302b2820d1
231 changed files with 96082 additions and 2 deletions

View file

@ -0,0 +1,85 @@
/*
Jappix - An open social platform
These are the Ad-Hoc JS scripts for Jappix
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 11/07/11
*/
// Opens the adhoc popup
function openAdHoc() {
// Popup HTML content
var html =
'<div class="top">' + _e("Commands") + '</div>' +
'<div class="content">' +
'<div class="adhoc-head"></div>' +
'<div class="results adhoc-results"></div>' +
'</div>' +
'<div class="bottom">' +
'<div class="wait wait-medium"></div>' +
'<a href="#" class="finish">' + _e("Close") + '</a>' +
'</div>';
// Create the popup
createPopup('adhoc', html);
// Associate the events
launchAdHoc();
return false;
}
// Quits the adhoc popup
function closeAdHoc() {
// Destroy the popup
destroyPopup('adhoc');
return false;
}
// Retrieves an entity adhoc command
function retrieveAdHoc(xid) {
// Open the popup
openAdHoc();
// Add a XID marker
$('#adhoc .adhoc-head').html('<b>' + getBuddyName(xid).htmlEnc() + '</b> (' + xid.htmlEnc() + ')');
// Get the highest entity resource
var highest = getHighestResource(xid);
if(highest)
xid = highest;
// Start a new adhoc command
dataForm(xid, 'command', '', '', 'adhoc');
return false;
}
// Starts an adhoc command on the user server
function serverAdHoc(server) {
// Open the popup
openAdHoc();
// Add a XID marker
$('#adhoc .adhoc-head').html('<b>' + server.htmlEnc() + '</b>');
// Start a new adhoc command
dataForm(server, 'command', '', '', 'adhoc');
}
// Plugin launcher
function launchAdHoc() {
// Click event
$('#adhoc .bottom .finish').click(closeAdHoc);
}

View file

@ -0,0 +1,131 @@
/*
Jappix - An open social platform
These are the anonymous mode JS script for Jappix
-------------------------------------------------
License: AGPL
Authors: Vanaryon, LinkMauve
Last revision: 02/10/11
*/
// Connected to an anonymous session
function anonymousConnected(con) {
logThis('Jappix (anonymous) is now connected.', 3);
// Connected marker
CONNECTED = true;
CURRENT_SESSION = true;
RECONNECT_TRY = 0;
RECONNECT_TIMER = 0;
// Not resumed?
if(!RESUME) {
// Create the app
createTalkPage();
// Send our first presence
firstPresence('');
// Set last activity stamp
LAST_ACTIVITY = getTimeStamp();
// Create the new groupchat
checkChatCreate(generateXID(ANONYMOUS_ROOM, 'groupchat'), 'groupchat');
// Remove some nasty elements for the anonymous mode
$('.tools-mucadmin, .tools-add').remove();
}
// Resumed
else {
// Send again our presence
presenceSend();
// Change the title
updateTitle();
}
// Remove the waiting icon
removeGeneralWait();
}
// Disconnected from an anonymous session
function anonymousDisconnected() {
logThis('Jappix (anonymous) is now disconnected.', 3);
}
// Logins to a anonymous account
function anonymousLogin(server) {
try {
// We define the http binding parameters
oArgs = new Object();
if(HOST_BOSH_MAIN)
oArgs.httpbase = HOST_BOSH_MAIN;
else
oArgs.httpbase = HOST_BOSH;
// We create the new http-binding connection
con = new JSJaCHttpBindingConnection(oArgs);
// And we handle everything that happen
con.registerHandler('message', handleMessage);
con.registerHandler('presence', handlePresence);
con.registerHandler('iq', handleIQ);
con.registerHandler('onconnect', anonymousConnected);
con.registerHandler('onerror', handleError);
con.registerHandler('ondisconnect', anonymousDisconnected);
// We set the anonymous connection parameters
oArgs = new Object();
oArgs.domain = server;
oArgs.authtype = 'saslanon';
oArgs.resource = JAPPIX_RESOURCE + ' Anonymous (' + (new Date()).getTime() + ')';
oArgs.secure = true;
oArgs.xmllang = XML_LANG;
// We connect !
con.connect(oArgs);
// Change the page title
pageTitle('wait');
}
catch(e) {
// Logs errors
logThis('Error while anonymous loggin in: ' + e, 1);
// Reset Jappix
anonymousDisconnected();
// Open an unknown error
openThisError(2);
}
finally {
return false;
}
}
// Plugin launcher
function launchAnonymous() {
logThis('Anonymous mode detected, connecting...', 3);
// We add the login wait div
showGeneralWait();
// Get the vars
if(LINK_VARS['r'])
ANONYMOUS_ROOM = LINK_VARS['r'];
if(LINK_VARS['n'])
ANONYMOUS_NICK = LINK_VARS['n'];
// Fire the login action
anonymousLogin(HOST_ANONYMOUS);
}
// Launch this plugin!
$(document).ready(launchAnonymous);

View file

@ -0,0 +1,418 @@
/*
Jappix - An open social platform
These are the archives functions for Jappix
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 03/03/11
*/
// Opens the archive tools
function openArchives() {
// Popup HTML content
var html =
'<div class="top">' + _e("Message archives") + '</div>' +
'<div class="content">' +
'<div class="filter">' +
'<select class="friend" multiple=""></select>' +
'<div class="date"></div>' +
'</div>' +
'<div class="current">' +
'<span class="name"></span>' +
'<span class="time">' + _e("Please select a friend to view the chat history.") + '</span>' +
'</div>' +
'<div class="logs" id="chat-content-archives"></div>' +
'</div>' +
'<div class="bottom">' +
'<div class="wait wait-medium"></div>' +
'<a href="#" class="finish">' + _e("Close") + '</a>' +
'</div>';
// Create the popup
createPopup('archives', html);
// Associate the events
launchArchives();
// Get all the buddies in our roster
var buddies = getAllBuddies();
var options = '';
for(i in buddies) {
var current = buddies[i];
// Add the current buddy
options += '<option value="' + encodeQuotes(current) + '">' + getBuddyName(current).htmlEnc() + '</option>';
}
// Can append the buddy HTML code?
if(options)
$('#archives .filter .friend').append(options);
return false;
}
// Closes the archive tools
function closeArchives() {
// Destroy the popup
destroyPopup('archives');
return false;
}
// Gets the archives list for a buddy
function getListArchives(xid) {
// Reset the archives viewer
$('#archives .logs').empty();
// Show the waiting icon
$('#archives .wait').show();
// Apply the ID
var id = genID();
$('#archives').attr('data-session', id);
// New IQ
var iq = new JSJaCIQ();
iq.setType('get');
iq.setID(id);
var list = iq.appendNode('list', {'xmlns': NS_URN_ARCHIVE, 'with': xid});
var set = list.appendChild(iq.buildNode('set', {'xmlns': NS_RSM}));
set.appendChild(iq.buildNode('max', {'xmlns': NS_RSM}, '0'));
con.send(iq, handleListArchives);
logThis('Getting archives list for: ' + xid + '...');
}
// Handles the archives list for a buddy
function handleListArchives(iq) {
// Hide the waiting icon
$('#archives .wait').hide();
// Any error?
if(handleErrorReply(iq) || !exists('#archives[data-session=' + iq.getID() + ']'))
return;
// Get the last archive date
var last = $(iq.getNode()).find('list set changed').text();
// Any last archive?
if(last) {
// Read the date
var date = Date.jab2date(last);
// Change the datepicker value
$('#archives .filter .date').DatePickerSetDate(date, true);
// Retrieve the archives
checkChangeArchives();
}
logThis('Got archives list.', 2);
}
// Gets the archives for a day
function getDayArchives(xid, date) {
// Reset the archives viewer
$('#archives .logs').empty();
// Show the waiting icon
$('#archives .wait').show();
// Apply the ID
var id = genID();
$('#archives').attr('data-session', id);
// New IQ
var iq = new JSJaCIQ();
iq.setType('get');
iq.setID(id);
iq.appendNode('list', {'xmlns': NS_URN_ARCHIVE, 'with': xid, 'start': date + 'T00:00:00Z', 'end': date + 'T23:59:59Z'});
con.send(iq, handleDayArchives);
logThis('Getting day archives (' + date + ') for: ' + xid + '...');
}
// Handles the archives for a day
function handleDayArchives(iq) {
// Hide the waiting icon
$('#archives .wait').hide();
// Any error?
if(handleErrorReply(iq) || !exists('#archives[data-session=' + iq.getID() + ']'))
return;
// Get each archive thread
$(iq.getNode()).find('chat').each(function() {
// Current values
var xid = $(this).attr('with');
var start = $(this).attr('start');
if(xid && start)
$('#archives .logs').append('<input class="archives-pending" type="hidden" data-with="' + encodeQuotes(xid) + '" data-start="' + encodeQuotes(start) + '" />');
});
// Display the day
var date = parseDay($('#archives .filter .date').DatePickerGetDate(true) + 'T00:00:00Z' + getDateTZO());
// Try to get the first thread
var pending = '#archives input.archives-pending:first';
if(!exists(pending))
date = printf(_e("Nothing found for: %s"), date);
else {
retrieveArchives($(pending).attr('data-with'), $(pending).attr('data-start'));
$(pending).remove();
}
$('#archives .current .time').text(date);
logThis('Got day archives.', 2);
}
// Retrieves a specified archive collection
function retrieveArchives(xid, start) {
// Show the waiting icon
$('#archives .wait').show();
// Apply the ID
var id = genID();
$('#archives').attr('data-session', id);
// New IQ
var iq = new JSJaCIQ();
iq.setType('get');
iq.setID(id);
var list = iq.appendNode('retrieve', {'xmlns': NS_URN_ARCHIVE, 'with': xid, 'start': start});
con.send(iq, handleRetrieveArchives);
logThis('Retrieving archives (start: ' + start + ') for: ' + xid + '...');
}
// Handles a specified archive collection
function handleRetrieveArchives(iq) {
// Hide the waiting icon
$('#archives .wait').hide();
// Any error?
if(handleErrorReply(iq) || !exists('#archives[data-session=' + iq.getID() + ']'))
return;
// Get the node
var chat = $(iq.getNode()).find('chat:first');
// Get the buddy XID
var xid = bareXID(chat.attr('with'));
// Get the start date & stamp
var start_date = Date.jab2date(chat.attr('start'));
var start_stamp = extractStamp(start_date);
// Parse the result chat
chat.find('to, from').each(function() {
var node = (this).nodeName;
var stamp = start_stamp + parseInt($(this).attr('secs'));
var date = extractTime(new Date(stamp * 1000));
var body = $(this).find('body').text();
// Is it my message?
if((node == 'to') && body)
displayMessage('chat', getXID(), 'archives', getBuddyName(getXID()).htmlEnc(), body, date, start_stamp, 'user-message', true, '', 'me');
// Is it a buddy message?
else if((node == 'from') && body)
displayMessage('chat', xid, 'archives', getBuddyName(xid).htmlEnc(), body, date, start_stamp, 'user-message', true, '', 'him');
});
// Not the latest thread?
var pending = '#archives input.archives-pending:first';
if(exists(pending)) {
retrieveArchives($(pending).attr('data-with'), $(pending).attr('data-start'));
$(pending).remove();
}
// Everything has been retrieved, get the avatars
else {
getAvatar(getXID(), 'cache', 'true', 'forget');
getAvatar(xid, 'cache', 'true', 'forget');
}
logThis('Got archives.', 2);
}
// Gets the archiving configuration
function getConfigArchives() {
// Lock the archiving options
$('#archiving').attr('checked', false).attr('disabled', true);
// Get the archiving configuration
var iq = new JSJaCIQ();
iq.setType('get');
iq.appendNode('pref', {'xmlns': NS_URN_ARCHIVE});
con.send(iq, handleGetConfigArchives);
}
// Handles the archiving configuration
function handleGetConfigArchives(iq) {
// Reset the options stuffs
waitOptions('archives');
// Unlock the archiving options
$('#archiving').removeAttr('disabled');
// End if not a result
if(!iq || (iq.getType() != 'result'))
return;
// Extract the preferences from the IQ
var enabled = $(iq.getNode()).find('pref auto').attr('save');
// Define the input enabling/disabling vars
var checked = true;
if(enabled != 'true')
checked = false;
// Apply the values
$('#archiving').attr('checked', checked);
}
// Configures the archiving on the server
function configArchives(enabled) {
// Configure the auto element
var iq = new JSJaCIQ();
iq.setType('set');
iq.appendNode('auto', {'xmlns': NS_URN_ARCHIVE, 'save': enabled});
con.send(iq, handleConfigArchives);
// Configure the default element
var iq = new JSJaCIQ();
iq.setType('set');
var pref = iq.appendNode('pref', {'xmlns': NS_URN_ARCHIVE});
pref.appendChild(iq.appendNode('default', {'xmlns': NS_URN_ARCHIVE, 'otr': 'concede', 'save': 'body'}));
con.send(iq);
// Configure the method element
var iq = new JSJaCIQ();
iq.setType('set');
var mType = new Array('auto', 'local', 'manual');
var mUse = new Array('prefer', 'concede', 'concede');
var pref = iq.appendNode('pref', {'xmlns': NS_URN_ARCHIVE});
for(i in mType)
pref.appendChild(iq.appendNode('method', {'xmlns': NS_URN_ARCHIVE, 'type': mType[i], 'use': mUse[i]}));
con.send(iq);
// Logger
logThis('Configuring archives...', 3);
}
// Handles the archives configuration
function handleConfigArchives(iq) {
if(!iq || (iq.getType() != 'result'))
logThis('Archives not configured.', 2);
else
logThis('Archives configured.', 3);
}
// Checks if the datepicker has changed
function checkChangeArchives() {
var xid = $('#archives .filter .friend').val();
var date = $('#archives .filter .date').DatePickerGetDate(true);
// No XID?
if(!xid || !xid.length)
return;
// Too many value?
if(xid.length > 1) {
$('#archives .filter .friend').val(xid[0]);
return;
}
// Get the first XID
xid = xid[0];
// Get the archives
getDayArchives(xid, date);
}
// Update the archives with the selected XID
function updateArchives() {
// Read the values
var xid = $('#archives .filter .friend').val();
var date = $('#archives .filter .date').DatePickerGetDate(true);
// No XID?
if(!xid || !xid.length)
return;
// Too many value?
if(xid.length > 1) {
$('#archives .filter .friend').val(xid[0]);
return;
}
// Get the first XID
xid = xid[0];
// Apply the current marker
$('#archives .current .name').text(getBuddyName(xid));
$('#archives .current .time').text(parseDay(date + 'T00:00:00Z' + getDateTZO()));
// Get the archives
getListArchives(xid, date);
}
// Plugin launcher
function launchArchives() {
// Current date
var current_date = explodeThis('T', getXMPPTime(), 0);
// Datepicker
$('#archives .filter .date').DatePicker({
flat: true,
date: current_date,
current: current_date,
calendars: 1,
starts: 1,
onChange: checkChangeArchives
});
// Click events
$('#archives .bottom .finish').click(function() {
return closeArchives();
});
// Change event
$('#archives .filter .friend').change(updateArchives);
}

View file

@ -0,0 +1,46 @@
/*
Jappix - An open social platform
These are the audio JS scripts for Jappix
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 10/08/11
*/
// Plays the given sound ID
function soundPlay(num) {
try {
// Not supported!
if((BrowserDetect.browser == 'Explorer') && (BrowserDetect.version < 9))
return false;
// If the sounds are enabled
if(getDB('options', 'sounds') == '1') {
// If the audio elements aren't yet in the DOM
if(!exists('#audio')) {
$('body').append(
'<div id="audio">' +
'<audio id="new-chat" src="./snd/new-chat.oga" type="audio/ogg" />' +
'<audio id="receive-message" src="./snd/receive-message.oga" type="audio/ogg" />' +
'<audio id="notification" src="./snd/notification.oga" type="audio/ogg" />' +
'</div>'
);
}
// We play the target sound
var playThis = document.getElementById('audio').getElementsByTagName('audio')[num];
playThis.load();
playThis.play();
}
}
catch(e) {}
finally {
return false;
}
}

View file

@ -0,0 +1,99 @@
/*
Jappix - An open social platform
These are the autocompletion tools JS script for Jappix
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 12/11/10
*/
// Sort an array with insensitivity to the case
function caseInsensitiveSort(a, b) {
// Put the two strings into lower case
a = a.toLowerCase();
b = b.toLowerCase();
// Process the sort
if(a > b)
return 1;
if(a < b)
return -1;
}
// Creates an array with the autocompletion results
function processAutocompletion(query, id) {
// Replace forbidden characters in regex
query = escapeRegex(query);
// Create an empty array
var results = new Array();
// Search in the roster
$('#' + id + ' .user').each(function() {
var nick = $(this).find('.name').text();
var regex = new RegExp('(^)' + query, 'gi');
if(nick.match(regex))
results.push(nick);
});
// Sort the array
results = results.sort(caseInsensitiveSort);
// Return the results array
return results;
}
// Resets the autocompletion tools
function resetAutocompletion(hash) {
$('#' + hash + ' .message-area').removeAttr('data-autocompletion-pointer').removeAttr('data-autocompletion-query');
}
// Autocompletes the chat input nick
function createAutocompletion(hash) {
// Initialize
var vSelector = $('#' + hash + ' .message-area');
var value = vSelector.val();
if(!value)
resetAutocompletion(hash);
var query = vSelector.attr('data-autocompletion-query');
// The autocompletion has not been yet launched
if(query == undefined) {
query = value;
vSelector.attr('data-autocompletion-query', query);
}
// Get the pointer
var pointer = vSelector.attr('data-autocompletion-pointer');
var i = 0;
if(pointer)
i = parseInt(pointer);
// We get the nickname
var nick = processAutocompletion(query, hash)[i];
// Shit, this is my nick!
if((nick != undefined) && (nick.toLowerCase() == getMUCNick(hash).toLowerCase())) {
// Increment
i++;
// Get the next nick
nick = processAutocompletion(query, hash)[i];
}
// We quote the nick
if(nick != undefined) {
// Increment
i++;
quoteMyNick(hash, nick);
// Put a pointer
vSelector.attr('data-autocompletion-pointer', i);
}
}

View file

@ -0,0 +1,205 @@
/*
Jappix - An open social platform
These are the avatar JS scripts for Jappix
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 01/03/11
*/
// Requests the avatar of a given user
var AVATAR_PENDING = [];
function getAvatar(xid, mode, enabled, photo) {
/* REF: http://xmpp.org/extensions/xep-0153.html */
// No need to get the avatar, another process is yet running
if(existArrayValue(AVATAR_PENDING, xid))
return false;
// Initialize: XML data is in one SQL entry, because some browser are sloooow with SQL requests
var xml = XMLFromString(getPersistent('avatar', xid));
var forced = false;
// Retrieving forced?
if($(xml).find('forced').text() == 'true')
forced = true;
// No avatar in presence
if(!photo && !forced && (enabled == 'true')) {
// Pending marker
AVATAR_PENDING.push(xid);
// Reset the avatar
resetAvatar(xid, hex_md5(xid));
logThis('No avatar for: ' + xid, 2);
}
// Try to catch the avatar
else {
// Define some stuffs
var type = $(xml).find('type').text();
var binval = $(xml).find('binval').text();
var checksum = $(xml).find('checksum').text();
var updated = false;
// Process the checksum of the avatar
if((checksum == photo) || (photo == 'forget') || forced)
updated = true;
// If the avatar is yet stored and a new retrieving is not needed
if((mode == 'cache') && type && binval && checksum && updated) {
// Pending marker
AVATAR_PENDING.push(xid);
// Display the cache avatar
displayAvatar(xid, hex_md5(xid), type, binval);
logThis('Read avatar from cache: ' + xid, 3);
}
// Else if the request has not yet been fired, we get it
else if((!updated || (mode == 'cache' && !updated) || (mode == 'force') || (photo = 'forget')) && (enabled != 'false')) {
// Pending marker
AVATAR_PENDING.push(xid);
// Get the latest avatar
var iq = new JSJaCIQ();
iq.setType('get');
iq.setTo(xid);
iq.appendNode('vCard', {'xmlns': NS_VCARD});
con.send(iq, handleAvatar);
logThis('Get avatar from server: ' + xid, 3);
}
}
return true;
}
// Handles the avatar
function handleAvatar(iq) {
// Extract the XML values
var handleXML = iq.getNode();
var handleFrom = fullXID(getStanzaFrom(iq));
// Is this me? Remove the resource!
if(bareXID(handleFrom) == getXID())
handleFrom = bareXID(handleFrom);
// Get some other values
var hash = hex_md5(handleFrom);
var find = $(handleXML).find('vCard');
var aChecksum = 'none';
var oChecksum = null;
// Read our own checksum
if(handleFrom == getXID()) {
oChecksum = getDB('checksum', 1);
// Avoid the "null" value
if(!oChecksum)
oChecksum = '';
}
// vCard not empty?
if(find.size()) {
// We get our profile details
if(handleFrom == getXID()) {
// Get the names
var names = generateBuddyName(iq);
// Write the values to the database
setDB('profile', 'name', names[0]);
setDB('profile', 'nick', names[1]);
}
// We get the avatar
var aType = find.find('TYPE:first').text();
var aBinval = find.find('BINVAL:first').text();
// No binval?
if(!aBinval) {
aType = 'none';
aBinval = 'none';
}
// Enough data
else {
// No type?
if(!aType)
aType = 'image/png';
// Process the checksum
else
aChecksum = hex_sha1(Base64.decode(aBinval));
}
// We display the user avatar
displayAvatar(handleFrom, hash, aType, aBinval);
// Store the avatar
setPersistent('avatar', handleFrom, '<avatar><type>' + aType + '</type><binval>' + aBinval + '</binval><checksum>' + aChecksum + '</checksum><forced>false</forced></avatar>');
logThis('Avatar retrieved from server: ' + handleFrom, 3);
}
// vCard is empty
else
resetAvatar(handleFrom);
// We got a new checksum for us?
if(((oChecksum != null) && (oChecksum != aChecksum)) || !FIRST_PRESENCE_SENT) {
// Define a proper checksum
var pChecksum = aChecksum;
if(pChecksum == 'none')
pChecksum = '';
// Update our temp. checksum
setDB('checksum', 1, pChecksum);
// Send the stanza
if(FIRST_PRESENCE_SENT)
presenceSend(pChecksum);
else
getStorage(NS_OPTIONS);
}
}
// Reset the avatar of an user
function resetAvatar(xid, hash) {
// Store the empty avatar
setPersistent('avatar', xid, '<avatar><type>none</type><binval>none</binval><checksum>none</checksum><forced>false</forced></avatar>');
// Display the empty avatar
displayAvatar(xid, hash, 'none', 'none');
}
// Displays the avatar of an user
function displayAvatar(xid, hash, type, binval) {
// Initialize the vars
var container = hash + ' .avatar-container';
var code = '<img class="avatar" src="';
// If the avatar exists
if((type != 'none') && (binval != 'none'))
code += 'data:' + type + ';base64,' + binval;
else
code += './img/others/default-avatar.png';
code += '" alt="" />';
// Replace with the new avatar (in the roster and in the chat)
$('.' + container).html(code);
// We can remove the pending marker
removeArrayValue(AVATAR_PENDING, xid);
}

View file

@ -0,0 +1,80 @@
// This code was written by Tyler Akins and has been placed in the
// public domain. It would be nice if you left this header intact.
// Base64 code from Tyler Akins -- http://rumkin.com
var Base64 = (function () {
var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
var obj = {
/**
* Encodes a string in base64
* @param {String} input The string to encode in base64.
*/
encode: function (input) {
var output = "";
var chr1, chr2, chr3;
var enc1, enc2, enc3, enc4;
var i = 0;
do {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) +
keyStr.charAt(enc3) + keyStr.charAt(enc4);
} while (i < input.length);
return output;
},
/**
* Decodes a base64 string.
* @param {String} input The string to decode.
*/
decode: function (input) {
var output = "";
var chr1, chr2, chr3;
var enc1, enc2, enc3, enc4;
var i = 0;
// remove all characters that are not A-Z, a-z, 0-9, +, /, or =
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
do {
enc1 = keyStr.indexOf(input.charAt(i++));
enc2 = keyStr.indexOf(input.charAt(i++));
enc3 = keyStr.indexOf(input.charAt(i++));
enc4 = keyStr.indexOf(input.charAt(i++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
output = output + String.fromCharCode(chr1);
if (enc3 != 64) {
output = output + String.fromCharCode(chr2);
}
if (enc4 != 64) {
output = output + String.fromCharCode(chr3);
}
} while (i < input.length);
return output;
}
};
return obj;
})();

View file

@ -0,0 +1,141 @@
/*
Jappix - An open social platform
These are the notification board JS script for Jappix
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 12/03/11
*/
// Creates a board panel
function createBoard(type, id) {
// Text var
var text = '';
// Info
if(type == 'info') {
switch(id) {
// Password change
case 1:
text = _e("Your password has been changed, now you can connect to your account with your new login data.");
break;
// Account deletion
case 2:
text = _e("Your XMPP account has been removed, bye!");
break;
// Account logout
case 3:
text = _e("You have been logged out of your XMPP account, have a nice day!");
break;
// Groupchat join
case 4:
text = _e("The room you joined seems not to exist. You should create it!");
break;
// Groupchat removal
case 5:
text = _e("The groupchat has been removed, now someone else will be able to recreate it.");
break;
// Non-existant groupchat user
case 6:
text = _e("The user that you want to reach is not present in the room.");
break;
}
}
// Error
else {
switch(id) {
// Custom error
case 1:
text = '<b>' + _e("Error") + '</b> &raquo; <span></span>';
break;
// Network error
case 2:
text = _e("Jappix has been interrupted by a network issue, a bug or bad login (check that you entered the right credentials), sorry for the inconvenience.");
break;
// List retrieving error
case 3:
text = _e("The element list on this server could not be obtained!");
break;
// Attaching error
case 4:
text = printf(_e("An error occured while uploading your file: maybe it is too big (%s maximum) or forbidden!"), JAPPIX_MAX_UPLOAD);
break;
}
}
// No text?
if(!text)
return false;
// Append the content
$('#board').append('<div class="one-board ' + type + '" data-id="' + id + '">' + text + '</div>');
// Events (click and auto-hide)
$('#board .one-board.' + type + '[data-id=' + id + ']')
.click(function() {
closeThisBoard(this);
})
.oneTime('5s', function() {
closeThisBoard(this);
})
.slideDown();
return true;
}
// Destroys the existing board notifications
function destroyBoard() {
$('#board').empty();
}
// Executes a given action on the notification board
function actionBoard(id, type) {
// In a first, we destroy other boards
destroyBoard();
// Then we display the board
createBoard(type, id);
}
// Opens a given error ID
function openThisError(id) {
actionBoard(id, 'error');
}
// Opens a given info ID
function openThisInfo(id) {
actionBoard(id, 'info');
}
// Closes a given board
function closeThisBoard(board) {
$(board).slideUp('normal', function() {
$(this).remove();
});
}

View file

@ -0,0 +1,124 @@
/* BROWSER DETECT
* http://www.quirksmode.org/js/detect.html
*/
var BrowserDetect = {
init: function () {
this.browser = this.searchString(this.dataBrowser) || "An unknown browser";
this.version = this.searchVersion(navigator.userAgent)
|| this.searchVersion(navigator.appVersion)
|| "an unknown version";
this.OS = this.searchString(this.dataOS) || "an unknown OS";
},
searchString: function (data) {
for (var i=0;i<data.length;i++) {
var dataString = data[i].string;
var dataProp = data[i].prop;
this.versionSearchString = data[i].versionSearch || data[i].identity;
if (dataString) {
if (dataString.indexOf(data[i].subString) != -1)
return data[i].identity;
}
else if (dataProp)
return data[i].identity;
}
},
searchVersion: function (dataString) {
var index = dataString.indexOf(this.versionSearchString);
if (index == -1) return;
return parseFloat(dataString.substring(index+this.versionSearchString.length+1));
},
dataBrowser: [
{
string: navigator.userAgent,
subString: "Chrome",
identity: "Chrome"
},
{ string: navigator.userAgent,
subString: "OmniWeb",
versionSearch: "OmniWeb/",
identity: "OmniWeb"
},
{
string: navigator.vendor,
subString: "Apple",
identity: "Safari",
versionSearch: "Version"
},
{
prop: window.opera,
identity: "Opera"
},
{
string: navigator.vendor,
subString: "iCab",
identity: "iCab"
},
{
string: navigator.vendor,
subString: "KDE",
identity: "Konqueror"
},
{
string: navigator.userAgent,
subString: "Firefox",
identity: "Firefox"
},
{
string: navigator.vendor,
subString: "Camino",
identity: "Camino"
},
{ // for newer Netscapes (6+)
string: navigator.userAgent,
subString: "Netscape",
identity: "Netscape"
},
{
string: navigator.userAgent,
subString: "MSIE",
identity: "Explorer",
versionSearch: "MSIE"
},
{
string: navigator.userAgent,
subString: "Gecko",
identity: "Mozilla",
versionSearch: "rv"
},
{ // for older Netscapes (4-)
string: navigator.userAgent,
subString: "Mozilla",
identity: "Netscape",
versionSearch: "Mozilla"
}
],
dataOS : [
{
string: navigator.platform,
subString: "Win",
identity: "Windows"
},
{
string: navigator.platform,
subString: "Mac",
identity: "Mac"
},
{
string: navigator.userAgent,
subString: "iPhone",
identity: "iPhone/iPod"
},
{
string: navigator.platform,
subString: "Linux",
identity: "Linux"
}
]
};
BrowserDetect.init();

View file

@ -0,0 +1,59 @@
/*
Jappix - An open social platform
These are the bubble JS scripts for Jappix
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 11/12/10
*/
// Closes all the opened bubbles
function closeBubbles() {
// Destroy all the elements
$('.bubble.hidable:visible').hide();
$('.bubble.removable').remove();
$('body').die('click');
return false;
}
// Click function when a bubble is opened
function showBubble(selector) {
// Hidable bubbles special things
if($(selector).is('.hidable')) {
// This bubble is yet displayed? So abort!
if($(selector).is(':visible'))
return closeBubbles();
// Close all the bubbles
closeBubbles();
// Show the requested bubble
$(selector).show();
}
// Removable bubbles special things
else {
// This bubble is yet added? So abort!
if(exists(selector))
return closeBubbles();
// Close all the bubbles
closeBubbles();
}
// Creates a new click event to close the bubble
$('body').live('click', function(evt) {
var target = evt.target;
// If this is a click away from a bubble
if(!$(target).parents('.ibubble').size())
closeBubbles();
});
return false;
}

View file

@ -0,0 +1,349 @@
/*
Jappix - An open social platform
These are the CAPS JS script for Jappix
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 26/08/11
*/
// Returns an array of the Jappix disco#infos
function myDiscoInfos() {
var fArray = new Array(
NS_MUC,
NS_MUC_USER,
NS_MUC_ADMIN,
NS_MUC_OWNER,
NS_MUC_CONFIG,
NS_DISCO_INFO,
NS_DISCO_ITEMS,
NS_PUBSUB_RI,
NS_BOSH,
NS_CAPS,
NS_MOOD,
NS_ACTIVITY,
NS_TUNE,
NS_GEOLOC,
NS_NICK,
NS_URN_ADATA,
NS_URN_AMETA,
NS_URN_MBLOG,
NS_URN_INBOX,
NS_MOOD + NS_NOTIFY,
NS_ACTIVITY + NS_NOTIFY,
NS_TUNE + NS_NOTIFY,
NS_GEOLOC + NS_NOTIFY,
NS_URN_MBLOG + NS_NOTIFY,
NS_URN_INBOX + NS_NOTIFY,
NS_URN_DELAY,
NS_ROSTER,
NS_ROSTERX,
NS_HTTP_AUTH,
NS_CHATSTATES,
NS_XHTML_IM,
NS_IPV6,
NS_LAST,
NS_PRIVATE,
NS_REGISTER,
NS_SEARCH,
NS_COMMANDS,
NS_VERSION,
NS_XDATA,
NS_VCARD,
NS_URN_TIME,
NS_URN_PING,
NS_URN_ARCHIVE,
NS_URN_AR_PREF,
NS_URN_RECEIPTS,
NS_PRIVACY,
NS_IQOOB,
NS_XOOB
);
return fArray;
}
// Gets the disco#infos of an entity
function getDiscoInfos(to, caps) {
// No CAPS
if(!caps) {
logThis('No CAPS: ' + to, 2);
displayDiscoInfos(to, '');
return false;
}
// Get the stored disco infos
var xml = XMLFromString(getPersistent('caps', caps));
// Yet stored
if(xml) {
logThis('CAPS from cache: ' + to, 3);
displayDiscoInfos(to, xml);
return true;
}
logThis('CAPS from the network: ' + to, 3);
// Not stored: get the disco#infos
var iq = new JSJaCIQ();
iq.setTo(to);
iq.setType('get');
iq.setQuery(NS_DISCO_INFO);
con.send(iq, handleDiscoInfos);
return true;
}
// Handles the disco#infos of an entity
function handleDiscoInfos(iq) {
if(!iq || (iq.getType() == 'error'))
return;
// IQ received, get some values
var from = fullXID(getStanzaFrom(iq));
var query = iq.getQuery();
// Generate the CAPS-processing values
var identities = new Array();
var features = new Array();
var data_forms = new Array();
// Identity values
$(query).find('identity').each(function() {
var pCategory = $(this).attr('category');
var pType = $(this).attr('type');
var pLang = $(this).attr('xml:lang');
var pName = $(this).attr('name');
if(!pCategory)
pCategory = '';
if(!pType)
pType = '';
if(!pLang)
pLang = '';
if(!pName)
pName = '';
identities.push(pCategory + '/' + pType + '/' + pLang + '/' + pName);
});
// Feature values
$(query).find('feature').each(function() {
var pVar = $(this).attr('var');
// Add the current value to the array
if(pVar)
features.push(pVar);
});
// Data-form values
$(query).find('x[xmlns=' + NS_XDATA + ']').each(function() {
// Initialize some stuffs
var pString = '';
var sortVar = new Array();
// Add the form type field
$(this).find('field[var=FORM_TYPE] value').each(function() {
var cText = $(this).text();
if(cText)
pString += cText + '<';
});
// Add the var attributes into an array
$(this).find('field:not([var=FORM_TYPE])').each(function() {
var cVar = $(this).attr('var');
if(cVar)
sortVar.push(cVar);
});
// Sort the var attributes
sortVar = sortVar.sort();
// Loop this sorted var attributes
for(i in sortVar) {
// Initialize the value sorting
var sortVal = new Array();
// Append it to the string
pString += sortVar[i] + '<';
// Add each value to the array
$(this).find('field[var=' + sortVar[i] + '] value').each(function() {
sortVal.push($(this).text());
});
// Sort the values
sortVal = sortVal.sort();
// Append the values to the string
for(j in sortVal)
pString += sortVal[j] + '<';
}
// Any string?
if(pString) {
// Remove the undesired double '<' from the string
if(pString.match(/(.+)(<)+$/))
pString = pString.substring(0, pString.length - 1);
// Add the current string to the array
data_forms.push(pString);
}
});
// Process the CAPS
var caps = processCaps(identities, features, data_forms);
// Get the XML string
var xml = xmlToString(query);
// Store the disco infos
setPersistent('caps', caps, xml);
// This is our server
if(from == getServer()) {
// Handle the features
handleFeatures(xml);
logThis('Got our server CAPS', 3);
}
else {
// Display the disco infos
displayDiscoInfos(from, xml);
logThis('Got CAPS: ' + from, 3);
}
}
// Displays the disco#infos everywhere needed for an entity
function displayDiscoInfos(from, xml) {
// Generate the chat path
var xid = bareXID(from);
// This comes from a private groupchat chat?
if(isPrivate(xid))
xid = from;
hash = hex_md5(xid);
// Support indicators
var xhtml_im = false;
var iq_oob = false;
var x_oob = false;
var receipts = false;
// Display the supported features
$(xml).find('feature').each(function() {
var current = $(this).attr('var');
// xHTML-IM
if(current == NS_XHTML_IM)
xhtml_im = true;
// Out of Band Data (IQ)
if(current == NS_IQOOB)
iq_oob = true;
// Out of Band Data (X)
if(current == NS_XOOB)
x_oob = true;
// Receipts
else if(current == NS_URN_RECEIPTS)
receipts = true;
});
// Paths
var path = $('#' + hash);
var message_area = path.find('.message-area');
var style = path.find('.chat-tools-style');
var file = path.find('.chat-tools-file');
// Apply xHTML-IM
if(xhtml_im)
style.show();
else {
// Remove the tooltip elements
style.hide();
style.find('.bubble-style').remove();
// Reset the markers
message_area.removeAttr('style')
.removeAttr('data-color')
.removeAttr('data-bold')
.removeAttr('data-italic')
.removeAttr('data-underline');
}
// Apply Out of Band Data
if(iq_oob || x_oob) {
file.show();
// Set a marker
if(iq_oob)
file.attr('data-oob', 'iq');
else
file.attr('data-oob', 'x');
}
else {
// Remove the tooltip elements
file.hide();
file.find('.bubble-style').remove();
// Reset the marker
file.removeAttr('data-oob');
}
// Apply receipts
if(receipts)
message_area.attr('data-receipts', 'true');
else
message_area.removeAttr('data-receipts');
}
// Generates the CAPS hash
function processCaps(cIdentities, cFeatures, cDataForms) {
// Initialize
var cString = '';
// Sort the arrays
cIdentities = cIdentities.sort();
cFeatures = cFeatures.sort();
cDataForms = cDataForms.sort();
// Process the sorted identity string
for(a in cIdentities)
cString += cIdentities[a] + '<';
// Process the sorted feature string
for(b in cFeatures)
cString += cFeatures[b] + '<';
// Process the sorted data-form string
for(c in cDataForms)
cString += cDataForms[c] + '<';
// Process the SHA-1 hash
var cHash = b64_sha1(cString);
return cHash;
}
// Generates the Jappix CAPS hash
function myCaps() {
return processCaps(new Array('client/web//Jappix'), myDiscoInfos(), new Array());
}

View file

@ -0,0 +1,297 @@
/*
Jappix - An open social platform
These are the chat JS scripts for Jappix
-------------------------------------------------
License: AGPL
Authors: Vanaryon, Eric
Last revision: 16/10/11
*/
// Correctly opens a new chat
function checkChatCreate(xid, type, nickname, password, title) {
// No XID?
if(!xid)
return false;
// We generate some stuffs
var hash = hex_md5(xid);
var name;
// Gets the name of the user/title of the room
if(title)
name = title;
else {
// Private groupchat chat
if(type == 'private')
name = thisResource(xid);
// XMPP-ID
else if(xid.indexOf('@') != -1)
name = getBuddyName(xid);
// Gateway
else
name = xid;
}
// If the target div does not exist
if(!exists('#' + hash)) {
// We check the type of the chat to open
if((type == 'chat') || (type == 'private'))
chatCreate(hash, xid, name, type);
else if(type == 'groupchat') {
// Try to read the room stored configuration
if(!isAnonymous() && (!nickname || !password || !title)) {
// Catch the room data
var fData = $(XMLFromString(getDB('favorites', xid)));
var fNick = fData.find('nick').text();
var fPwd = fData.find('password').text();
var fName = fData.find('name').text();
// Apply the room data
if(!nickname && fNick)
nickname = fNick;
if(!password && fPwd)
password = fPwd;
if(!title && fName)
name = fName;
}
groupchatCreate(hash, xid, name, nickname, password);
}
}
// Switch to the newly-created chat
switchChan(hash);
return false;
}
// Generates the chat DOM elements
function generateChat(type, id, xid, nick) {
// Generate some stuffs
var path = '#' + id + ' .';
var escaped_xid = escape(xid);
// Special code
var specialAttributes, specialAvatar, specialName, specialCode, specialLink, specialDisabled, specialStyle;
// Groupchat special code
if(type == 'groupchat') {
specialAttributes = ' data-type="groupchat"';
specialAvatar = '';
specialName = '<p class="bc-infos"><b>' + _e("Subject") + '</b> <span class="muc-topic">' + _e("no subject defined for this room.") + '</span></p>';
specialCode = '<div class="content groupchat-content" id="chat-content-' + id + '"></div><div class="list"><div class="moderator role"><p class="title">' + _e("Moderators") + '</p></div><div class="participant role"><p class="title">' + _e("Participants") + '</p></div><div class="visitor role"><p class="title">' + _e("Visitors") + '</p></div><div class="none role"><p class="title">' + _e("Others") + '</p></div></div>';
specialLink = '<a href="#" class="tools-mucadmin tools-tooltip talk-images chat-tools-content" title="' + _e("Administration panel for this room") + '"></a>';
specialStyle = '';
// Is this a gateway?
if(xid.match(/%/))
specialDisabled = '';
else
specialDisabled = ' disabled=""';
}
// Chat (or other things?!) special code
else {
specialAttributes = ' data-type="chat"';
specialAvatar = '<div class="avatar-container"><img class="avatar" src="' + './img/others/default-avatar.png' + '" alt="" /></div>';
specialName = '<div class="bc-pep"></div><p class="bc-infos"><span class="unavailable show talk-images"></span></p>';
specialCode = '<div class="content" id="chat-content-' + id + '"></div>';
specialLink = '<a href="#" class="tools-archives tools-tooltip talk-images chat-tools-content" title="' + _e("View chat history") + '"></a><a href="#" class="tools-infos tools-tooltip talk-images chat-tools-content" title="' + _e("Show user profile") + '"></a>';
specialStyle = ' style="display: none;"';
specialDisabled = '';
}
// Not a groupchat private chat, we can use the buddy add icon
if((type == 'chat') || (type == 'groupchat')) {
var addTitle;
if(type == 'chat')
addTitle = _e("Add this contact to your friends");
else
addTitle = _e("Add this groupchat to your favorites");
specialLink += '<a href="#" class="tools-add tools-tooltip talk-images chat-tools-content" title="' + addTitle + '"></a>';
}
// IE DOM parsing bug fix
var specialStylePicker = '<div class="chat-tools-content chat-tools-style"' + specialStyle + '>' +
'<a href="#" class="tools-style tools-tooltip talk-images"></a>' +
'</div>';
if((BrowserDetect.browser == 'Explorer') && (BrowserDetect.version < 9))
specialStylePicker = '';
// Append the chat HTML code
$('#page-engine').append(
'<div id="' + id + '" class="page-engine-chan chat one-counter"' + specialAttributes + ' data-xid="' + escaped_xid + '">' +
'<div class="top ' + id + '">' +
specialAvatar +
'<div class="name">' +
'<p class="bc-name bc-name-nick">' + nick.htmlEnc() + '</p>' +
specialName +
'</div>' +
'</div>' +
specialCode +
'<div class="text">' +
'<div class="footer">' +
'<div class="chat-tools-content chat-tools-smileys">' +
'<a href="#" class="tools-smileys tools-tooltip talk-images"></a>' +
'</div>' +
specialStylePicker +
'<div class="chat-tools-content chat-tools-file">' +
'<a href="#" class="tools-file tools-tooltip talk-images"></a>' +
'</div>' +
'<div class="chat-tools-content chat-tools-save">' +
'<a href="#" class="tools-save tools-tooltip talk-images"></a>' +
'</div>' +
'<a href="#" class="tools-clear tools-tooltip talk-images chat-tools-content" title="' + _e("Clean current chat") + '"></a>' +
specialLink +
'</div>' +
'<div class="compose">' +
'<textarea class="message-area focusable" ' + specialDisabled + ' data-to="' + escaped_xid + '" /></textarea>' +
'</div>' +
'</div>' +
'</div>'
);
// Click event: chat cleaner
$(path + 'tools-clear').click(function() {
cleanChat(id);
});
// Click event: user-infos
$(path + 'tools-infos').click(function() {
openUserInfos(xid);
});
}
// Generates the chat switch elements
function generateSwitch(type, id, xid, nick) {
// Path to the element
var chat_switch = '#page-switch .';
// Special code
var specialClass = ' unavailable';
var show_close = true;
// Groupchat
if(type == 'groupchat') {
specialClass = ' groupchat-default';
if(isAnonymous() && (xid == generateXID(ANONYMOUS_ROOM, 'groupchat')))
show_close = false;
}
// Generate the HTML code
var html = '<div class="' + id + ' switcher chan" onclick="return switchChan(\'' + encodeOnclick(id) + '\')">' +
'<div class="icon talk-images' + specialClass + '"></div>' +
'<div class="name">' + nick.htmlEnc() + '</div>';
// Show the close button if not MUC and not anonymous
if(show_close)
html += '<div class="exit" title="' + _e("Close this tab") + '" onclick="return quitThisChat(\'' + encodeOnclick(xid) + '\', \'' + encodeOnclick(id) + '\', \'' + encodeOnclick(type) + '\');">x</div>';
// Close the HTML
html += '</div>';
// Append the HTML code
$(chat_switch + 'chans, ' + chat_switch + 'more-content').append(html);
}
// Cleans given the chat lines
function cleanChat(chat) {
$('#page-engine #' + chat + ' .content .one-group').remove();
$(document).oneTime(10, function() {
$('#page-engine #' + chat + ' .text .message-area').focus();
});
}
// Creates a new chat
function chatCreate(hash, xid, nick, type) {
logThis('New chat: ' + xid, 3);
// Create the chat content
generateChat(type, hash, xid, nick);
// Create the chat switcher
generateSwitch(type, hash, xid, nick);
// If the user is not in our buddy-list
if(type == 'chat') {
// Add button
if(!exists('#buddy-list .buddy[data-xid=' + escape(xid) + ']'))
$('#' + hash + ' .tools-add').click(function() {
// Hide the icon (to tell the user all is okay)
$(this).hide();
// Send the subscribe request
addThisContact(xid, nick);
}).show();
// Archives button
else if(enabledArchives() || enabledArchives('auto') || enabledArchives('manual') || enabledArchives('manage'))
$('#' + hash + ' .tools-archives').click(function() {
// Open the archives popup
openArchives();
// Get the archives for this user
$('#archives .filter .friend').val(xid);
updateArchives();
}).show();
}
// We catch the user's informations (like this avatar, vcard, and so on...)
getUserInfos(hash, xid, nick, type);
// The icons-hover functions
tooltipIcons(xid, hash);
// The event handlers
var inputDetect = $('#page-engine #' + hash + ' .message-area');
inputDetect.focus(function() {
chanCleanNotify(hash);
})
inputDetect.keypress(function(e) {
// Enter key
if(e.keyCode == 13) {
// Add a new line
if(e.shiftKey)
inputDetect.val(inputDetect.val() + '\n');
// Send the message
else {
// Send the message
sendMessage(hash, 'chat');
// Reset the composing database entry
setDB('chatstate', xid, 'off');
}
return false;
}
});
// Chatstate events
eventsChatState(inputDetect, xid, hash);
}

View file

@ -0,0 +1,174 @@
/*
Jappix - An open social platform
These are the chatstate JS script for Jappix
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 25/08/11
*/
// Sends a given chatstate to a given entity
function chatStateSend(state, xid, hash) {
var user_type = $('#' + hash).attr('data-type');
// If the friend client supports chatstates and is online
if((user_type == 'groupchat') || ((user_type == 'chat') && $('#' + hash + ' .message-area').attr('data-chatstates') && !exists('#page-switch .' + hash + ' .unavailable'))) {
// Already sent?
if(getDB('currentchatstate', xid) == state)
return;
// Write the state
setDB('currentchatstate', xid, state);
// New message stanza
var aMsg = new JSJaCMessage();
aMsg.setTo(xid);
aMsg.setType(user_type);
// Append the chatstate node
aMsg.appendNode(state, {'xmlns': NS_CHATSTATES});
// Send this!
con.send(aMsg);
}
}
// Displays a given chatstate in a given chat
function displayChatState(state, hash, type) {
// Groupchat?
if(type == 'groupchat') {
resetChatState(hash, type);
// "gone" state not allowed
if(state != 'gone')
$('#page-engine .page-engine-chan .user.' + hash).addClass(state);
}
// Chat
else {
// We change the buddy name color in the page-switch
resetChatState(hash, type);
$('#page-switch .' + hash + ' .name').addClass(state);
// We generate the chatstate text
var text = '';
switch(state) {
// Active
case 'active':
text = _e("Your friend is paying attention to the conversation.");
break;
// Composing
case 'composing':
text = _e("Your friend is writing a message...");
break;
// Paused
case 'paused':
text = _e("Your friend stopped writing a message.");
break;
// Inactive
case 'inactive':
text = _e("Your friend is doing something else.");
break;
// Gone
case 'gone':
text = _e("Your friend closed the chat.");
break;
}
// We reset the previous state
$('#' + hash + ' .chatstate').remove();
// We create the chatstate
$('#' + hash + ' .content').after('<div class="' + state + ' chatstate">' + text + '</div>');
}
}
// Resets the chatstate switcher marker
function resetChatState(hash, type) {
// Define the selector
var selector;
if(type == 'groupchat')
selector = $('#page-engine .page-engine-chan .user.' + hash);
else
selector = $('#page-switch .' + hash + ' .name');
// Reset!
selector.removeClass('active')
selector.removeClass('composing')
selector.removeClass('paused')
selector.removeClass('inactive')
selector.removeClass('gone');
}
// Adds the chatstate events
function eventsChatState(target, xid, hash) {
target.keyup(function(e) {
if(e.keyCode != 13) {
// Composing a message
if($(this).val() && (getDB('chatstate', xid) != 'on')) {
// We change the state detect input
setDB('chatstate', xid, 'on');
// We send the friend a "composing" chatstate
chatStateSend('composing', xid, hash);
}
// Stopped composing a message
else if(!$(this).val() && (getDB('chatstate', xid) == 'on')) {
// We change the state detect input
setDB('chatstate', xid, 'off');
// We send the friend an "active" chatstate
chatStateSend('active', xid, hash);
}
}
});
target.change(function() {
// Reset the composing database entry
setDB('chatstate', xid, 'off');
});
target.focus(function() {
// Not needed
if(target.is(':disabled'))
return;
// Nothing in the input, user is active
if(!$(this).val())
chatStateSend('active', xid, hash);
// Something was written, user started writing again
else
chatStateSend('composing', xid, hash);
});
target.blur(function() {
// Not needed
if(target.is(':disabled'))
return;
// Nothing in the input, user is inactive
if(!$(this).val())
chatStateSend('inactive', xid, hash);
// Something was written, user paused
else
chatStateSend('paused', xid, hash);
});
}

View file

@ -0,0 +1,311 @@
/*
Jappix - An open social platform
These are the common JS script for Jappix
-------------------------------------------------
License: AGPL
Authors: Vanaryon, olivierm
Last revision: 24/06/11
*/
// Checks if an element exists in the DOM
function exists(selector) {
if(jQuery(selector).size() > 0)
return true;
else
return false;
}
// Checks if Jappix is connected
function isConnected() {
if((typeof con != 'undefined') && con && con.connected())
return true;
return false;
}
// Checks if Jappix has focus
function isFocused() {
try {
if(document.hasFocus())
return true;
return false;
}
catch(e) {
return true;
}
}
// Generates the good XID
function generateXID(xid, type) {
// XID needs to be transformed
if(xid && (xid.indexOf('@') == -1)) {
// Groupchat
if(type == 'groupchat')
return xid + '@' + HOST_MUC;
// One-to-one chat
if(xid.indexOf('.') == -1)
return xid + '@' + HOST_MAIN;
// It might be a gateway?
return xid;
}
// Nothing special (yet bare XID)
return xid;
}
// Gets the asked translated string
function _e(string) {
return string;
}
// Replaces '%s' to a given value for a translated string
function printf(string, value) {
return string.replace('%s', value);
}
// Properly explodes a string with a given character
function explodeThis(toEx, toStr, i) {
// Get the index of our char to explode
var index = toStr.indexOf(toEx);
// We split if necessary the string
if(index != -1) {
if(i == 0)
toStr = toStr.substr(0, index);
else
toStr = toStr.substr(index + 1);
}
// We return the value
return toStr;
}
// Cuts the resource of a XID
function cutResource(aXID) {
return explodeThis('/', aXID, 0);
}
// Gets the resource of a XID
function thisResource(aXID) {
// Any resource?
if(aXID.indexOf('/') != -1)
return explodeThis('/', aXID, 1);
// No resource
return '';
}
// Does stringprep on a string
function stringPrep(string) {
// Replacement arrays
var invalid = new Array('Š', 'š', 'Đ', 'đ', 'Ž', 'ž', 'Č', 'č', 'Ć', 'ć', 'À', 'Á', 'Â', 'Ã', 'Ä', 'Å', 'Æ', 'Ç', 'È', 'É', 'Ê', 'Ë', 'Ì', 'Í', 'Î', 'Ï', 'Ñ', 'Ò', 'Ó', 'Ô', 'Õ', 'Ö', 'Ø', 'Ù', 'Ú', 'Û', 'Ü', 'Ý', 'Þ', 'ß', 'à', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è', 'é', 'ê', 'ë', 'ì', 'í', 'î', 'ï', 'ð', 'ñ', 'ò', 'ó', 'ô', 'õ', 'ö', 'ø', 'ù', 'ú', 'û', 'ý', 'þ', 'ÿ', 'Ŕ', 'ŕ');
var valid = new Array('S', 's', 'Dj', 'dj', 'Z', 'z', 'C', 'c', 'C', 'c', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'C', 'E', 'E', 'E', 'E', 'I', 'I', 'I', 'I', 'N', 'O', 'O', 'O', 'O', 'O', 'O', 'U', 'U', 'U', 'U', 'Y', 'B', 'Ss', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'c', 'e', 'e', 'e', 'e', 'i', 'i', 'i', 'i', 'o', 'n', 'o', 'o', 'o', 'o', 'o', 'o', 'u', 'u', 'u', 'y', 'b', 'y', 'R', 'r');
// Compute a new string
for(i in invalid)
string = string.replace(invalid[i], valid[i]);
return string;
}
// Encodes quotes in a string
function encodeQuotes(str) {
return (str + '').replace(/"/g, '&quot;');
}
// Gets the bare XID from a XID
function bareXID(xid) {
// Cut the resource
xid = cutResource(xid);
// Launch the stringprep
xid = stringPrep(xid);
// Set the XID to lower case
xid = xid.toLowerCase();
return xid;
}
// Gets the full XID from a XID
function fullXID(xid) {
// Normalizes the XID
var full = bareXID(xid);
var resource = thisResource(xid);
// Any resource?
if(resource)
full += '/' + resource;
return full;
}
// Gets the nick from a XID
function getXIDNick(aXID) {
return explodeThis('@', aXID, 0);
}
// Gets the host from a XID
function getXIDHost(aXID) {
return explodeThis('@', aXID, 1);
}
// Checks if we are in developer mode
function isDeveloper() {
if(DEVELOPER == 'on')
return true;
return false;
}
// Checks if anonymous mode is allowed
function allowedAnonymous() {
if(ANONYMOUS == 'on')
return true;
return false;
}
// Checks if host is locked
function lockHost() {
if(LOCK_HOST == 'on')
return true;
return false;
}
// Gets the full XID of the user
function getXID() {
// Return the XID of the user
if(con.username && con.domain)
return con.username + '@' + con.domain;
return '';
}
// Generates the colors for a given user XID
function generateColor(xid) {
var colors = new Array(
'ac0000',
'a66200',
'007703',
'00705f',
'00236b',
'4e005c'
);
var number = 0;
for(var i = 0; i < xid.length; i++)
number += xid.charCodeAt(i);
var color = '#' + colors[number % (colors.length)];
return color;
}
// Checks if the XID is a gateway
function isGateway(xid) {
if(xid.indexOf('@') != -1)
return false;
return true;
}
// Gets the from attribute of a stanza (overrides some servers like Prosody missing from attributes)
function getStanzaFrom(stanza) {
var from = stanza.getFrom();
// No from, we assume this is our XID
if(!from)
from = getXID();
return from;
}
// Logs a given data in the console
function logThis(data, level) {
// Console not available
if(!isDeveloper() || (typeof(console) == 'undefined'))
return false;
// Switch the log level
switch(level) {
// Debug
case 0:
console.debug(data);
break;
// Error
case 1:
console.error(data);
break;
// Warning
case 2:
console.warn(data);
break;
// Information
case 3:
console.info(data);
break;
// Default log level
default:
console.log(data);
break;
}
return true;
}
// Gets the current Jappix app. location
function getJappixLocation() {
var url = window.location.href;
// If the URL has variables, remove them
if(url.indexOf('?') != -1)
url = url.split('?')[0];
if(url.indexOf('#') != -1)
url = url.split('#')[0];
// No "/" at the end
if(!url.match(/(.+)\/$/))
url += '/';
return url;
}
// Removes spaces at the beginning & the end of a string
function trim(str) {
return str.replace(/^\s+/g,'').replace(/\s+$/g,'');
}
// Adds a zero to a date when needed
function padZero(i) {
// Negative number (without first 0)
if(i > -10 && i < 0)
return '-0' + (i * -1);
// Positive number (without first 0)
if(i < 10 && i >= 0)
return '0' + i;
// All is okay
return i;
}

View file

@ -0,0 +1,526 @@
/*
Jappix - An open social platform
These are the connection JS script for Jappix
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 29/08/11
*/
// Does the user login
var CURRENT_SESSION = false;
function doLogin(lNick, lServer, lPass, lResource, lPriority, lRemember) {
try {
// We remove the not completed class to avoid problems
$('#home .loginer input').removeClass('please-complete');
// We add the login wait div
showGeneralWait();
// We define the http binding parameters
oArgs = new Object();
if(HOST_BOSH_MAIN)
oArgs.httpbase = HOST_BOSH_MAIN;
else
oArgs.httpbase = HOST_BOSH;
// We create the new http-binding connection
con = new JSJaCHttpBindingConnection(oArgs);
// And we handle everything that happen
setupCon(con);
// Generate a resource
var random_resource = getDB('session', 'resource');
if(!random_resource)
random_resource = lResource + ' (' + (new Date()).getTime() + ')';
// We retrieve what the user typed in the login inputs
oArgs = new Object();
oArgs.domain = trim(lServer);
oArgs.username = trim(lNick);
oArgs.resource = random_resource;
oArgs.pass = lPass;
oArgs.secure = true;
oArgs.xmllang = XML_LANG;
// Store the resource (for reconnection)
setDB('session', 'resource', random_resource);
// Generate a session XML to be stored
session_xml = '<session><stored>true</stored><domain>' + lServer.htmlEnc() + '</domain><username>' + lNick.htmlEnc() + '</username><resource>' + lResource.htmlEnc() + '</resource><password>' + lPass.htmlEnc() + '</password><priority>' + lPriority.htmlEnc() + '</priority></session>';
// Save the session parameters (for reconnect if network issue)
CURRENT_SESSION = session_xml;
// Remember me?
if(lRemember)
setDB('remember', 'session', 1);
// We store the infos of the user into the data-base
setDB('priority', 1, lPriority);
// We connect !
con.connect(oArgs);
// Change the page title
pageTitle('wait');
logThis('Jappix is connecting...', 3);
}
catch(e) {
// Logs errors
logThis('Error while logging in: ' + e, 1);
// Reset Jappix
destroyTalkPage();
// Open an unknown error
openThisError(2);
}
finally {
return false;
}
}
// Handles the user registration
function handleRegistered() {
logThis('A new account has been registered.', 3);
// We remove the waiting image
removeGeneralWait();
// Reset the title
pageTitle('home');
// We show the success information
$('#home .registerer .success').fadeIn('fast');
// We quit the session
logout();
}
// Does the user registration
function doRegister(username, domain, pass) {
logThis('Trying to register an account...', 3);
try {
// We define the http binding parameters
oArgs = new Object();
if(HOST_BOSH_MAIN)
oArgs.httpbase = HOST_BOSH_MAIN;
else
oArgs.httpbase = HOST_BOSH;
// We create the new http-binding connection
con = new JSJaCHttpBindingConnection(oArgs);
// We setup the connection !
con.registerHandler('onconnect', handleRegistered);
con.registerHandler('onerror', handleError);
// We retrieve what the user typed in the register inputs
oArgs = new Object();
oArgs.domain = trim(domain);
oArgs.username = trim(username);
oArgs.resource = JAPPIX_RESOURCE + ' Register (' + (new Date()).getTime() + ')';
oArgs.pass = pass;
oArgs.register = true;
oArgs.secure = true;
oArgs.xmllang = XML_LANG;
con.connect(oArgs);
// We change the registered information text
$('#home .homediv.registerer').append(
'<div class="info success">' +
_e("You have been registered, here is your XMPP address:") + ' <b>' + con.username.htmlEnc() + '@' + con.domain.htmlEnc() + '</b> - <a href="#">' + _e("Login") + '</a>' +
'</div>'
);
// Login link
$('#home .homediv.registerer .success a').click(function() {
return doLogin(con.username, con.domain, con.pass, con.resource, '10', false);
});
// Show the waiting image
showGeneralWait();
// Change the page title
pageTitle('wait');
}
catch(e) {
// Logs errors
logThis(e, 1);
}
finally {
return false;
}
}
// Does the user anonymous login
function doAnonymous() {
logThis('Trying to login anonymously...', 3);
var aPath = '#home .anonymouser ';
var room = $(aPath + '.room').val();
var nick = $(aPath + '.nick').val();
// If the form is correctly completed
if(room && nick) {
// We remove the not completed class to avoid problems
$('#home .anonymouser input').removeClass('please-complete');
// Redirect the user to the anonymous room
window.location.href = JAPPIX_LOCATION + '?r=' + room + '&n=' + nick;
}
// We check if the form is entirely completed
else {
$(aPath + 'input[type=text]').each(function() {
var select = $(this);
if(!select.val())
$(document).oneTime(10, function() {
select.addClass('please-complete').focus();
});
else
select.removeClass('please-complete');
});
}
return false;
}
// Handles the user connected event
var CONNECTED = false;
function handleConnected() {
logThis('Jappix is now connected.', 3);
// Connection markers
CONNECTED = true;
RECONNECT_TRY = 0;
RECONNECT_TIMER = 0;
// We hide the home page
$('#home').hide();
// Not resumed?
if(!RESUME) {
// Remember the session?
if(getDB('remember', 'session'))
setPersistent('session', 1, CURRENT_SESSION);
// We show the chatting app.
createTalkPage();
// We reset the homepage
switchHome('default');
// We get all the other things
getEverything();
// Set last activity stamp
LAST_ACTIVITY = getTimeStamp();
}
// Resumed
else {
// Send our presence
presenceSend();
// Change the title
updateTitle();
}
// Remove the waiting item
removeGeneralWait();
}
// Handles the user disconnected event
function handleDisconnected() {
logThis('Jappix is now disconnected.', 3);
// Normal disconnection
if(!CURRENT_SESSION && !CONNECTED)
destroyTalkPage();
}
// Setups the normal connection
function setupCon(con) {
// We setup all the necessary handlers for the connection
con.registerHandler('message', handleMessage);
con.registerHandler('presence', handlePresence);
con.registerHandler('iq', handleIQ);
con.registerHandler('onconnect', handleConnected);
con.registerHandler('onerror', handleError);
con.registerHandler('ondisconnect', handleDisconnected);
}
// Logouts from the server
function logout() {
// We are not connected
if(!isConnected())
return false;
// Disconnect from the XMPP server
con.disconnect();
logThis('Jappix is disconnecting...', 3);
}
// Terminates a session
function terminate() {
if(!isConnected())
return;
// Clear temporary session storage
resetConMarkers();
// Show the waiting item (useful if BOSH is sloooow)
showGeneralWait();
// Change the page title
pageTitle('wait');
// Disconnect from the XMPP server
logout();
}
// Quitss a session
function quit() {
if(!isConnected())
return;
// We show the waiting image
showGeneralWait();
// Change the page title
pageTitle('wait');
// We disconnect from the XMPP server
logout();
}
// Creates the reconnect pane
var RECONNECT_TRY = 0;
var RECONNECT_TIMER = 0;
function createReconnect(mode) {
logThis('This is not a normal disconnection, show the reconnect pane...', 1);
// Reconnect pane not yet displayed?
if(!exists('#reconnect')) {
// Blur the focused input/textarea/select
$('input, select, textarea').blur();
// Create the HTML code
var html = '<div id="reconnect" class="lock">' +
'<div class="pane">' +
_e("Due to a network issue, you were disconnected. What do you want to do now?");
// Can we cancel reconnection?
if(mode == 'normal')
html += '<a href="#" class="finish cancel">' + _e("Cancel") + '</a>';
html += '<a href="#" class="finish reconnect">' + _e("Reconnect") + '</a>' +
'</div></div>';
// Append the code
$('body').append(html);
// Click events
if(mode == 'normal')
$('#reconnect a.finish.cancel').click(function() {
return cancelReconnect();
});
$('#reconnect a.finish.reconnect').click(function() {
return acceptReconnect(mode);
});
// Try to reconnect automatically after a while
if(RECONNECT_TRY < 5)
RECONNECT_TIMER = 5 + (5 * RECONNECT_TRY);
else
RECONNECT_TIMER = 120;
// Change the try number
RECONNECT_TRY++;
// Fire the event!
$('#reconnect a.finish.reconnect').everyTime('1s', function() {
// We can reconnect!
if(RECONNECT_TIMER == 0)
return acceptReconnect(mode);
// Button text
if(RECONNECT_TIMER <= 10)
$(this).text(_e("Reconnect") + ' (' + RECONNECT_TIMER + ')');
// Remove 1 second
RECONNECT_TIMER--;
});
// Page title
updateTitle();
}
}
// Reconnects the user if he was disconnected (network issue)
var RESUME = false;
function acceptReconnect(mode) {
logThis('Trying to reconnect the user...', 3);
// Resume marker
RESUME = true;
// Show waiting item
showGeneralWait();
// Reset some various stuffs
var groupchats = '#page-engine .page-engine-chan[data-type=groupchat]';
$(groupchats + ' .list .role').hide();
$(groupchats + ' .one-group, ' + groupchats + ' .list .user').remove();
$(groupchats).attr('data-initial', 'false');
// Stop the timer
$('#reconnect a.finish.reconnect').stopTime();
// Remove the reconnect pane
$('#reconnect').remove();
// Try to login again
if(mode == 'normal')
loginFromSession(XMLFromString(CURRENT_SESSION));
else if(mode == 'anonymous')
anonymousLogin(HOST_ANONYMOUS);
return false;
}
// Cancel the reconnection of user account (network issue)
function cancelReconnect() {
logThis('User has canceled automatic reconnection...', 3);
// Stop the timer
$('#reconnect a.finish.reconnect').stopTime();
// Remove the reconnect pane
$('#reconnect').remove();
// Destroy the talk page
destroyTalkPage();
// Renitialize the previous session parameters
resetConMarkers();
return false;
}
// Clears session reminder database
function clearLastSession() {
// Clear temporary storage
resetConMarkers();
// Clear persistent storage
if($(XMLFromString(getPersistent('session', 1))).find('stored').text() == 'true')
removePersistent('session', 1);
}
// Resets the connection markers
function resetConMarkers() {
CURRENT_SESSION = false;
CONNECTED = false;
RESUME = false;
RECONNECT_TRY = 0;
RECONNECT_TIMER = 0;
}
// Logins from a saved session
function loginFromSession(data) {
// Select the data
var session = $(data);
// Fire the login event
doLogin(
session.find('username').text(),
session.find('domain').text(),
session.find('password').text(),
session.find('resource').text(),
session.find('priority').text(),
false
);
}
// Quits a session normally
function normalQuit() {
// Reset our database
clearLastSession();
// We quit the current session
quit();
// We show an info
openThisInfo(3);
return false;
}
// Gets all the users stuffs
function getEverything() {
getFeatures();
getRoster();
listPrivacy();
getStorage(NS_ROSTERNOTES);
}
// Plugin launcher
function launchConnection() {
// Logouts when Jappix is closed
$(window).bind('beforeunload', terminate);
// Nothing to do when anonymous!
if(isAnonymous())
return;
// Try to resume a stored session, if not anonymous
var session = XMLFromString(getPersistent('session', 1));
if($(session).find('stored').text() == 'true') {
// Hide the homepage
$('#home').hide();
// Show the waiting icon
showGeneralWait();
// Login!
loginFromSession(session);
logThis('Saved session found, resuming it...', 3);
}
// Not connected, maybe a XMPP link is submitted?
else if((parent.location.hash != '#OK') && LINK_VARS['x']) {
switchHome('loginer');
logThis('A XMPP link is set, switch to login page.', 3);
}
}
// Launch this plugin!
$(document).ready(launchConnection);

View file

@ -0,0 +1,211 @@
/*
Jappix - An open social platform
These are the constants JS scripts for Jappix
-------------------------------------------------
License: AGPL
Authors: Stefan Strigler, Vanaryon
Last revision: 26/08/11
*/
// XMPP XMLNS attributes
var NS_PROTOCOL = 'http://jabber.org/protocol/';
var NS_FEATURES = 'http://jabber.org/features/';
var NS_CLIENT = 'jabber:client';
var NS_IQ = 'jabber:iq:';
var NS_X = 'jabber:x:';
var NS_IETF = 'urn:ietf:params:xml:ns:xmpp-';
var NS_XMPP = 'urn:xmpp:';
var NS_STORAGE = 'storage:';
var NS_BOOKMARKS = NS_STORAGE + 'bookmarks';
var NS_ROSTERNOTES = NS_STORAGE + 'rosternotes';
var NS_JAPPIX = 'jappix:';
var NS_INBOX = NS_JAPPIX + 'inbox';
var NS_OPTIONS = NS_JAPPIX + 'options';
var NS_DISCO_ITEMS = NS_PROTOCOL + 'disco#items';
var NS_DISCO_INFO = NS_PROTOCOL + 'disco#info';
var NS_VCARD = 'vcard-temp';
var NS_VCARD_P = NS_VCARD + ':x:update';
var NS_AUTH = NS_IQ + 'auth';
var NS_AUTH_ERROR = NS_IQ + 'auth:error';
var NS_REGISTER = NS_IQ + 'register';
var NS_SEARCH = NS_IQ + 'search';
var NS_ROSTER = NS_IQ + 'roster';
var NS_PRIVACY = NS_IQ + 'privacy';
var NS_PRIVATE = NS_IQ + 'private';
var NS_VERSION = NS_IQ + 'version';
var NS_TIME = NS_IQ + 'time';
var NS_LAST = NS_IQ + 'last';
var NS_IQDATA = NS_IQ + 'data';
var NS_XDATA = NS_X + 'data';
var NS_IQOOB = NS_IQ + 'oob';
var NS_XOOB = NS_X + 'oob';
var NS_DELAY = NS_X + 'delay';
var NS_EXPIRE = NS_X + 'expire';
var NS_EVENT = NS_X + 'event';
var NS_XCONFERENCE = NS_X + 'conference';
var NS_STATS = NS_PROTOCOL + 'stats';
var NS_MUC = NS_PROTOCOL + 'muc';
var NS_MUC_USER = NS_MUC + '#user';
var NS_MUC_ADMIN = NS_MUC + '#admin';
var NS_MUC_OWNER = NS_MUC + '#owner';
var NS_MUC_CONFIG = NS_MUC + '#roomconfig';
var NS_PUBSUB = NS_PROTOCOL + 'pubsub';
var NS_PUBSUB_EVENT = NS_PUBSUB + '#event';
var NS_PUBSUB_OWNER = NS_PUBSUB + '#owner';
var NS_PUBSUB_NMI = NS_PUBSUB + '#node-meta-info';
var NS_PUBSUB_NC = NS_PUBSUB + '#node_config';
var NS_PUBSUB_RI = NS_PUBSUB + '#retrieve-items';
var NS_COMMANDS = NS_PROTOCOL + 'commands';
var NS_BOSH = NS_PROTOCOL + 'httpbind';
var NS_STREAM = 'http://etherx.jabber.org/streams';
var NS_URN_TIME = NS_XMPP + 'time';
var NS_URN_PING = NS_XMPP + 'ping';
var NS_URN_ADATA = NS_XMPP + 'avatar:data';
var NS_URN_AMETA = NS_XMPP + 'avatar:metadata';
var NS_URN_MBLOG = NS_XMPP + 'microblog:0';
var NS_URN_INBOX = NS_XMPP + 'inbox';
var NS_URN_ARCHIVE = NS_XMPP + 'archive';
var NS_URN_AR_PREF = NS_URN_ARCHIVE + ':pref';
var NS_URN_AR_AUTO = NS_URN_ARCHIVE + ':auto';
var NS_URN_AR_MANUAL = NS_URN_ARCHIVE + ':manual';
var NS_URN_AR_MANAGE = NS_URN_ARCHIVE + ':manage';
var NS_URN_DELAY = NS_XMPP + 'delay';
var NS_URN_RECEIPTS = NS_XMPP + 'receipts';
var NS_RSM = NS_PROTOCOL + 'rsm';
var NS_IPV6 = 'ipv6';
var NS_XHTML = 'http://www.w3.org/1999/xhtml';
var NS_XHTML_IM = NS_PROTOCOL + 'xhtml-im';
var NS_CHATSTATES = NS_PROTOCOL + 'chatstates';
var NS_HTTP_AUTH = NS_PROTOCOL + 'http-auth';
var NS_ROSTERX = NS_PROTOCOL + 'rosterx';
var NS_MOOD = NS_PROTOCOL + 'mood';
var NS_ACTIVITY = NS_PROTOCOL + 'activity';
var NS_TUNE = NS_PROTOCOL + 'tune';
var NS_GEOLOC = NS_PROTOCOL + 'geoloc';
var NS_NICK = NS_PROTOCOL + 'nick';
var NS_NOTIFY = '+notify';
var NS_CAPS = NS_PROTOCOL + 'caps';
var NS_ATOM = 'http://www.w3.org/2005/Atom';
var NS_STANZAS = NS_IETF + 'stanzas';
var NS_STREAMS = NS_IETF + 'streams';
var NS_TLS = NS_IETF + 'tls';
var NS_SASL = NS_IETF + 'sasl';
var NS_SESSION = NS_IETF + 'session';
var NS_BIND = NS_IETF + 'bind';
var NS_FEATURE_IQAUTH = NS_FEATURES + 'iq-auth';
var NS_FEATURE_IQREGISTER = NS_FEATURES + 'iq-register';
var NS_FEATURE_COMPRESS = NS_FEATURES + 'compress';
var NS_COMPRESS = NS_PROTOCOL + 'compress';
// Available locales
var LOCALES_AVAILABLE_ID = new Array();
var LOCALES_AVAILABLE_NAMES = new Array();
// XML lang
var XML_LANG = null;
// Jappix parameters
var JAPPIX_STATIC = null;
var JAPPIX_VERSION = null;
var JAPPIX_MAX_FILE_SIZE = null;
var JAPPIX_MAX_UPLOAD = null;
// Jappix main configuration
var SERVICE_NAME = null;
var SERVICE_DESC = null;
var JAPPIX_RESOURCE = null;
var LOCK_HOST = null;
var ANONYMOUS = null;
var REGISTRATION = null;
var BOSH_PROXY = null;
var MANAGER_LINK = null;
var GROUPCHATS_JOIN = null;
var ENCRYPTION = null;
var HTTPS_STORAGE = null;
var HTTPS_FORCE = null;
var COMPRESSION = null;
var MULTI_FILES = null;
var DEVELOPER = null;
// Jappix hosts configuration
var HOST_MAIN = null;
var HOST_MUC = null;
var HOST_PUBSUB = null;
var HOST_VJUD = null;
var HOST_ANONYMOUS = null;
var HOST_BOSH = null;
var HOST_BOSH_MAIN = null;
var HOST_BOSH_MINI = null;
var HOST_STATIC = null;
var HOST_UPLOAD = null;
// Anonymous mode
var ANONYMOUS_ROOM = null;
var ANONYMOUS_NICK = null;
// Node parameters
var JAPPIX_LOCATION = getJappixLocation();
// XMPP error stanzas
function STANZA_ERROR(code, type, cond) {
if (window == this)
return new STANZA_ERROR(code, type, cond);
this.code = code;
this.type = type;
this.cond = cond;
}
var ERR_BAD_REQUEST =
STANZA_ERROR('400', 'modify', 'bad-request');
var ERR_CONFLICT =
STANZA_ERROR('409', 'cancel', 'conflict');
var ERR_FEATURE_NOT_IMPLEMENTED =
STANZA_ERROR('501', 'cancel', 'feature-not-implemented');
var ERR_FORBIDDEN =
STANZA_ERROR('403', 'auth', 'forbidden');
var ERR_GONE =
STANZA_ERROR('302', 'modify', 'gone');
var ERR_INTERNAL_SERVER_ERROR =
STANZA_ERROR('500', 'wait', 'internal-server-error');
var ERR_ITEM_NOT_FOUND =
STANZA_ERROR('404', 'cancel', 'item-not-found');
var ERR_JID_MALFORMED =
STANZA_ERROR('400', 'modify', 'jid-malformed');
var ERR_NOT_ACCEPTABLE =
STANZA_ERROR('406', 'modify', 'not-acceptable');
var ERR_NOT_ALLOWED =
STANZA_ERROR('405', 'cancel', 'not-allowed');
var ERR_NOT_AUTHORIZED =
STANZA_ERROR('401', 'auth', 'not-authorized');
var ERR_PAYMENT_REQUIRED =
STANZA_ERROR('402', 'auth', 'payment-required');
var ERR_RECIPIENT_UNAVAILABLE =
STANZA_ERROR('404', 'wait', 'recipient-unavailable');
var ERR_REDIRECT =
STANZA_ERROR('302', 'modify', 'redirect');
var ERR_REGISTRATION_REQUIRED =
STANZA_ERROR('407', 'auth', 'registration-required');
var ERR_REMOTE_SERVER_NOT_FOUND =
STANZA_ERROR('404', 'cancel', 'remote-server-not-found');
var ERR_REMOTE_SERVER_TIMEOUT =
STANZA_ERROR('504', 'wait', 'remote-server-timeout');
var ERR_RESOURCE_CONSTRAINT =
STANZA_ERROR('500', 'wait', 'resource-constraint');
var ERR_SERVICE_UNAVAILABLE =
STANZA_ERROR('503', 'cancel', 'service-unavailable');
var ERR_SUBSCRIPTION_REQUIRED =
STANZA_ERROR('407', 'auth', 'subscription-required');
var ERR_UNEXPECTED_REQUEST =
STANZA_ERROR('400', 'wait', 'unexpected-request');

View file

@ -0,0 +1,921 @@
/*
Jappix - An open social platform
These are the dataform JS scripts for Jappix
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 28/08/11
*/
// Gets the defined dataform elements
function dataForm(host, type, node, action, target) {
// Clean the current session
cleanDataForm(target);
// We tell the user that a search has been launched
$('#' + target + ' .wait').show();
// If we have enough data
if(host && type) {
// Generate a session ID
var sessionID = Math.round(100000.5 + (((900000.49999) - (100000.5)) * Math.random()));
var id = target + '-' + sessionID + '-' + genID();
$('.' + target + '-results').attr('data-session', target + '-' + sessionID);
// We request the service item
var iq = new JSJaCIQ();
iq.setID(id);
iq.setTo(host);
iq.setType('get');
// MUC admin query
if(type == 'muc') {
iq.setQuery(NS_MUC_OWNER);
con.send(iq, handleDataFormMuc);
}
// Browse query
else if(type == 'browse') {
var iqQuery = iq.setQuery(NS_DISCO_ITEMS);
if(node)
iqQuery.setAttribute('node', node);
con.send(iq, handleDataFormBrowse);
}
// Command
else if(type == 'command') {
var items;
if(node)
items = iq.appendNode('command', {'node': node, 'xmlns': NS_COMMANDS});
else {
items = iq.setQuery(NS_DISCO_ITEMS);
items.setAttribute('node', NS_COMMANDS);
}
if(action && node) {
iq.setType('set');
items.setAttribute('action', action);
}
con.send(iq, handleDataFormCommand);
}
// Search query
else if(type == 'search') {
iq.setQuery(NS_SEARCH);
con.send(iq, handleDataFormSearch);
}
// Subscribe query
else if(type == 'subscribe') {
iq.setQuery(NS_REGISTER);
con.send(iq, handleDataFormSubscribe);
}
// Join
else if(type == 'join') {
if(target == 'discovery')
closeDiscovery();
checkChatCreate(host, 'groupchat');
}
}
return false;
}
// Sends a given dataform
function sendDataForm(type, action, x_type, id, xid, node, sessionid, target) {
// Path
var pathID = '#' + target + ' .results[data-session=' + id + ']';
// New IQ
var iq = new JSJaCIQ();
iq.setTo(xid);
iq.setType('set');
// Set the correct query
var query;
if(type == 'subscribe')
iqQuery = iq.setQuery(NS_REGISTER);
else if(type == 'search')
iqQuery = iq.setQuery(NS_SEARCH);
else if(type == 'command')
iqQuery = iq.appendNode('command', {'xmlns': NS_COMMANDS, 'node': node, 'sessionid': sessionid, 'action': action});
else if(type == 'x')
iqQuery = iq.setQuery(NS_MUC_OWNER);
// Build the XML document
if(action != 'cancel') {
// No X node
if(exists('input.register-special') && (type == 'subscribe')) {
$('input.register-special').each(function() {
var iName = $(this).attr('name');
var iValue = $(this).val();
iqQuery.appendChild(iq.buildNode(iName, {'xmlns': NS_REGISTER}, iValue));
});
}
// Can create the X node
else {
var iqX = iqQuery.appendChild(iq.buildNode('x', {'xmlns': NS_XDATA, 'type': x_type}));
// Each input
$(pathID + ' .oneresult input, ' + pathID + ' .oneresult textarea, ' + pathID + ' .oneresult select').each(function() {
// Get the current input value
var iVar = $(this).attr('name');
var iType = $(this).attr('data-type');
var iValue = $(this).val();
// Build a new field node
var field = iqX.appendChild(iq.buildNode('field', {'var': iVar, 'type': iType, 'xmlns': NS_XDATA}));
// Boolean input?
if(iType == 'boolean') {
if($(this).filter(':checked').size())
iValue = '1';
else
iValue = '0';
}
// JID-multi input?
if(iType == 'jid-multi') {
// Values array
var xid_arr = [iValue];
var xid_check = [];
// Try to split it
if(iValue.indexOf(',') != -1)
xid_arr = iValue.split(',');
// Append each value to the XML document
for(i in xid_arr) {
// Get the current value
xid_current = trim(xid_arr[i]);
// No current value?
if(!xid_current)
continue;
// Add the current value
if(!existArrayValue(xid_check, xid_current)) {
xid_check.push(xid_current);
field.appendChild(iq.buildNode('value', {'xmlns': NS_XDATA}, xid_current));
}
}
}
// List-multi selector?
else if(iType == 'list-multi') {
// Any value?
if(iValue && iValue.length) {
for(i in iValue)
field.appendChild(iq.buildNode('value', {'xmlns': NS_XDATA}, iValue[i]));
}
}
// Other inputs?
else
field.appendChild(iq.buildNode('value', {'xmlns': NS_XDATA}, iValue));
});
}
}
// Clean the current session
cleanDataForm(target);
// Show the waiting item
$('#' + target + ' .wait').show();
// Change the ID of the current discovered item
var iqID = target + '-' + genID();
$('#' + target + ' .' + target + '-results').attr('data-session', iqID);
iq.setID(iqID);
// Send the IQ
if(type == 'subscribe')
con.send(iq, handleDataFormSubscribe);
else if(type == 'search')
con.send(iq, handleDataFormSearch);
else if(type == 'command')
con.send(iq, handleDataFormCommand);
else
con.send(iq);
return false;
}
// Displays the good dataform buttons
function buttonsDataForm(type, action, id, xid, node, sessionid, target, pathID) {
// No need to use buttons?
if(type == 'muc')
return;
// Override the "undefined" output
if(!id)
id = '';
if(!xid)
xid = '';
if(!node)
node = '';
if(!sessionid)
sessionid = '';
// We generate the buttons code
var buttonsCode = '<div class="oneresult ' + target + '-oneresult ' + target + '-formtools">';
if(action == 'submit') {
if((target == 'adhoc') && (type == 'command')) {
buttonsCode += '<a href="#" class="submit" onclick="return sendDataForm(\'' + encodeOnclick(type) + '\', \'execute\', \'submit\', \'' + encodeOnclick(id) + '\', \'' + encodeOnclick(xid) + '\', \'' + encodeOnclick(node) + '\', \'' + encodeOnclick(sessionid) + '\', \'' + encodeOnclick(target) + '\');">' + _e("Submit") + '</a>';
// When keyup on one text input
$(pathID + ' input').keyup(function(e) {
if(e.keyCode == 13) {
sendDataForm(type, 'execute', 'submit', id, xid, node, sessionid, target);
return false;
}
});
}
else {
buttonsCode += '<a href="#" class="submit" onclick="return sendDataForm(\'' + encodeOnclick(type) + '\', \'submit\', \'submit\', \'' + encodeOnclick(id) + '\', \'' + encodeOnclick(xid) + '\', \'' + encodeOnclick(node) + '\', \'' + encodeOnclick(sessionid) + '\', \'' + encodeOnclick(target) + '\');">' + _e("Submit") + '</a>';
// When keyup on one text input
$(pathID + ' input').keyup(function(e) {
if(e.keyCode == 13) {
sendDataForm(type, 'submit', 'submit', id, xid, node, sessionid, target);
return false;
}
});
}
}
if((action == 'submit') && (type != 'subscribe') && (type != 'search'))
buttonsCode += '<a href="#" class="submit" onclick="return sendDataForm(\'' + encodeOnclick(type) + '\', \'cancel\', \'cancel\', \'' + encodeOnclick(id) + '\', \'' + encodeOnclick(xid) + '\', \'' + encodeOnclick(node) + '\', \'' + encodeOnclick(sessionid) + '\', \'' + encodeOnclick(target) + '\');">' + _e("Cancel") + '</a>';
if(((action == 'back') || (type == 'subscribe') || (type == 'search')) && (target == 'discovery'))
buttonsCode += '<a href="#" class="back" onclick="return startDiscovery();">' + _e("Close") + '</a>';
if((action == 'back') && ((target == 'welcome') || (target == 'directory')))
buttonsCode += '<a href="#" class="back" onclick="return dataForm(HOST_VJUD, \'search\', \'\', \'\', \'' + target + '\');">' + _e("Previous") + '</a>';
if((action == 'back') && (target == 'adhoc'))
buttonsCode += '<a href="#" class="back" onclick="return dataForm(\'' + encodeOnclick(xid) + '\', \'command\', \'\', \'\', \'adhoc\');">' + _e("Previous") + '</a>';
buttonsCode += '</div>';
// We display the buttons code
$(pathID).append(buttonsCode);
// If no submit link, lock the form
if(!exists(pathID + ' a.submit'))
$(pathID + ' input, ' + pathID + ' textarea').attr('readonly', true);
}
// Handles the MUC dataform
function handleDataFormMuc(iq) {
handleErrorReply(iq);
handleDataFormContent(iq, 'muc');
}
// Handles the browse dataform
function handleDataFormBrowse(iq) {
handleErrorReply(iq);
handleDataFormContent(iq, 'browse');
}
// Handles the command dataform
function handleDataFormCommand(iq) {
handleErrorReply(iq);
handleDataFormContent(iq, 'command');
}
// Handles the subscribe dataform
function handleDataFormSubscribe(iq) {
handleErrorReply(iq);
handleDataFormContent(iq, 'subscribe');
}
// Handles the search dataform
function handleDataFormSearch(iq) {
handleErrorReply(iq);
handleDataFormContent(iq, 'search');
}
// Handles the dataform content
function handleDataFormContent(iq, type) {
// Get the ID
var sID = iq.getID();
// Get the target
var splitted = sID.split('-');
var target = splitted[0];
var sessionID = target + '-' + splitted[1];
var from = fullXID(getStanzaFrom(iq));
var pathID = '#' + target + ' .results[data-session=' + sessionID + ']';
// If an error occured
if(!iq || (iq.getType() != 'result'))
noResultDataForm(pathID);
// If we got something okay
else {
var handleXML = iq.getNode();
if(type == 'browse') {
if($(handleXML).find('item').attr('jid')) {
// Get the query node
var queryNode = $(handleXML).find('query').attr('node');
$(handleXML).find('item').each(function() {
// We parse the received xml
var itemHost = $(this).attr('jid');
var itemNode = $(this).attr('node');
var itemName = $(this).attr('name');
var itemHash = hex_md5(itemHost);
// Node
if(itemNode)
$(pathID).append(
'<div class="oneresult ' + target + '-oneresult" onclick="return dataForm(\'' + encodeOnclick(itemHost) + '\', \'browse\', \'' + encodeOnclick(itemNode) + '\', \'\', \'' + encodeOnclick(target) + '\');">' +
'<div class="one-name">' + itemNode.htmlEnc() + '</div>' +
'</div>'
);
// Item
else if(queryNode && itemName)
$(pathID).append(
'<div class="oneresult ' + target + '-oneresult">' +
'<div class="one-name">' + itemName.htmlEnc() + '</div>' +
'</div>'
);
// Item with children
else {
// We display the waiting element
$(pathID + ' .disco-wait .disco-category-title').after(
'<div class="oneresult ' + target + '-oneresult ' + itemHash + '">' +
'<div class="one-icon loading talk-images"></div>' +
'<div class="one-host">' + itemHost + '</div>' +
'<div class="one-type">' + _e("Requesting this service...") + '</div>' +
'</div>'
);
// We display the category
$('#' + target + ' .disco-wait').show();
// We ask the server what's the service type
getDataFormType(itemHost, itemNode, sessionID);
}
});
}
// Else, there are no items for this query
else
noResultDataForm(pathID);
}
else if((type == 'muc') || (type == 'search') || (type == 'subscribe') || ((type == 'command') && $(handleXML).find('command').attr('xmlns'))) {
// Get some values
var xCommand = $(handleXML).find('command');
var bNode = xCommand.attr('node');
var bSession = xCommand.attr('sessionid');
var bStatus = xCommand.attr('status');
var xRegister = $(handleXML).find('query[xmlns=' + NS_REGISTER + ']').text();
var xElement = $(handleXML).find('x');
// Search done
if((xElement.attr('type') == 'result') && (type == 'search')) {
var bPath = pathID;
// Display the result
$(handleXML).find('item').each(function() {
var bXID = $(this).find('field[var=jid] value:first').text();
var bName = $(this).find('field[var=fn] value:first').text();
var bCountry = $(this).find('field[var=ctry] value:first').text();
var dName = bName;
// Override "undefined" value
if(!bXID)
bXID = '';
if(!bName)
bName = _e("Unknown name");
if(!bCountry)
bCountry = _e("Unknown country");
// User hash
var bHash = hex_md5(bXID);
// HTML code
var bHTML = '<div class="oneresult ' + target + '-oneresult ' + bHash + '">' +
'<div class="avatar-container">' +
'<img class="avatar" src="' + './img/others/default-avatar.png' + '" alt="" />' +
'</div>' +
'<div class="one-fn">' + bName + '</div>' +
'<div class="one-ctry">' + bCountry + '</div>' +
'<div class="one-jid">' + bXID + '</div>' +
'<div class="buttons-container">';
// The buddy is not in our buddy list?
if(!exists('#buddy-list .buddy[data-xid=' + escape(bXID) + ']'))
bHTML += '<a href="#" class="one-add one-vjud one-button talk-images">' + _e("Add") + '</a>';
// Chat button, if not in welcome/directory mode
if(target == 'discovery')
bHTML += '<a href="#" class="one-chat one-vjud one-button talk-images">' + _e("Chat") + '</a>';
// Close the HTML element
bHTML += '</div></div>';
$(bPath).append(bHTML);
// Click events
$(bPath + ' .' + bHash + ' a').click(function() {
// Buddy add
if($(this).is('.one-add')) {
$(this).hide();
addThisContact(bXID, dName);
}
// Buddy chat
if($(this).is('.one-chat')) {
if(target == 'discovery')
closeDiscovery();
checkChatCreate(bXID , 'chat', '', '', dName);
}
return false;
});
// Get the user's avatar
if(bXID)
getAvatar(bXID, 'cache', 'true', 'forget');
});
// No result?
if(!$(handleXML).find('item').size())
noResultDataForm(pathID);
// Previous button
buttonsDataForm(type, 'back', sessionID, from, bNode, bSession, target, pathID);
}
// Command to complete
else if(xElement.attr('xmlns') || ((type == 'subscribe') && xRegister)) {
// We display the elements
fillDataForm(handleXML, sessionID);
// We display the buttons
if(bStatus != 'completed')
buttonsDataForm(type, 'submit', sessionID, from, bNode, bSession, target, pathID);
else
buttonsDataForm(type, 'back', sessionID, from, bNode, bSession, target, pathID);
}
// Command completed or subscription done
else if(((bStatus == 'completed') && (type == 'command')) || (!xRegister && (type == 'subscribe'))) {
// Display the good text
var cNote = $(xCommand).find('note');
// Any note?
if(cNote.size()) {
cNote.each(function() {
$(pathID).append(
'<div class="onetitle ' + target + '-oneresult">' + $(this).text().htmlEnc() + '</div>'
);
});
}
// Default text
else
$(pathID).append('<div class="oneinstructions ' + target + '-oneresult">' + _e("Your form has been sent.") + '</div>');
// Display the back button
buttonsDataForm(type, 'back', sessionID, from, '', '', target, pathID);
// Add the gateway to our roster if subscribed
if(type == 'subscribe')
addThisContact(from);
}
// Command canceled
else if((bStatus == 'canceled') && (type == 'command')) {
if(target == 'discovery')
startDiscovery();
else if(target == 'adhoc')
dataForm(from, 'command', '', '', 'adhoc');
}
// No items for this query
else
noResultDataForm(pathID);
}
else if(type == 'command') {
if($(handleXML).find('item').attr('jid')) {
// We display the elements
$(handleXML).find('item').each(function() {
// We parse the received xml
var itemHost = $(this).attr('jid');
var itemNode = $(this).attr('node');
var itemName = $(this).attr('name');
var itemHash = hex_md5(itemHost);
// We display the waiting element
$(pathID).prepend(
'<div class="oneresult ' + target + '-oneresult ' + itemHash + '" onclick="return dataForm(\'' + encodeOnclick(itemHost) + '\', \'command\', \'' + encodeOnclick(itemNode) + '\', \'execute\', \'' + encodeOnclick(target) + '\');">' +
'<div class="one-name">' + itemName + '</div>' +
'<div class="one-next">»</div>' +
'</div>'
);
});
}
// Else, there are no items for this query
else
noResultDataForm(pathID);
}
}
// Focus on the first input
$(document).oneTime(10, function() {
$(pathID + ' input:visible:first').focus();
});
// Hide the wait icon
$('#' + target + ' .wait').hide();
}
// Fills the dataform elements
function fillDataForm(xml, id) {
/* REF: http://xmpp.org/extensions/xep-0004.html */
// Initialize new vars
var target = id.split('-')[0];
var pathID = '#' + target + ' .results[data-session=' + id + ']';
var selector, is_dataform;
// Is it a dataform?
if($(xml).find('x[xmlns=' + NS_XDATA + ']').size())
is_dataform = true;
else
is_dataform = false;
// Determines the good selector to use
if(is_dataform)
selector = $(xml).find('x[xmlns=' + NS_XDATA + ']');
else
selector = $(xml);
// Form title
selector.find('title').each(function() {
$(pathID).append(
'<div class="onetitle ' + target + '-oneresult">' + $(this).text().htmlEnc() + '</div>'
);
});
// Form instructions
selector.find('instructions').each(function() {
$(pathID).append(
'<div class="oneinstructions ' + target + '-oneresult">' + $(this).text().htmlEnc() + '</div>'
);
});
// Register?
if(!is_dataform) {
// Items to detect
var reg_names = [_e("Nickname"), _e("Name"), _e("Password"), _e("E-mail")];
var reg_ids = ['username', 'name', 'password', 'email'];
// Append these inputs
for(a in reg_names) {
selector.find(reg_ids[a]).each(function() {
$(pathID).append(
'<div class="oneresult ' + target + '-oneresult">' +
'<label>' + reg_names[a] + '</label>' +
'<input name="' + reg_ids[a] + '" type="text" class="register-special dataform-i" />' +
'</div>'
);
});
}
return false;
}
// Dataform?
selector.find('field').each(function() {
// We parse the received xml
var type = $(this).attr('type');
var label = $(this).attr('label');
var field = $(this).attr('var');
var value = $(this).find('value:first').text();
var required = '';
// No value?
if(!field)
return;
// Required input?
if($(this).find('required').size())
required = ' required=""';
// Compatibility fix
if(!label)
label = field;
if(!type)
type = '';
// Generate some values
var input;
var hideThis = '';
// Fixed field
if(type == 'fixed')
$(pathID).append('<div class="oneinstructions">' + value.htmlEnc() + '</div>');
else {
// Hidden field
if(type == 'hidden') {
hideThis = ' style="display: none;"';
input = '<input name="' + encodeQuotes(field) + '" data-type="' + encodeQuotes(type) + '" type="hidden" class="dataform-i" value="' + encodeQuotes(value) + '" ' + required + ' />';
}
// Boolean field
else if(type == 'boolean') {
var checked;
if(value == '1')
checked = 'checked';
else
checked = '';
input = '<input name="' + encodeQuotes(field) + '" type="checkbox" data-type="' + encodeQuotes(type) + '" class="dataform-i df-checkbox" ' + checked + required + ' />';
}
// List-single/list-multi field
else if((type == 'list-single') || (type == 'list-multi')) {
var multiple = '';
// Multiple options?
if(type == 'list-multi')
multiple = ' multiple=""';
// Append the select field
input = '<select name="' + encodeQuotes(field) + '" data-type="' + encodeQuotes(type) + '" class="dataform-i"' + required + multiple + '>';
var selected;
// Append the available options
$(this).find('option').each(function() {
var nLabel = $(this).attr('label');
var nValue = $(this).find('value').text();
// No label?
if(!nLabel)
nLabel = nValue;
// If this is the selected value
if(nValue == value)
selected = 'selected';
else
selected = '';
input += '<option ' + selected + ' value="' + encodeQuotes(nValue) + '">' + nLabel.htmlEnc() + '</option>';
});
input += '</select>';
}
// Text-multi field
else if(type == 'text-multi')
input = '<textarea rows="8" cols="60" data-type="' + encodeQuotes(type) + '" name="' + encodeQuotes(field) + '" class="dataform-i"' + required + '>' + value.htmlEnc() + '</textarea>';
// JID-multi field
else if(type == 'jid-multi') {
// Put the XID into an array
var xid_arr = [];
$(this).find('value').each(function() {
var cValue = $(this).text();
if(!existArrayValue(xid_arr, cValue))
xid_arr.push(cValue);
});
// Sort the array
xid_arr.sort();
// Create the input
var xid_value = '';
if(xid_arr.length) {
for(i in xid_arr) {
// Any pre-value
if(xid_value)
xid_value += ', ';
// Add the current XID
xid_value += xid_arr[i];
}
}
input = '<input name="' + encodeQuotes(field) + '" data-type="' + encodeQuotes(type) + '" type="text" class="dataform-i" value="' + encodeQuotes(xid_value) + '" placeholder="jack@jappix.com, jones@jappix.com"' + required + ' />';
}
// Other stuffs that are similar
else {
// Text-single field
var iType = 'text';
// Text-private field
if(type == 'text-private')
iType = 'password';
// JID-single field
else if(type == 'jid-single')
iType = 'email';
input = '<input name="' + encodeQuotes(field) + '" data-type="' + encodeQuotes(type) + '" type="' + iType + '" class="dataform-i" value="' + encodeQuotes(value) + '"' + required + ' />';
}
// Append the HTML markup for this field
$(pathID).append(
'<div class="oneresult ' + target + '-oneresult"' + hideThis + '>' +
'<label>' + label.htmlEnc() + '</label>' +
input +
'</div>'
);
}
});
return false;
}
// Gets the dataform type
function getDataFormType(host, node, id) {
var iq = new JSJaCIQ();
iq.setID(id + '-' + genID());
iq.setTo(host);
iq.setType('get');
var iqQuery = iq.setQuery(NS_DISCO_INFO);
if(node)
iqQuery.setAttribute('node', node);
con.send(iq, handleThisBrowse);
}
// Handles the browse stanza
function handleThisBrowse(iq) {
/* REF: http://xmpp.org/registrar/disco-categories.html */
var id = iq.getID();
var splitted = id.split('-');
var target = splitted[0];
var sessionID = target + '-' + splitted[1];
var from = fullXID(getStanzaFrom(iq));
var hash = hex_md5(from);
var handleXML = iq.getQuery();
var pathID = '#' + target + ' .results[data-session=' + sessionID + ']';
// We first remove the waiting element
$(pathID + ' .disco-wait .' + hash).remove();
if($(handleXML).find('identity').attr('type')) {
var category = $(handleXML).find('identity').attr('category');
var type = $(handleXML).find('identity').attr('type');
var named = $(handleXML).find('identity').attr('name');
if(named)
gName = named;
else
gName = '';
var one, two, three, four, five;
// Get the features that this entity supports
var findFeature = $(handleXML).find('feature');
for(i in findFeature) {
var current = findFeature.eq(i).attr('var');
switch(current) {
case NS_SEARCH:
one = 1;
break;
case NS_MUC:
two = 1;
break;
case NS_REGISTER:
three = 1;
break;
case NS_COMMANDS:
four = 1;
break;
case NS_DISCO_ITEMS:
five = 1;
break;
default:
break;
}
}
var buttons = Array(one, two, three, four, five);
// We define the toolbox links depending on the supported features
var tools = '';
var aTools = Array('search', 'join', 'subscribe', 'command', 'browse');
var bTools = Array(_e("Search"), _e("Join"), _e("Subscribe"), _e("Command"), _e("Browse"));
for(i in buttons) {
if(buttons[i])
tools += '<a href="#" class="one-button ' + aTools[i] + ' talk-images" onclick="return dataForm(\'' + encodeOnclick(from) + '\', \'' + encodeOnclick(aTools[i]) + '\', \'\', \'\', \'' + encodeOnclick(target) + '\');" title="' + encodeOnclick(bTools[i]) + '"></a>';
}
// As defined in the ref, we detect the type of each category to put an icon
switch(category) {
case 'account':
case 'auth':
case 'automation':
case 'client':
case 'collaboration':
case 'component':
case 'conference':
case 'directory':
case 'gateway':
case 'headline':
case 'hierarchy':
case 'proxy':
case 'pubsub':
case 'server':
case 'store':
break;
default:
category = 'others';
}
// We display the item we found
$(pathID + ' .disco-' + category + ' .disco-category-title').after(
'<div class="oneresult ' + target + '-oneresult ' + hash + '">' +
'<div class="one-icon ' + category + ' talk-images"></div>' +
'<div class="one-host">' + from + '</div>' +
'<div class="one-type">' + gName + '</div>' +
'<div class="one-actions">' + tools + '</div>' +
'</div>'
);
// We display the category
$(pathID + ' .disco-' + category).show();
}
else {
$(pathID + ' .disco-others .disco-category-title').after(
'<div class="oneresult ' + target + '-oneresult">' +
'<div class="one-icon down talk-images"></div>' +
'<div class="one-host">' + from + '</div>' +
'<div class="one-type">' + _e("Service offline or broken") + '</div>' +
'</div>'
);
// We display the category
$(pathID + ' .disco-others').show();
}
// We hide the waiting stuffs if there's no remaining loading items
if(!$(pathID + ' .disco-wait .' + target + '-oneresult').size())
$(pathID + ' .disco-wait, #' + target + ' .wait').hide();
}
// Cleans the current data-form popup
function cleanDataForm(target) {
if(target == 'discovery')
cleanDiscovery();
else
$('#' + target + ' div.results').empty();
}
// Displays the no result indicator
function noResultDataForm(path) {
$(path).prepend('<p class="no-results">' + _e("Sorry, but the entity didn't return any result!") + '</p>');
}

View file

@ -0,0 +1,209 @@
/*
Jappix - An open social platform
These are the temporary/persistent data store functions
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 23/06/11
*/
// Temporary: returns whether it is available or not
function hasDB() {
if(window.sessionStorage)
return true;
return false;
}
// Temporary: used to read a database entry
function getDB(type, id) {
try {
return sessionStorage.getItem(type + '_' + id);
}
catch(e) {
logThis('Error while getting a temporary database entry (' + type + ' -> ' + id + '): ' + e, 1);
return null;
}
}
// Temporary: used to update a database entry
function setDB(type, id, value) {
try {
sessionStorage.setItem(type + '_' + id, value);
return true;
}
catch(e) {
logThis('Error while writing a temporary database entry (' + type + ' -> ' + id + '): ' + e, 1);
return false;
}
}
// Temporary: used to remove a database entry
function removeDB(type, id) {
try {
sessionStorage.removeItem(type + '_' + id);
return true;
}
catch(e) {
logThis('Error while removing a temporary database entry (' + type + ' -> ' + id + '): ' + e, 1);
return false;
}
}
// Temporary: used to check a database entry exists
function existDB(type, id) {
var read = getDB(type, id);
if(read != null)
return true;
return false;
}
// Temporary: used to clear all the database
function resetDB() {
try {
sessionStorage.clear();
logThis('Temporary database cleared.', 3);
return true;
}
catch(e) {
logThis('Error while clearing temporary database: ' + e, 1);
return false;
}
}
// Persistent: returns whether it is available or not
function hasPersistent() {
if(window.localStorage)
return true;
return false;
}
// Persistent: used to read a database entry
function getPersistent(type, id) {
try {
return localStorage.getItem(type + '_' + id);
}
catch(e) {
logThis('Error while getting a persistent database entry (' + type + ' -> ' + id + '): ' + e, 1);
return null;
}
}
// Persistent: used to update a database entry
function setPersistent(type, id, value) {
try {
localStorage.setItem(type + '_' + id, value);
return true;
}
// Database might be full
catch(e) {
logThis('Retrying: could not write a persistent database entry (' + type + ' -> ' + id + '): ' + e, 2);
// Flush it!
flushPersistent();
// Set the item again
try {
localStorage.setItem(type + '_' + id, value);
return true;
}
// New error!
catch(e) {
logThis('Aborted: error while writing a persistent database entry (' + type + ' -> ' + id + '): ' + e, 1);
return false;
}
}
}
// Persistent: used to remove a database entry
function removePersistent(type, id) {
try {
localStorage.removeItem(type + '_' + id);
return true;
}
catch(e) {
logThis('Error while removing a persistent database entry (' + type + ' -> ' + id + '): ' + e, 1);
return false;
}
}
// Persistent: used to check a database entry exists
function existPersistent(type, id) {
var read = getPersistent(type, id);
if(read != null)
return true;
return false;
}
// Persistent: used to clear all the database
function resetPersistent() {
try {
localStorage.clear();
logThis('Persistent database cleared.', 3);
return true;
}
catch(e) {
logThis('Error while clearing persistent database: ' + e, 1);
return false;
}
}
// Persistent: used to flush the database
function flushPersistent() {
try {
// Get the stored session entry
var session = getPersistent('session', 1);
// Clear the persistent database
localStorage.clear();
// Restaure the stored session entry
if(session)
setPersistent('session', 1, session);
logThis('Persistent database flushed.', 3);
return true;
}
catch(e) {
logThis('Error while flushing persistent database: ' + e, 1);
return false;
}
}

View file

@ -0,0 +1,212 @@
/*
Jappix - An open social platform
These are the date related JS scripts for Jappix
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 17/08/11
*/
// Gets a stamp from a date
function extractStamp(date) {
return Math.round(date.getTime() / 1000);
}
// Gets the time from a date
function extractTime(date) {
return date.toLocaleTimeString();
}
// Gets the actual date stamp
function getTimeStamp() {
return extractStamp(new Date());
}
// Gets the last user activity in seconds
var LAST_ACTIVITY = 0;
function getLastActivity() {
// Last activity not yet initialized?
if(LAST_ACTIVITY == 0)
return 0;
return getTimeStamp() - LAST_ACTIVITY;
}
// Gets the last user available presence in seconds
var PRESENCE_LAST_ACTIVITY = 0;
function getPresenceLast() {
// Last presence stamp not yet initialized?
if(PRESENCE_LAST_ACTIVITY == 0)
return 0;
return getTimeStamp() - PRESENCE_LAST_ACTIVITY;
}
// Generates the time for XMPP
function getXMPPTime(location) {
/* FROM : http://trac.jwchat.org/jsjac/browser/branches/jsjac_1.0/jsextras.js?rev=221 */
// Initialize
var jInit = new Date();
var year, month, day, hours, minutes, seconds;
// Gets the UTC date
if(location == 'utc') {
year = jInit.getUTCFullYear();
month = jInit.getUTCMonth();
day = jInit.getUTCDate();
hours = jInit.getUTCHours();
minutes = jInit.getUTCMinutes();
seconds = jInit.getUTCSeconds();
}
// Gets the local date
else {
year = jInit.getFullYear();
month = jInit.getMonth();
day = jInit.getDate();
hours = jInit.getHours();
minutes = jInit.getMinutes();
seconds = jInit.getSeconds();
}
// Generates the date string
var jDate = year + '-';
jDate += padZero(month + 1) + '-';
jDate += padZero(day) + 'T';
jDate += padZero(hours) + ':';
jDate += padZero(minutes) + ':';
jDate += padZero(seconds) + 'Z';
// Returns the date string
return jDate;
}
// Generates then human time
function getCompleteTime() {
var init = new Date();
var time = padZero(init.getHours()) + ':';
time += padZero(init.getMinutes()) + ':';
time += padZero(init.getSeconds());
return time;
}
// Gets the TZO of a date
function getDateTZO() {
// Get the date
var date = new Date();
var offset = date.getTimezoneOffset();
// Default vars
var sign = '';
var hours = 0;
var minutes = 0;
// Process a neutral offset
if(offset < 0) {
offset = offset * -1;
sign = '+';
}
// Get the values
var n_date = new Date(offset * 60 * 1000);
hours = n_date.getHours() - 1;
minutes = n_date.getMinutes();
// Process the TZO
tzo = sign + padZero(hours) + ':' + padZero(minutes);
// Return the processed value
return tzo;
}
// Parses a XMPP date (yyyy-mm-dd, hh-mm-ss) into an human-readable one
function parseDate(to_parse) {
var date = Date.jab2date(to_parse);
var parsed = date.toLocaleDateString() + ' (' + date.toLocaleTimeString() + ')';
return parsed;
}
// Parses a XMPP date (yyyy-mm-dd) into an human-readable one
function parseDay(to_parse) {
var date = Date.jab2date(to_parse);
var parsed = date.toLocaleDateString();
return parsed;
}
// Parses a XMPP date (hh-mm-ss) into an human-readable one
function parseTime(to_parse) {
var date = Date.jab2date(to_parse);
var parsed = date.toLocaleTimeString();
return parsed;
}
// Parses a XMPP date stamp into a relative one
function relativeDate(to_parse) {
// Get the current date
var current_date = Date.jab2date(getXMPPTime('utc'));
var current_day = current_date.getDate();
var current_stamp = current_date.getTime();
// Parse the given date
var old_date = Date.jab2date(to_parse);
var old_day = old_date.getDate();
var old_stamp = old_date.getTime();
var old_time = old_date.toLocaleTimeString();
// Get the day number between the two dates
var days = Math.round((current_stamp - old_stamp) / 86400000);
// Invalid date?
if(isNaN(old_stamp) || isNaN(days))
return getCompleteTime();
// Is it today?
if(current_day == old_day)
return old_time;
// It is yesterday?
if(days <= 1)
return _e("Yesterday") + ' - ' + old_time;
// Is it less than a week ago?
if(days <= 7)
return printf(_e("%s days ago"), days) + ' - ' + old_time;
// Another longer period
return old_date.toLocaleDateString() + ' - ' + old_time;
}
// Reads a message delay
function readMessageDelay(node) {
// Initialize
var delay, d_delay;
// Read the delay
d_delay = jQuery(node).find('delay[xmlns=' + NS_URN_DELAY + ']:first').attr('stamp');
// New delay (valid XEP)
if(d_delay)
delay = d_delay;
// Old delay (obsolete XEP!)
else {
// Try to read the old-school delay
var x_delay = jQuery(node).find('x[xmlns=' + NS_DELAY + ']:first').attr('stamp');
if(x_delay)
delay = x_delay.replace(/^(\w{4})(\w{2})(\w{2})T(\w{2}):(\w{2}):(\w{2})Z?(\S+)?/, '$1-$2-$3T$4:$5:$6Z$7');
}
return delay;
}

View file

@ -0,0 +1,87 @@
/*
Jappix - An open social platform
These are the directory JS scripts for Jappix
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 03/03/11
*/
// Opens the directory popup
function openDirectory() {
// Popup HTML content
var html =
'<div class="top">' + _e("User directory") + '</div>' +
'<div class="content">' +
'<div class="directory-head">' +
'<div class="directory-server-text">' + _e("Server to query") + '</div>' +
'<input name="directory-server-input" class="directory-server-input" value="' + encodeQuotes(HOST_VJUD) + '" />' +
'</div>' +
'<div class="results directory-results"></div>' +
'</div>' +
'<div class="bottom">' +
'<div class="wait wait-medium"></div>' +
'<a href="#" class="finish">' + _e("Close") + '</a>' +
'</div>';
// Create the popup
createPopup('directory', html);
// Associate the events
launchDirectory();
// Start a search!
startDirectory();
return false;
}
// Quits the directory popup
function closeDirectory() {
// Destroy the popup
destroyPopup('directory');
return false;
}
// Launches a directory search
function startDirectory() {
// Get the server to query
var server = $('#directory .directory-server-input').val();
// Launch the search!
dataForm($('#directory .directory-server-input').val(), 'search', '', '', 'directory');
logThis('Directory search launched: ' + server);
return false;
}
// Plugin launcher
function launchDirectory() {
// Click event
$('#directory .bottom .finish').click(closeDirectory);
// Keyboard event
$('#directory .directory-server-input').keyup(function(e) {
if(e.keyCode == 13) {
// No value?
if(!$(this).val())
$(this).val(HOST_VJUD);
// Start the directory search
startDirectory();
return false;
}
});
}

View file

@ -0,0 +1,169 @@
/*
Jappix - An open social platform
These are the discovery JS scripts for Jappix
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 03/03/11
*/
// Opens the discovery popup
function openDiscovery() {
// Popup HTML content
var html =
'<div class="top">' + _e("Service discovery") + '</div>' +
'<div class="content">' +
'<div class="discovery-head">' +
'<div class="disco-server-text">' + _e("Server to query") + '</div>' +
'<input name="disco-server-input" class="disco-server-input" value="' + encodeQuotes(HOST_MAIN) + '" />' +
'</div>' +
'<div class="results discovery-results">' +
'<div class="disco-category disco-account">' +
'<p class="disco-category-title">' + _e("Accounts") + '</p>' +
'</div>' +
'<div class="disco-category disco-auth">' +
'<p class="disco-category-title">' + _e("Authentications") + '</p>' +
'</div>' +
'<div class="disco-category disco-automation">' +
'<p class="disco-category-title">' + _e("Automation") + '</p>' +
'</div>' +
'<div class="disco-category disco-client">' +
'<p class="disco-category-title">' + _e("Clients") + '</p>' +
'</div>' +
'<div class="disco-category disco-collaboration">' +
'<p class="disco-category-title">' + _e("Collaboration") + '</p>' +
'</div>' +
'<div class="disco-category disco-component">' +
'<p class="disco-category-title">' + _e("Components") + '</p>' +
'</div>' +
'<div class="disco-category disco-conference">' +
'<p class="disco-category-title">' + _e("Rooms") + '</p>' +
'</div>' +
'<div class="disco-category disco-directory">' +
'<p class="disco-category-title">' + _e("Directories") + '</p>' +
'</div>' +
'<div class="disco-category disco-gateway">' +
'<p class="disco-category-title">' + _e("Gateways") + '</p>' +
'</div>' +
'<div class="disco-category disco-headline">' +
'<p class="disco-category-title">' + _e("News") + '</p>' +
'</div>' +
'<div class="disco-category disco-hierarchy">' +
'<p class="disco-category-title">' + _e("Hierarchy") + '</p>' +
'</div>' +
'<div class="disco-category disco-proxy">' +
'<p class="disco-category-title">' + _e("Proxies") + '</p>' +
'</div>' +
'<div class="disco-category disco-pubsub">' +
'<p class="disco-category-title">' + _e("Publication/Subscription") + '</p>' +
'</div>' +
'<div class="disco-category disco-server">' +
'<p class="disco-category-title">' + _e("Server") + '</p>' +
'</div>' +
'<div class="disco-category disco-store">' +
'<p class="disco-category-title">' + _e("Storage") + '</p>' +
'</div>' +
'<div class="disco-category disco-others">' +
'<p class="disco-category-title">' + _e("Others") + '</p>' +
'</div>' +
'<div class="disco-category disco-wait">' +
'<p class="disco-category-title">' + _e("Loading") + '</p>' +
'</div>' +
'</div>' +
'</div>' +
'<div class="bottom">' +
'<div class="wait wait-medium"></div>' +
'<a href="#" class="finish">' + _e("Close") + '</a>' +
'</div>';
// Create the popup
createPopup('discovery', html);
// Associate the events
launchDiscovery();
// We request a disco to the default server
startDiscovery();
return false;
}
// Quits the discovery popup
function closeDiscovery() {
// Destroy the popup
destroyPopup('discovery');
return false;
}
// Launches a discovery
function startDiscovery() {
/* REF: http://xmpp.org/extensions/xep-0030.html */
// We get the server to query
var discoServer = $('#discovery .disco-server-input').val();
// We launch the items query
dataForm(discoServer, 'browse', '', '', 'discovery');
logThis('Service discovery launched: ' + discoServer);
return false;
}
// Cleans the discovery results
function cleanDiscovery() {
// We remove the results
$('#discovery .discovery-oneresult, #discovery .oneinstructions, #discovery .onetitle, #discovery .no-results').remove();
// We clean the user info
$('#discovery .disco-server-info').text('');
// We hide the wait icon, the no result alert and the results
$('#discovery .wait, #discovery .disco-category').hide();
}
// Plugin launcher
function launchDiscovery() {
// Click event
$('#discovery .bottom .finish').click(closeDiscovery);
// Keyboard event
$('#discovery .disco-server-input').keyup(function(e) {
if(e.keyCode == 13) {
// No value?
if(!$(this).val())
$(this).val(HOST_MAIN);
// Start the discovery
startDiscovery();
return false;
}
});
}

View file

@ -0,0 +1,139 @@
/*
Jappix - An open social platform
These are the error functions for Jappix
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 02/04/11
*/
// Shows the given error output
function showError(condition, reason, type) {
// Enough data to output the error
if(condition || reason) {
// Initialize the error text
var eText = '';
// Any error condition
if(condition)
eText += condition;
// Any error type
if(type && eText)
eText += ' (' + type + ')';
// Any error reason
if(reason) {
if(eText)
eText += ' - ';
eText += reason;
}
// We reveal the error
openThisError(1);
// Create the error text
$('#board .one-board.error[data-id=1] span').text(eText);
}
// Not enough data to output the error: output a generic board
else
openThisError(2);
}
// Handles the error from a packet and return true if any error
function handleError(packet) {
/* REF: http://xmpp.org/extensions/xep-0086.html */
// Initialize
var type, code, reason, condition;
var node = $(packet);
// First level error (connection error)
if(node.is('error')) {
// Get the value
code = node.attr('code');
// Specific error reason
switch(code) {
case '401':
reason = _e("Authorization failed");
break;
case '409':
reason = _e("Registration failed, please choose a different username");
break;
case '503':
reason = _e("Service unavailable");
break;
case '500':
reason = _e("Internal server error, try later");
break;
default:
reason = node.find('text').text();
break;
}
// Remove the general wait item (security)
removeGeneralWait();
// Show reconnect pane
if(CURRENT_SESSION && CONNECTED) {
// Anonymous?
if(isAnonymous())
createReconnect('anonymous');
else
createReconnect('normal');
}
// Show the homepage (security)
else if(!CURRENT_SESSION || !CONNECTED) {
$('#home').show();
pageTitle('home');
}
// Still connected? (security)
if(isConnected())
con.disconnect();
logThis('First level error received.', 1);
}
// Second level error (another error)
else if(node.find('error').size()) {
type = node.find('error').attr('type');
reason = node.find('error text').text();
condition = packet.getElementsByTagName('error').item(0).childNodes.item(0).nodeName.replace(/-/g, ' ');
logThis('Second level error received.', 1);
}
// No error
else
return false;
// Show the error board
showError(condition, reason, type);
// Return there's an error
return true;
}
// Handles the error reply of a packet
function handleErrorReply(packet) {
return handleError(packet.getNode());
}
// Handles the error reply for a message
function handleMessageError(packet) {
if(!handleErrorReply(packet))
handleMessage(packet);
}

View file

@ -0,0 +1,537 @@
/*
Jappix - An open social platform
These are the favorites JS scripts for Jappix
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 23/06/11
*/
// Opens the favorites popup
function openFavorites() {
// Popup HTML content
var html =
'<div class="top">' + _e("Manage favorite rooms") + '</div>' +
'<div class="content">' +
'<div class="switch-fav">' +
'<div class="room-switcher room-list">' +
'<div class="icon list-icon talk-images"></div>' +
_e("Change favorites") +
'</div>' +
'<div class="room-switcher room-search">' +
'<div class="icon search-icon talk-images"></div>' +
_e("Search a room") +
'</div>' +
'</div>' +
'<div class="static-fav">' +
'<div class="favorites-edit favorites-content">' +
'<div class="head fedit-head static-fav-head">' +
'<div class="head-text fedit-head-text">' + _e("Select a favorite") + '</div>' +
'<select name="fedit-head-select" class="head-select fedit-head-select"></select>' +
'</div>' +
'<div class="results fedit-results static-fav-results">' +
'<div class="fedit-line">' +
'<label>' + _e("Name") + '</label>' +
'<input class="fedit-title" type="text" required="" />' +
'</div>' +
'<div class="fedit-line">' +
'<label>' + _e("Nickname") + '</label>' +
'<input class="fedit-nick" type="text" value="' + getNick() + '" required="" />' +
'</div>' +
'<div class="fedit-line">' +
'<label>' + _e("Room") + '</label>' +
'<input class="fedit-chan" type="text" required="" />' +
'</div>' +
'<div class="fedit-line">' +
'<label>' + _e("Server") + '</label>' +
'<input class="fedit-server" type="text" value="' + HOST_MUC + '" required="" />' +
'</div>' +
'<div class="fedit-line">' +
'<label>' + _e("Password") + '</label>' +
'<input class="fedit-password" type="password" />' +
'</div>' +
'<div class="fedit-line">' +
'<label>' + _e("Automatic") + '</label>' +
'<input type="checkbox" class="fedit-autojoin" />' +
'</div>' +
'<div class="fedit-actions">' +
'<a href="#" class="fedit-terminate fedit-add add one-button talk-images">' + _e("Add") + '</a>' +
'<a href="#" class="fedit-terminate fedit-edit one-button talk-images">' + _e("Edit") + '</a>' +
'<a href="#" class="fedit-terminate fedit-remove remove one-button talk-images">' + _e("Remove") + '</a>' +
'</div>' +
'</div>' +
'</div>' +
'<div class="favorites-search favorites-content">' +
'<div class="head fsearch-head static-fav-head">' +
'<div class="head-text fsearch-head-text">' + _e("Search a room on") + '</div>' +
'<input type="text" class="head-input fsearch-head-server" value="' + HOST_MUC + '" />' +
'</div>' +
'<div class="results fsearch-results static-fav-results">' +
'<p class="fsearch-noresults">' + _e("No room found on this server.") + '</p>' +
'</div>' +
'</div>' +
'</div>' +
'</div>' +
'<div class="bottom">' +
'<div class="wait wait-medium"></div>' +
'<a href="#" class="finish">' + _e("Close") + '</a>' +
'</div>';
// Create the popup
createPopup('favorites', html);
// Load the favorites
loadFavorites();
// Associate the events
launchFavorites();
}
// Resets the favorites elements
function resetFavorites() {
var path = '#favorites ';
$(path + '.wait, ' + path + '.fedit-terminate').hide();
$(path + '.fedit-add').show();
$(path + '.fsearch-oneresult').remove();
$(path + 'input').val('');
$(path + '.please-complete').removeClass('please-complete');
$(path + '.fedit-nick').val(getNick());
$(path + '.fsearch-head-server, ' + path + '.fedit-server').val(HOST_MUC);
$(path + '.fedit-autojoin').attr('checked', false);
}
// Quits the favorites popup
function quitFavorites() {
// Destroy the popup
destroyPopup('favorites');
return false;
}
// Adds a room to the favorites
function addThisFavorite(roomXID, roomName) {
// Button path
var button = '#favorites .fsearch-results div[data-xid=' + escape(roomXID) + '] a.one-button';
// Add a remove button instead of the add one
$(button + '.add').replaceWith('<a href="#" class="one-button remove talk-images">' + _e("Remove") + '</a>');
// Click event
$(button + '.remove').click(function() {
return removeThisFavorite(roomXID, roomName);
});
// Hide the add button in the (opened?) groupchat
$('#' + hex_md5(roomXID) + ' .tools-add').hide();
// Add the database entry
displayFavorites(roomXID, explodeThis(' (', roomName, 0), getNick(), '0', '');
// Publish the favorites
favoritePublish();
return false;
}
// Removes a room from the favorites
function removeThisFavorite(roomXID, roomName) {
// Button path
var button = '#favorites .fsearch-results div[data-xid=' + escape(roomXID) + '] a.one-button';
// Add a remove button instead of the add one
$(button + '.remove').replaceWith('<a href="#" class="one-button add talk-images">' + _e("Add") + '</a>');
// Click event
$(button + '.add').click(function() {
return addThisFavorite(roomXID, roomName);
});
// Show the add button in the (opened?) groupchat
$('#' + hex_md5(roomXID) + ' .tools-add').show();
// Remove the favorite
removeFavorite(roomXID, true);
// Publish the favorites
favoritePublish();
return false;
}
// Edits a favorite
function editFavorite() {
// Path to favorites
var favorites = '#favorites .';
// Reset the favorites
resetFavorites();
// Show the edit/remove button, hide the others
$(favorites + 'fedit-terminate').hide();
$(favorites + 'fedit-edit').show();
$(favorites + 'fedit-remove').show();
// We retrieve the values
var xid = $(favorites + 'fedit-head-select').val();
var data = XMLFromString(getDB('favorites', xid));
// If this is not the default room
if(xid != 'none') {
// We apply the values
$(favorites + 'fedit-title').val($(data).find('name').text());
$(favorites + 'fedit-nick').val($(data).find('nick').text());
$(favorites + 'fedit-chan').val(getXIDNick(xid));
$(favorites + 'fedit-server').val(getXIDHost(xid));
$(favorites + 'fedit-password').val($(data).find('password').text());
if($(data).find('autojoin').text() == '1')
$(favorites + 'fedit-autojoin').attr('checked', true);
}
else
resetFavorites();
}
// Adds a favorite
function addFavorite() {
// Path to favorites
var favorites = '#favorites .';
// We reset the inputs
$(favorites + 'fedit-title, ' + favorites + 'fedit-nick, ' + favorites + 'fedit-chan, ' + favorites + 'fedit-server, ' + favorites + 'fedit-password').val('');
// Show the add button, hide the others
$(favorites + 'fedit-terminate').hide();
$(favorites + 'fedit-add').show();
}
// Terminate a favorite editing
function terminateThisFavorite(type) {
// Path to favorites
var favorites = '#favorites ';
// We get the values of the current edited groupchat
var old_xid = $(favorites + '.fedit-head-select').val();
var title = $(favorites + '.fedit-title').val();
var nick = $(favorites + '.fedit-nick').val();
var room = $(favorites + '.fedit-chan').val();
var server = $(favorites + '.fedit-server').val();
var xid = room + '@' + server;
var password = $(favorites + '.fedit-password').val();
var autojoin = '0';
if($(favorites + '.fedit-autojoin').filter(':checked').size())
autojoin = '1';
// We check the missing values and send this if okay
if((type == 'add') || (type == 'edit')) {
if(title && nick && room && server) {
// Remove the edited room
if(type == 'edit')
removeFavorite(old_xid, true);
// Display the favorites
displayFavorites(xid, title, nick, autojoin, password);
// Reset the inputs
resetFavorites();
}
else {
$(favorites + 'input[required]').each(function() {
var select = $(this);
if(!select.val())
$(document).oneTime(10, function() {
select.addClass('please-complete').focus();
});
else
select.removeClass('please-complete');
});
}
}
// Must remove a favorite?
else if(type == 'remove') {
removeFavorite(old_xid, true);
// Reset the inputs
resetFavorites();
}
// Publish the new favorites
favoritePublish();
logThis('Action on this bookmark: ' + room + '@' + server + ' / ' + type, 3);
return false;
}
// Removes a favorite
function removeFavorite(xid, database) {
// We remove the target favorite everywhere needed
$('.buddy-conf-groupchat-select option[value=' + xid + ']').remove();
$('.fedit-head-select option[value=' + xid + ']').remove();
// Must remove it from database?
if(database)
removeDB('favorites', xid);
}
// Sends a favorite to the XMPP server
function favoritePublish() {
var iq = new JSJaCIQ();
iq.setType('set');
var query = iq.setQuery(NS_PRIVATE);
var storage = query.appendChild(iq.buildNode('storage', {'xmlns': NS_BOOKMARKS}));
// We generate the XML
for(var i = 0; i < sessionStorage.length; i++) {
// Get the pointer values
var current = sessionStorage.key(i);
// If the pointer is on a stored favorite
if(explodeThis('_', current, 0) == 'favorites') {
var data = XMLFromString(sessionStorage.getItem(current));
var xid = $(data).find('xid').text();
var rName = $(data).find('name').text();
var nick = $(data).find('nick').text();
var password = $(data).find('password').text();
var autojoin = $(data).find('autojoin').text();
// We create the node for this groupchat
var item = storage.appendChild(iq.buildNode('conference', {'name': rName, 'jid': xid, 'autojoin': autojoin, xmlns: NS_BOOKMARKS}));
item.appendChild(iq.buildNode('nick', {xmlns: NS_BOOKMARKS}, nick));
if(password)
item.appendChild(iq.buildNode('password', {xmlns: NS_BOOKMARKS}, password));
logThis('Bookmark sent: ' + xid, 3);
}
}
con.send(iq);
}
// Gets a list of the MUC items on a given server
function getGCList() {
var path = '#favorites .';
var gcServer = $('.fsearch-head-server').val();
// We reset some things
$(path + 'fsearch-oneresult').remove();
$(path + 'fsearch-noresults').hide();
$(path + 'wait').show();
var iq = new JSJaCIQ();
iq.setType('get');
iq.setTo(gcServer);
iq.setQuery(NS_DISCO_ITEMS);
con.send(iq, handleGCList);
}
// Handles the MUC items list
function handleGCList(iq) {
var path = '#favorites .';
var from = fullXID(getStanzaFrom(iq));
if (!iq || (iq.getType() != 'result')) {
openThisError(3);
$(path + 'wait').hide();
logThis('Error while retrieving the rooms: ' + from, 1);
}
else {
var handleXML = iq.getQuery();
if($(handleXML).find('item').size()) {
// Initialize the HTML code
var html = '';
$(handleXML).find('item').each(function() {
var roomXID = $(this).attr('jid');
var roomName = $(this).attr('name');
if(roomXID && roomName) {
// Escaped values
var escaped_xid = encodeOnclick(roomXID);
var escaped_name = encodeOnclick(roomName);
// Initialize the room HTML
html += '<div class="oneresult fsearch-oneresult" data-xid="' + escape(roomXID) + '">' +
'<div class="room-name">' + roomName.htmlEnc() + '</div>' +
'<a href="#" class="one-button join talk-images" onclick="return joinFavorite(\'' + escaped_xid + '\');">' + _e("Join") + '</a>';
// This room is yet a favorite
if(existDB('favorites', roomXID))
html += '<a href="#" class="one-button remove talk-images" onclick="return removeThisFavorite(\'' + escaped_xid + '\', \'' + escaped_name + '\');">' + _e("Remove") + '</a>';
else
html += '<a href="#" class="one-button add talk-images" onclick="return addThisFavorite(\'' + escaped_xid + '\', \'' + escaped_name + '\');">' + _e("Add") + '</a>';
// Close the room HTML
html += '</div>';
}
});
// Append this code to the popup
$(path + 'fsearch-results').append(html);
}
else
$(path + 'fsearch-noresults').show();
logThis('Rooms retrieved: ' + from, 3);
}
$(path + 'wait').hide();
}
// Joins a groupchat from favorites
function joinFavorite(room) {
quitFavorites();
checkChatCreate(room, 'groupchat', '', '', getXIDNick(room));
return false;
}
// Displays a given favorite
function displayFavorites(xid, name, nick, autojoin, password) {
// Generate the HTML code
var html = '<option value="' + encodeQuotes(xid) + '">' + name.htmlEnc() + '</option>';
// Remove the existing favorite
removeFavorite(xid, false);
// We complete the select forms
$('#buddy-list .gc-join-first-option, #favorites .fedit-head-select-first-option').after(html);
// We store the informations
var value = '<groupchat><xid>' + xid.htmlEnc() + '</xid><name>' + name.htmlEnc() + '</name><nick>' + nick.htmlEnc() + '</nick><autojoin>' + autojoin.htmlEnc() + '</autojoin><password>' + password.htmlEnc() + '</password></groupchat>';
setDB('favorites', xid, value);
}
// Loads the favorites for the popup
function loadFavorites() {
// Initialize the HTML code
var html = '';
// Read the database
for(var i = 0; i < sessionStorage.length; i++) {
// Get the pointer values
var current = sessionStorage.key(i);
// If the pointer is on a stored favorite
if(explodeThis('_', current, 0) == 'favorites') {
var data = XMLFromString(sessionStorage.getItem(current));
// Add the current favorite to the HTML code
html += '<option value="' + encodeQuotes($(data).find('xid').text()) + '">' + $(data).find('name').text().htmlEnc() + '</option>';
}
}
// Generate specific HTML code
var favorites_bubble = '<option value="none" class="gc-join-first-option" selected="">' + _e("Select a favorite") + '</option>' + html;
var favorites_popup = '<option value="none" class="fedit-head-select-first-option" selected="">' + _e("Select a favorite") + '</option>' + html;
// Append the HTML code
$('#buddy-list .buddy-conf-groupchat-select').html(favorites_bubble);
$('#favorites .fedit-head-select').html(favorites_popup);
}
// Plugin launcher
function launchFavorites() {
var path = '#favorites .';
// Keyboard events
$(path + 'fsearch-head-server').keyup(function(e) {
if(e.keyCode == 13) {
// No value?
if(!$(this).val())
$(this).val(HOST_MUC);
// Get the list
getGCList();
}
});
$(path + 'fedit-line input').keyup(function(e) {
if(e.keyCode == 13) {
// Edit a favorite
if($(path + 'fedit-edit').is(':visible'))
terminateThisFavorite('edit');
// Add a favorite
else
terminateThisFavorite('add');
}
});
// Change events
$('.fedit-head-select').change(editFavorite);
// Click events
$(path + 'room-switcher').click(function() {
$(path + 'favorites-content').hide();
resetFavorites();
});
$(path + 'room-list').click(function() {
$(path + 'favorites-edit').show();
});
$(path + 'room-search').click(function() {
$(path + 'favorites-search').show();
getGCList();
});
$(path + 'fedit-add').click(function() {
return terminateThisFavorite('add');
});
$(path + 'fedit-edit').click(function() {
return terminateThisFavorite('edit');
});
$(path + 'fedit-remove').click(function() {
return terminateThisFavorite('remove');
});
$(path + 'bottom .finish').click(function() {
return quitFavorites();
});
}

View file

@ -0,0 +1,213 @@
/*
Jappix - An open social platform
This is the server features JS script for Jappix
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 01/06/11
*/
// Gets the features of a server
function getFeatures() {
/* REF: http://xmpp.org/extensions/xep-0030.html */
// Get the main values
var to = getServer();
var caps = con.server_caps;
var xml = null;
// Try to get the stored data
if(caps)
xml = XMLFromString(getPersistent('caps', caps));
// Any stored data?
if(xml) {
handleFeatures(xml);
logThis('Read server CAPS from cache.');
}
// Not stored (or no CAPS)!
else {
var iq = new JSJaCIQ();
iq.setTo(to);
iq.setType('get');
iq.setQuery(NS_DISCO_INFO);
con.send(iq, handleDiscoInfos);
logThis('Read server CAPS from network.');
}
}
// Handles the features of a server
function handleFeatures(xml) {
// Selector
var selector = $(xml);
// Markers
var pep = false;
var pubsub = false;
var archive = false;
var archive_auto = false;
var archive_manual = false;
var archive_manage = false;
var archive_pref = false;
var commands = false;
// Scan the features
if(selector.find('identity[category=pubsub][type=pep]').size())
pep = true;
if(selector.find('feature[var=' + NS_PUBSUB + ']').size())
pubsub = true;
if(selector.find('feature[var=' + NS_URN_ARCHIVE + ']').size())
archive = true;
if(selector.find('feature[var=' + NS_URN_AR_AUTO + ']').size())
archive_auto = true;
if(selector.find('feature[var=' + NS_URN_AR_MANUAL + ']').size())
archive_manual = true;
if(selector.find('feature[var=' + NS_URN_AR_MANAGE + ']').size())
archive_manage = true;
if(selector.find('feature[var=' + NS_URN_AR_PREF + ']').size())
archive_pref = true;
if(selector.find('feature[var=' + NS_COMMANDS + ']').size())
commands = true;
// Enable the pep elements if available
if(pep) {
// Update our database
enableFeature('pep');
// Get the microblog
getInitMicroblog();
// Get the notifications
getNotifications();
// Geolocate the user
geolocate();
// Enable microblogging send tools
waitMicroblog('sync');
$('.postit.attach').css('display', 'block');
logThis('XMPP server supports PEP.', 3);
}
// Disable microblogging send tools (no PEP!)
else {
waitMicroblog('unsync');
logThis('XMPP server does not support PEP.', 2);
}
// Enable the pubsub features if available
if(pubsub)
enableFeature(NS_PUBSUB);
// Enable the archiving features if available
if(archive)
enableFeature(NS_URN_ARCHIVE);
// Enable the archiving sub-features if available
if(archive_pref)
enableFeature(NS_URN_AR_PREF);
if(archive_auto)
enableFeature(NS_URN_AR_AUTO);
if(archive_manual)
enableFeature(NS_URN_AR_MANUAL);
if(archive_manage)
enableFeature(NS_URN_AR_MANAGE);
// Enable the commands features if available
if(commands)
enableFeature(NS_COMMANDS);
// Hide the private life fieldset if nothing to show
if(!pep && !archive_pref)
$('#options fieldset.privacy').hide();
// Apply the features
applyFeatures('talk');
// Process the buddy-list height
if(pep)
adaptRoster();
return false;
}
// The function to apply the features to an element
function applyFeatures(id) {
// Path to the elements
var path = '#' + id + ' .';
// PEP features
if(enabledPEP())
$(path + 'pep-hidable').show();
// PubSub features
if(enabledPubSub())
$(path + 'pubsub-hidable').show();
// Archives features
if(enabledArchives() || enabledArchives('auto') || enabledArchives('manual') || enabledArchives('manage')) {
$(path + 'archives-hidable:not(.pref)').show();
// Sub-feature: archives preferences
if(enabledArchives('pref'))
$(path + 'archives-hidable.pref').show();
}
// Commands features
if(enabledCommands())
$(path + 'commands-hidable').show();
// XMPP links (browser feature)
if(navigator.registerProtocolHandler)
$(path + 'xmpplinks-hidable').show();
}
// Enables a feature
function enableFeature(feature) {
setDB('feature', feature, 'true');
}
// Checks if a feature is enabled
function enabledFeature(feature) {
if(getDB('feature', feature) == 'true')
return true;
else
return false;
}
// Returns the XMPP server PEP support
function enabledPEP() {
return enabledFeature('pep');
}
// Returns the XMPP server PubSub support
function enabledPubSub() {
return enabledFeature(NS_PUBSUB);
}
// Returns the XMPP server archives support
function enabledArchives(sub) {
var xmlns = NS_URN_ARCHIVE;
// Any sub element sent?
if(sub)
xmlns += ':' + sub;
return enabledFeature(xmlns);
}
// Returns the XMPP server commands support
function enabledCommands() {
return enabledFeature(NS_COMMANDS);
}

View file

@ -0,0 +1,189 @@
/*
Jappix - An open social platform
These are the filtering JS script for Jappix
-------------------------------------------------
License: AGPL
Authors: Vanaryon, Maranda
Last revision: 04/08/11
*/
// Generates a given emoticon HTML code
function emoteImage(image, text, after) {
return ' <img class="emoticon emoticon-' + image + ' smileys-images" alt="' + encodeQuotes(text) + '" src="' + './img/others/blank.gif' + '" /> ' + after;
}
// Filters a given message
function filterThisMessage(neutralMessage, nick, html_encode) {
var filteredMessage = neutralMessage;
// We encode the HTML special chars
if(html_encode)
filteredMessage = filteredMessage.htmlEnc();
// /me command
filteredMessage = filteredMessage.replace(/((^)|((.+)(>)))(\/me )([^<]+)/, nick + ' $7')
// We replace the smilies text into images
.replace(/(:-?@)($|\s|<)/gi, emoteImage('angry', '$1', '$2'))
.replace(/(:-?\[)($|\s|<)/gi, emoteImage('bat', '$1', '$2'))
.replace(/(\(B\))($|\s|<)/g, emoteImage('beer', '$1', '$2'))
.replace(/((:-?D)|(XD))($|\s|<)/gi, emoteImage('biggrin', '$1', '$4'))
.replace(/(:-?\$)($|\s|<)/gi, emoteImage('blush', '$1', '$2'))
.replace(/(\(Z\))($|\s|<)/g, emoteImage('boy', '$1', '$2'))
.replace(/(\(W\))($|\s|<)/g, emoteImage('brflower', '$1', '$2'))
.replace(/((&lt;\/3)|(\(U\)))($|\s|<)/g, emoteImage('brheart', '$1', '$4'))
.replace(/(\(C\))($|\s|<)/g, emoteImage('coffee', '$1', '$2'))
.replace(/((8-\))|(\(H\)))($|\s|<)/g, emoteImage('coolglasses', '$1', '$4'))
.replace(/(:'-?\()($|\s|<)/gi, emoteImage('cry', '$1', '$2'))
.replace(/(\(%\))($|\s|<)/g, emoteImage('cuffs', '$1', '$2'))
.replace(/(\]:-?&gt;)($|\s|<)/gi, emoteImage('devil', '$1', '$2'))
.replace(/(\(D\))($|\s|<)/g, emoteImage('drink', '$1', '$2'))
.replace(/(@}-&gt;--)($|\s|<)/gi, emoteImage('flower', '$1', '$2'))
.replace(/((:-?\/)|(:-?S))($|\s|<)/gi, emoteImage('frowning', '$1', '$4'))
.replace(/(\(X\))($|\s|<)/g, emoteImage('girl', '$1', '$2'))
.replace(/((&lt;3)|(\(L\)))($|\s|<)/g, emoteImage('heart', '$1', '$4'))
.replace(/(\(}\))($|\s|<)/g, emoteImage('hugleft', '$1', '$2'))
.replace(/(\({\))($|\s|<)/g, emoteImage('hugright', '$1', '$2'))
.replace(/(:-?{})($|\s|<)/gi, emoteImage('kiss', '$1', '$2'))
.replace(/(\(I\))($|\s|<)/g, emoteImage('lamp', '$1', '$2'))
.replace(/(:-?3)($|\s|<)/gi, emoteImage('lion', '$1', '$2'))
.replace(/(\(E\))($|\s|<)/g, emoteImage('mail', '$1', '$2'))
.replace(/(\(S\))($|\s|<)/g, emoteImage('moon', '$1', '$2'))
.replace(/(\(8\))($|\s|<)/g, emoteImage('music', '$1', '$2'))
.replace(/((=-?O)|(:-?O))($|\s|<)/gi, emoteImage('oh', '$1', '$4'))
.replace(/(\(T\))($|\s|<)/g, emoteImage('phone', '$1', '$2'))
.replace(/(\(P\))($|\s|<)/g, emoteImage('photo', '$1', '$2'))
.replace(/(:-?!)($|\s|<)/gi, emoteImage('puke', '$1', '$2'))
.replace(/(\(@\))($|\s|<)/g, emoteImage('pussy', '$1', '$2'))
.replace(/(\(R\))($|\s|<)/g, emoteImage('rainbow', '$1', '$2'))
.replace(/(:-?\))($|\s|<)/gi, emoteImage('smile', '$1', '$2'))
.replace(/(\(\*\))($|\s|<)/g, emoteImage('star', '$1', '$2'))
.replace(/(:-?\|)($|\s|<)/gi, emoteImage('stare', '$1', '$2'))
.replace(/(\(N\))($|\s|<)/g, emoteImage('thumbdown', '$1', '$2'))
.replace(/(\(Y\))($|\s|<)/g, emoteImage('thumbup', '$1', '$2'))
.replace(/(:-?P)($|\s|<)/gi, emoteImage('tongue', '$1', '$2'))
.replace(/(:-?\()($|\s|<)/gi, emoteImage('unhappy', '$1', '$2'))
.replace(/(;-?\))($|\s|<)/gi, emoteImage('wink', '$1', '$2'))
// Text in bold
.replace(/(^|\s|>)((\*)([^<>'"]+)(\*))($|\s|<)/gi, '$1<b>$2</b>$6')
// Italic text
.replace(/(^|\s|>)((\/)([^<>'"]+)(\/))($|\s|<)/gi, '$1<i>$2</i>$6')
// Underlined text
.replace(/(^|\s|>)((_)([^<>'"]+)(_))($|\s|<)/gi, '$1<span style="text-decoration: underline;">$2</span>$6');
// Add the links
if(html_encode)
filteredMessage = applyLinks(filteredMessage, 'desktop');
// Filter integratebox links
filteredMessage = filterIntegrateBox(filteredMessage);
return filteredMessage;
}
// Filters a xHTML message to be displayed in Jappix
function filterThisXHTML(code) {
// Allowed elements array
var elements = new Array(
'a',
'abbr',
'acronym',
'address',
'blockquote',
'body',
'br',
'cite',
'code',
'dd',
'dfn',
'div',
'dt',
'em',
'h1',
'h2',
'h3',
'h4',
'h5',
'h6',
'head',
'html',
'img',
'kbd',
'li',
'ol',
'p',
'pre',
'q',
'samp',
'span',
'strong',
'title',
'ul',
'var'
);
// Allowed attributes array
var attributes = new Array(
'accesskey',
'alt',
'charset',
'cite',
'class',
'height',
'href',
'hreflang',
'id',
'longdesc',
'profile',
'rel',
'rev',
'src',
'style',
'tabindex',
'title',
'type',
'uri',
'version',
'width',
'xml:lang',
'xmlns'
);
// Remove forbidden elements
$(code).find('html body *').each(function() {
// This element is not authorized
if(!existArrayValue(elements, (this).nodeName.toLowerCase()))
$(this).remove();
});
// Remove forbidden attributes
$(code).find('html body *').each(function() {
// Put a pointer on this element (jQuery way & normal way)
var cSelector = $(this);
var cElement = (this);
// Loop the attributes of the current element
$(cElement.attributes).each(function(index) {
// Read the current attribute
var cAttr = cElement.attributes[index];
var cName = cAttr.name;
var cVal = cAttr.value;
// This attribute is not authorized, or contains JS code
if(!existArrayValue(attributes, cName.toLowerCase()) || ((cVal.toLowerCase()).match(/(^|"|')javascript:/)))
cSelector.removeAttr(cName);
});
});
// Filter some other elements
$(code).find('a').attr('target', '_blank');
return $(code).find('html body').html();
}

View file

@ -0,0 +1,283 @@
/*
Jappix - An open social platform
These are the groupchat JS scripts for Jappix
-------------------------------------------------
License: AGPL
Authors: Vanaryon, Maranda, Eric
Last revision: 28/08/11
*/
// Displays the MUC admin elements
function displayMucAdmin(affiliation, id, xid, statuscode) {
// We must be in the "login" mode
if(isAnonymous())
return;
// We check if the user is a room owner or administrator to give him privileges
if(affiliation == 'owner' || affiliation == 'admin')
$('#' + id + ' .tools-mucadmin').show();
// We check if the room hasn't been yet created
if(statuscode == 201)
openThisInfo(4);
// We add the click event
$('#' + id + ' .tools-mucadmin').click(function() {
openMucAdmin(xid, affiliation);
});
}
// Initializes a connection with a MUC groupchat
function getMUC(room, nickname, password) {
// Room hash
var hash = hex_md5(room);
// Reset the elements
$('#' + hash + ' .muc-ask').remove();
$('#' + hash + ' .compose').show();
// No nickname?
if(!nickname) {
// Get some values
if(!isAnonymous())
nickname = getNick();
else
nickname = ANONYMOUS_NICK;
// If the nickname could not be retrieved, ask it
if(!nickname)
generateMUCAsk('nickname', room, hash, nickname, password);
}
// Got our nickname?
if(nickname) {
// Get our general presence
var show = getDB('presence-show', 1);
var status = getDB('options', 'presence-status');
// Set my nick
$('#' + hash).attr('data-nick', escape(nickname));
// Send the appropriate presence
sendPresence(room + '/' + nickname, '', show, status, '', true, password, handleMUC);
}
return false;
}
// Handles the MUC main elements
function handleMUC(presence) {
// We get the xml content
var xml = presence.getNode();
var from = fullXID(getStanzaFrom(presence));
var room = bareXID(from);
var nickname = thisResource(from);
var hash = hex_md5(room);
// No ID: must fix M-Link bug
if(presence.getID() == null)
presence.setID(1);
logThis('First MUC presence: ' + from, 3);
// Catch the errors
if(!handleError(xml)) {
// Define some stuffs
var muc_user = $(xml).find('x[xmlns=' + NS_MUC_USER + ']');
var affiliation = muc_user.find('item').attr('affiliation');
var statuscode = parseInt(muc_user.find('status').attr('code'));
// Handle my presence
handlePresence(presence);
// Check if I am a room owner
displayMucAdmin(affiliation, hash, room, statuscode);
// Tell the MUC we can notify the incoming presences
$(document).oneTime('15s', function() {
$('#' + hash).attr('data-initial', 'true');
});
// Enable the chatting input
$(document).oneTime(10, function() {
$('#' + hash + ' .message-area').removeAttr('disabled').focus();
});
}
// A password is required
else if($(xml).find('error[type=auth] not-authorized').size())
generateMUCAsk('password', room, hash, nickname);
// There's a nickname conflict
else if($(xml).find('error[type=cancel] conflict').size())
generateMUCAsk('nickname', room, hash);
}
// Generates a correct MUC asker
function generateMUCAsk(type, room, hash, nickname, password) {
// Generate the path to the elements
var path_to = '#' + hash + ' .muc-ask';
// Define the label text
var label_text;
switch(type) {
case 'nickname':
label_text = _e("Nickname");
break;
case 'password':
label_text = _e("Password");
break;
}
// Create the HTML markup
$('#' + hash + ' .compose').hide();
$('#' + hash).append(
'<div class="muc-ask text">' +
'<label>' + label_text + '</label>' +
'<input class="focusable" type="text" />' +
'</div>'
);
// When a key is pressed in the input
$(path_to + ' input').keyup(function(e) {
var value_input = $(this).val();
// Enter key pressed
if((e.keyCode == 13) && value_input) {
if(type == 'nickname')
nickname = value_input;
else if(type == 'password')
password = value_input;
return getMUC(room, nickname, password);
}
});
// Focus on the input
$(document).oneTime(10, function() {
$(path_to + ' input').focus();
});
}
// Creates a new groupchat
function groupchatCreate(hash, room, chan, nickname, password) {
/* REF: http://xmpp.org/extensions/xep-0045.html */
logThis('New groupchat: ' + room, 3);
// Create the chat content
generateChat('groupchat', hash, room, chan);
// Create the chat switcher
generateSwitch('groupchat', hash, room, chan);
// The icons-hover functions
tooltipIcons(room, hash);
// Click event on the add tool
$('#' + hash + ' .tools-add').click(function() {
// Hide the icon (to tell the user all is okay)
$(this).hide();
// Add the groupchat to the user favorites
addThisFavorite(room, chan);
});
// Must show the add button?
if(!existDB('favorites', room))
$('#' + hash + ' .tools-add').show();
// The event handlers
var inputDetect = $('#' + hash + ' .message-area');
// Focus event
inputDetect.focus(function() {
chanCleanNotify(hash);
})
// Blur event
inputDetect.blur(function() {
resetAutocompletion(hash);
})
// Lock to the input
inputDetect.keypress(function(e) {
// Enter key
if(e.keyCode == 13) {
// Add a new line
if(e.shiftKey)
inputDetect.val(inputDetect.val() + '\n');
// Send the message
else {
sendMessage(hash, 'groupchat');
// Reset the composing database entry
setDB('chatstate', room, 'off');
}
return false;
}
// Tabulation key
else if(e.keyCode == 9) {
createAutocompletion(hash);
return false;
}
// Reset the autocompleter
else
resetAutocompletion(hash);
});
// Chatstate events
eventsChatState(inputDetect, room, hash);
// Get the current muc informations and content
getMUC(room, nickname, password);
}
// Joins the defined groupchats
function joinConfGroupchats() {
// Nothing to join?
if(!GROUPCHATS_JOIN)
return;
// Values array
var muc_arr = [GROUPCHATS_JOIN];
var new_arr = [];
// Try to split it
if(GROUPCHATS_JOIN.indexOf(',') != -1)
muc_arr = GROUPCHATS_JOIN.split(',');
for(i in muc_arr) {
// Get the current value
var muc_current = trim(muc_arr[i]);
// No current value?
if(!muc_current)
continue;
// Filter the current value
muc_current = generateXID(muc_current, 'groupchat');
// Add the current value
if(!existArrayValue(new_arr, muc_current))
new_arr.push(muc_current);
}
// Join the chats
if(new_arr.length) {
for(g in new_arr)
checkChatCreate(new_arr[g], 'groupchat');
}
}

View file

@ -0,0 +1,371 @@
/*
Jappix - An open social platform
These are the homepage JS scripts for Jappix
-------------------------------------------------
License: AGPL
Authors: Vanaryon, LinkMauve
Last revision: 15/01/12
*/
// Allows the user to switch the difference home page elements
function switchHome(div) {
// Path to
var home = '#home .';
var right = home + 'right ';
var current = right + '.homediv.' + div;
// We switch the div
$(right + '.homediv, ' + right + '.top').hide();
$(right + '.' + div).show();
// We reset the homedivs
$(home + 'homediv:not(.default), ' + home + 'top:not(.default)').remove();
// Get the HTML code to display
var disable_form = '';
var lock_host = '';
var code = '';
// Apply the previous link
switch(div) {
case 'loginer':
case 'anonymouser':
case 'registerer':
if(!exists(right + '.top.sub')) {
// Append the HTML code for previous link
$(right + '.top.default').after('<h1 class="top sub loginer anonymouser registerer">&laquo; <a href="#" class="previous">' + _e("Previous") + '</a></h1>');
// Click event on previous link
$(home + 'top.sub a.previous').click(function() {
return switchHome('default');
});
}
break;
}
// Apply the form
switch(div) {
// Login tool
case 'loginer':
lock_host = disableInput(LOCK_HOST, 'on');
code = '<p>' + printf(_e("Login to your existing XMPP account. You can also use the %s to join a groupchat."), '<a href="#" class="to-anonymous">' + _e("anonymous mode") + '</a>') + '</p>' +
'<form action="#" method="post">' +
'<fieldset>' +
'<legend>' + _e("Required") + '</legend>' +
'<label for="lnick">' + _e("Address") + '</label>' +
'<input type="text" class="nick" id="lnick" pattern="[^@/]+" required="" /><span class="jid">@</span><input type="text" class="server" id="lserver" value="' + HOST_MAIN + '" ' + lock_host + ' pattern="[^@/]+" required="" />' +
'<label for="lpassword">' + _e("Password") + '</label>' +
'<input type="password" class="password" id="lpassword" required="" />' +
'<label for="lremember">' + _e("Remember me") + '</label>' +
'<input type="checkbox" class="remember" id="lremember" />' +
'</fieldset>' +
'<a href="#" class="advanced home-images">' + _e("Advanced") + '</a>' +
'<fieldset class="advanced">' +
'<legend>' + _e("Advanced") + '</legend>' +
'<label for="lresource">' + _e("Resource") + '</label>' +
'<input type="text" class="resource" id="lresource" value="' + JAPPIX_RESOURCE + '" />' +
'<label for="lpriority">' + _e("Priority") + '</label>' +
'<select class="priority" id="lpriority">' +
'<option value="1">' + _e("Low") + '</option>' +
'<option value="10" selected="">' + _e("Medium") + '</option>' +
'<option value="100">' + _e("High") + '</option>' +
'</select>' +
'</fieldset>' +
'<input type="submit" value="' + _e("Here we go!") + '" />' +
'</form>';
break;
// Anonymous login tool
case 'anonymouser':
disable_form = disableInput(ANONYMOUS, 'off');
code = '<p>' + printf(_e("Enter the groupchat you want to join and the nick you want to have. You can also go back to the %s."), '<a href="#" class="to-home">' + _e("login page") + '</a>') + '</p>' +
'<form action="#" method="post">' +
'<fieldset>' +
'<legend>' + _e("Required") + '</legend>' +
'<label>' + _e("Room") + '</label>' +
'<input type="text" class="room"' + disable_form + ' pattern="[^/]+" required="" />' +
'<label>' + _e("Nickname") + '</label>' +
'<input type="text" class="nick"' + disable_form + ' required="" />' +
'</fieldset>' +
'<input type="submit" value="' + _e("Here we go!") + '"' + disable_form + ' />' +
'</form>' +
'<div class="info report">' +
_e("Share this link with your friends:") + ' <span></span>' +
'</div>';
break;
// Register tool
case 'registerer':
disable_form = disableInput(REGISTRATION, 'off');
if(!disable_form)
lock_host = disableInput(LOCK_HOST, 'on');
code = '<p>' + _e("Register a new XMPP account to join your friends on your own social cloud. That's simple!") + '</p>' +
'<form action="#" method="post">' +
'<fieldset>' +
'<legend>' + _e("Required") + '</legend>' +
'<label for="rnick">' + _e("Address") + '</label>' +
'<input type="text" class="nick" id="rnick" ' + disable_form + ' pattern="[^@/]+" required="" /><span class="jid">@</span><input type="text" class="server" id="rserver" value="' + HOST_MAIN + '" ' + disable_form + lock_host + ' pattern="[^@/]+" required="" />' +
'<label for="rpassword">' + _e("Password") + '</label>' +
'<input type="password" class="password" id="rpassword" ' + disable_form + ' required="" />' +
'<label for="spassword">' + _e("Confirm") + '</label><input type="password" class="spassword" id="spassword" ' + disable_form + ' required="" />' +
'</fieldset>' +
'<input type="submit" value="' + _e("Here we go!") + '" ' + disable_form + '/>' +
'</form>';
break;
}
// Form disabled?
if(disable_form)
code += '<div class="info fail">' +
_e("This tool has been disabled, you cannot use it!") +
'</div>';
// Create this HTML code
if(code && !exists(current)) {
// Append it!
$(right + '.homediv.default').after('<div class="' + div + ' homediv">' + code + '</div>');
// Create the attached events
switch(div) {
// Login tool
case 'loginer':
$(current + ' a.to-anonymous').click(function() {
return switchHome('anonymouser');
});
$(current + ' a.advanced').click(showAdvanced);
$(current + ' form').submit(loginForm);
break;
// Anonymous login tool
case 'anonymouser':
$(current + ' a.to-home').click(function() {
return switchHome('loginer');
});
$(current + ' form').submit(doAnonymous);
// Keyup event on anonymous join's room input
$(current + ' input.room').keyup(function() {
var value = $(this).val();
var report = current + ' .report';
var span = report + ' span';
if(!value) {
$(report).hide();
$(span).text('');
}
else {
$(report).show();
$(span).text(JAPPIX_LOCATION + '?r=' + value);
}
});
break;
// Register tool
case 'registerer':
$(current + ' form').submit(registerForm);
break;
}
}
// We focus on the first input
$(document).oneTime(10, function() {
$(right + 'input:visible:first').focus();
});
return false;
}
// Allows the user to display the advanced login options
function showAdvanced() {
// Hide the link
$('#home a.advanced').hide();
// Show the fieldset
$('#home fieldset.advanced').show();
return false;
}
// Reads the login form values
function loginForm() {
// We get the values
var lPath = '#home .loginer ';
var lServer = $(lPath + '.server').val();
var lNick = $(lPath + '.nick').val();
var lPass = $(lPath + '.password').val();
var lResource = $(lPath + '.resource').val();
var lPriority = $(lPath + '.priority').val();
var lRemember = $(lPath + '.remember').filter(':checked').size();
// Enough values?
if(lServer && lNick && lPass && lResource && lPriority)
doLogin(lNick, lServer, lPass, lResource, lPriority, lRemember);
// Something is missing?
else {
$(lPath + 'input[type=text], ' + lPath + 'input[type=password]').each(function() {
var select = $(this);
if(!select.val())
$(document).oneTime(10, function() {
select.addClass('please-complete').focus();
});
else
select.removeClass('please-complete');
});
}
return false;
}
// Reads the register form values
function registerForm() {
var rPath = '#home .registerer ';
// Remove the success info
$(rPath + '.success').remove();
// Get the values
var username = $(rPath + '.nick').val();
var domain = $(rPath + '.server').val();
var pass = $(rPath + '.password').val();
var spass = $(rPath + '.spassword').val();
// Enough values?
if(domain && username && pass && spass && (pass == spass)) {
// We remove the not completed class to avoid problems
$('#home .registerer input').removeClass('please-complete');
// Fire the register event!
doRegister(username, domain, pass);
}
// Something is missing?
else {
$(rPath + 'input[type=text], ' + rPath + 'input[type=password]').each(function() {
var select = $(this);
if(!select.val() || (select.is('#spassword') && pass && (pass != spass)))
$(document).oneTime(10, function() {
select.addClass('please-complete').focus();
});
else
select.removeClass('please-complete');
});
}
return false;
}
// Plugin launcher
function launchHome() {
// Define the vars
var home = '#home ';
var button = home + 'button';
var corp = home + '.corporation';
var locale = home + '.locale';
// Removes the <noscript /> elements to lighten the DOM
$('noscript').remove();
// Allows the user to switch the home page
$(button).click(function() {
// Login button
if($(this).is('.login'))
return switchHome('loginer');
// Register button
else
return switchHome('registerer');
});
// Allows the user to view the corporation infobox
$(corp).hover(function() {
$(corp).addClass('hovered');
}, function() {
$(corp).removeClass('hovered');
});
// Allows the user to switch the language
$(locale).hover(function() {
// Initialize the HTML code
var keepget = $(locale).attr('data-keepget');
var html = '<div class="list">';
// Generate each locale HTML code
for(i in LOCALES_AVAILABLE_ID)
html += '<a href="./?l=' + LOCALES_AVAILABLE_ID[i] + keepget + '">' + LOCALES_AVAILABLE_NAMES[i].htmlEnc() + '</a>';
html += '</div>';
// Append the HTML code
$(locale).append(html);
}, function() {
$(locale + ' .list').remove();
});
// Disables the browser HTTP-requests stopper
$(document).keydown(function(e) {
if((e.keyCode == 27) && !isDeveloper())
return false;
});
// Warns for an obsolete browser
if(isObsolete()) {
// Add the code
$(locale).after(
'<div class="obsolete">' +
'<p>' + _e("Your browser is out of date!") + '</p>' +
'<a class="firefox browsers-images" title="' + printf(_e("Last %s version is better!"), 'Mozilla Firefox') + '" href="http://www.mozilla.com/firefox/"></a>' +
'<a class="chrome browsers-images" title="' + printf(_e("Last %s version is better!"), 'Google Chrome') + '" href="http://www.google.com/chrome"></a>' +
'<a class="safari browsers-images" title="' + printf(_e("Last %s version is better!"), 'Safari') + '" href="http://www.apple.com/safari/"></a>' +
'<a class="opera browsers-images" title="' + printf(_e("Last %s version is better!"), 'Opera') + '" href="http://www.opera.com/"></a>' +
'<a class="ie browsers-images" title="' + printf(_e("Last %s version is better!"), 'Internet Explorer') + '" href="http://www.microsoft.com/hk/windows/internet-explorer/"></a>' +
'</div>'
);
// Display it later
$(home + '.obsolete').oneTime('1s', function() {
$(this).slideDown();
});
logThis('Jappix does not support this browser!', 2);
}
logThis('Welcome to Jappix! Happy coding in developer mode!');
}
// Launch this plugin!
$(document).ready(launchHome);

View file

@ -0,0 +1,41 @@
/*
Jappix - An open social platform
These are the http-auth JS scripts for Jappix
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 16/11/10
*/
// Replies to a HTTP request
function requestReply(value, xml) {
// We parse the xml content
var from = fullXID(getStanzaFrom(xml));
var confirm = $(xml.getNode()).find('confirm');
var xmlns = confirm.attr('xmlns');
var id = confirm.attr('id');
var method = confirm.attr('method');
var url = confirm.attr('url');
// We generate the reply message
var aMsg = new JSJaCMessage();
aMsg.setTo(from);
// If "no"
if(value == 'no') {
aMsg.setType('error');
aMsg.appendNode('error', {'code': '401', 'type': 'auth'});
}
// We set the confirm node
aMsg.appendNode('confirm', {'xmlns': xmlns, 'url': url, 'id': id, 'method': method});
// We send the message
con.send(aMsg, handleErrorReply);
logThis('Replying HTTP auth request: ' + from, 3);
}

View file

@ -0,0 +1,694 @@
/*
Jappix - An open social platform
These are the inbox JS script for Jappix
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 08/06/11
*/
// Opens the inbox popup
function openInbox() {
// Popup HTML content
var html =
'<div class="top">' + _e("Your inbox") + '</div>' +
'<div class="content">' +
'<div class="head inbox-head">' +
'<div class="head-text inbox-head-text">' + _e("Available actions") + '</div>' +
'<div class="head-actions inbox-head-actions">' +
'<a href="#" class="a-delete-messages">' + _e("Clean") + '</a>' +
'<a href="#" class="a-new-message">' + _e("New") + '</a>' +
'<a href="#" class="a-show-messages">' + _e("Received") + '</a>' +
'</div>' +
'</div>' +
'<div class="inbox-results">' +
'<p class="inbox-noresults">' + _e("Your inbox is empty.") + '</p>' +
'<div class="inbox"></div>' +
'</div>' +
'<div class="inbox-new">' +
'<div class="inbox-new-to inbox-new-block search">' +
'<p class="inbox-new-text">' + _e("To") + '</p>' +
'<input name="inbox-new-to-input" class="inbox-new-input inbox-new-to-input" type="text" required="" />' +
'</div>' +
'<div class="inbox-new-topic inbox-new-block">' +
'<p class="inbox-new-text">' + _e("Subject") + '</p>' +
'<input name="inbox-new-subject-input" class="inbox-new-input inbox-new-subject-input" type="text" required="" />' +
'</div>' +
'<div class="inbox-new-body inbox-new-block">' +
'<p class="inbox-new-text">' + _e("Content") + '</p>' +
'<textarea class="inbox-new-textarea" rows="8" cols="60" required=""></textarea>' +
'</div>' +
'<form class="inbox-new-file inbox-new-block" action="./php/file-share.php" method="post" enctype="multipart/form-data">' +
'<p class="inbox-new-text">' + _e("File") + '</p>' +
generateFileShare() +
'</form>' +
'<div class="inbox-new-send inbox-new-block">' +
'<a href="#" class="send one-button talk-images">' + _e("Send message") + '</a>' +
'</div>' +
'</div>' +
'</div>' +
'<div class="bottom">' +
'<div class="wait wait-medium"></div>' +
'<a href="#" class="finish">' + _e("Close") + '</a>' +
'</div>';
// Create the popup
createPopup('inbox', html);
// Associate the events
launchInbox();
// Load the messages
loadInbox();
return false;
}
// Closes the inbox popup
function closeInbox() {
// Destroy the popup
destroyPopup('inbox');
return false;
}
// Opens the message compose tool
function composeInboxMessage(xid) {
// Open things
openInbox();
newInboxMessage();
// Apply XID
$('#inbox .inbox-new-to-input').val(xid);
// Focus to the next item
$(document).oneTime(10, function() {
$('#inbox .inbox-new-subject-input').focus();
});
return false;
}
// Stores the inbox
function storeInbox() {
var iq = new JSJaCIQ();
iq.setType('set');
var query = iq.setQuery(NS_PRIVATE);
var storage = query.appendChild(iq.buildNode('storage', {'xmlns': NS_INBOX}));
for(var i = 0; i < sessionStorage.length; i++) {
// Get the pointer values
var current = sessionStorage.key(i);
// If the pointer is on a stored message
if(explodeThis('_', current, 0) == 'inbox') {
// Get the values
var value = $(XMLFromString(sessionStorage.getItem(current)));
// Create the storage node
storage.appendChild(iq.buildNode('message', {
'id': value.find('id').text().revertHtmlEnc(),
'from': value.find('from').text().revertHtmlEnc(),
'subject': value.find('subject').text().revertHtmlEnc(),
'status': value.find('status').text().revertHtmlEnc(),
'date': value.find('date').text().revertHtmlEnc(),
'xmlns': NS_INBOX
},
value.find('content').text().revertHtmlEnc()
));
}
}
con.send(iq);
}
// Creates a new normal message
function newInboxMessage() {
// Init
var mPath = '#inbox .';
// Reset the previous buddy search
resetBuddySearch('#inbox .inbox-new-to');
// We switch the divs
$(mPath + 'inbox-results, #inbox .a-new-message, #inbox .a-delete-messages').hide();
$(mPath + 'inbox-new, #inbox .a-show-messages').show();
// We focus on the first input
$(document).oneTime(10, function() {
$(mPath + 'inbox-new-to-input').focus();
});
// We reset some stuffs
cleanNewInboxMessage();
return false;
}
// Cleans the inbox
function cleanNewInboxMessage() {
// Init
var mPath = '#inbox .';
// We reset the forms
$(mPath + 'inbox-new-block:not(form) input, ' + mPath + 'inbox-new textarea').val('').removeClass('please-complete');
$(mPath + 'inbox-new-file a').remove();
$(mPath + 'inbox-new-file input').show();
// We close an eventual opened message
$(mPath + 'message-content').remove();
$(mPath + 'one-message').removeClass('message-reading');
}
// Sends a normal message
function sendInboxMessage(to, subject, body) {
// We send the message
var mess = new JSJaCMessage();
// Main attributes
mess.setTo(to);
mess.setSubject(subject);
mess.setType('normal');
// Any file to attach?
var attached = '#inbox .inbox-new-file a.file';
if(exists(attached))
body += '\n' +
'\n' +
$(attached).attr('data-attachedtitle') + ' - ' + $(attached).attr('data-attachedhref');
// Set body
mess.setBody(body);
con.send(mess, handleErrorReply);
}
// Performs the normal message sender checks
function checkInboxMessage() {
// We get some informations
var mPath = '#inbox ';
var to = $(mPath + '.inbox-new-to-input').val();
var body = $(mPath + '.inbox-new-textarea').val();
var subject = $(mPath + '.inbox-new-subject-input').val();
if(to && body && subject) {
// New array of XID
var xid = new Array(to);
// More than one XID
if(to.indexOf(',') != -1)
xid = to.split(',');
for(i in xid) {
var current = xid[i];
// No current value?
if(!current || current.match(/^(\s+)$/))
continue;
// Edit the XID if needed
current = current.replace(/ /g, '');
current = generateXID(current, 'chat');
// We send the message
sendInboxMessage(current, subject, body);
// We clean the inputs
cleanNewInboxMessage();
logThis('Inbox message sent: ' + current, 3);
}
// Close the inbox
closeInbox();
}
else {
$(mPath + 'input[type=text], ' + mPath + 'textarea').each(function() {
var current = this;
if(!$(current).val()) {
$(document).oneTime(10, function() {
$(current).addClass('please-complete').focus();
});
}
else
$(current).removeClass('please-complete');
});
}
return false;
}
// Shows the inbox messages
function showInboxMessages() {
// Init
var mPath = '#inbox .';
// We switch the divs
$(mPath + 'inbox-new').hide();
$(mPath + 'inbox-results').show();
// We show a new link in the menu
$(mPath + 'a-show-messages').hide();
$(mPath + 'a-delete-messages').show();
$(mPath + 'a-new-message').show();
// We reset some stuffs
cleanNewInboxMessage();
return false;
}
// Displays a normal message
function displayInboxMessage(from, subject, content, status, id, date) {
// Generate some paths
var inbox = '#inbox .';
var one_message = inbox + 'one-message.' + id;
// Message yet displayed!
if(exists(one_message))
return false;
// Get the nearest element
var stamp = extractStamp(Date.jab2date(date));
var nearest = sortElementByStamp(stamp, '#inbox .one-message');
// Get the buddy name
var name = getBuddyName(from).htmlEnc();
// We generate the html code
var nContent = '<div class="one-message message-' + status + ' ' + id + ' ' + hex_md5(from) + '" data-stamp="' + stamp + '">' +
'<div class="message-head">' +
'<div class="avatar-container">' +
'<img class="avatar" src="' + './img/others/default-avatar.png' + '" alt="" />' +
'</div>' +
'<div class="message-jid">' + name + '</div>' +
'<div class="message-subject">' + subject.htmlEnc() + '</div>' +
'<div class="message-truncated">' + truncate(noLines(content), 90).htmlEnc() + '</div>' +
'</div>' +
'</div>';
// Display the message
if(nearest == 0)
$(inbox + 'inbox-results .inbox').append(nContent);
else
$('#inbox .one-message[data-stamp=' + nearest + ']:first').before(nContent);
// Click events
$(one_message + ' .message-head').click(function() {
if(!exists(one_message + ' .message-content'))
revealInboxMessage(id, from, subject, content, name, date, status);
else
hideInboxMessage(id);
return false;
});
// Get the user avatar
getAvatar(from, 'cache', 'true', 'forget');
return true;
}
// Stores an inbox message
function storeInboxMessage(from, subject, content, status, id, date) {
// Initialize the XML data
var xml = '<message><id>' + id.htmlEnc().htmlEnc() + '</id><date>' + date.htmlEnc().htmlEnc() + '</date><from>' + from.htmlEnc().htmlEnc() + '</from><subject>' + subject.htmlEnc().htmlEnc() + '</subject><status>' + status.htmlEnc().htmlEnc() + '</status><content>' + content.htmlEnc().htmlEnc() + '</content>';
// End the XML data
xml += '</message>';
// Store this message!
setDB('inbox', id, xml);
}
// Removes a given normal message
function deleteInboxMessage(id) {
// Remove the message from the inbox
$('#inbox .one-message.' + id).remove();
// Remove the message from the database
removeDB('inbox', id);
// Check the unread messages
checkInboxMessages();
// Store the new inbox
storeInbox();
return false;
}
// Removes all the inbox messages
function purgeInbox() {
// Remove all the messages from the database
for(var i = 0; i < sessionStorage.length; i++) {
// Get the pointer values
var current = sessionStorage.key(i);
// If the pointer is on a stored message
if(explodeThis('_', current, 0) == 'inbox')
removeDB('inbox', explodeThis('_', current, 1));
}
// Prevent the database lag
$(document).oneTime(100, function() {
// Store the new inbox
storeInbox();
// Remove all the messages from the inbox
$('#inbox .one-message').remove();
// Reload the inbox
loadInbox();
});
return false;
}
// Checks if there are new messages to be notified
function checkInboxMessages() {
// Selectors
var inbox_link = '#top-content a.inbox-hidable';
var no_results = '#inbox .inbox-noresults';
// Marker
var has_messages = false;
// Read the number of unread messages
var unread = 0;
// Read the local inbox database
for(var i = 0; i < sessionStorage.length; i++) {
// Database pointer
var current = sessionStorage.key(i);
// Check inbox messages
if(explodeThis('_', current, 0) == 'inbox') {
// Read the current status
var status = $(XMLFromString(sessionStorage.getItem(current))).find('status').text();
// Found an unread message
if(status == 'unread')
unread++;
// Update the marker
has_messages = true;
}
}
// No message?
if(!has_messages)
$(no_results).show();
else
$(no_results).hide();
// Reset notifications
$(inbox_link + ' .notify').remove();
// Any unread message?
if(unread) {
// Notify the user
$(inbox_link).prepend('<div class="notify one-counter" data-counter="' + unread + '">' + unread + '</div>');
// Update the title
updateTitle();
return true;
}
// Anyway, update the title
updateTitle();
return false;
}
// Reveal a normal message content
function revealInboxMessage(id, from, subject, content, name, date, status) {
// Message path
var all_message = '#inbox .one-message';
var one_message = all_message + '.' + id;
var one_content = one_message + ' .message-content';
// We reset all the other messages
$(all_message + ' .message-content').remove();
$(all_message).removeClass('message-reading');
// Message content
var html =
'<div class="message-content">' +
'<div class="message-body">' + filterThisMessage(content, name, true) + '</div>' +
'<div class="message-meta">' +
'<span class="date">' + parseDate(date) + '</span>' +
'<a href="#" class="reply one-button talk-images">' + _e("Reply") + '</a>' +
'<a href="#" class="remove one-button talk-images">' + _e("Delete") + '</a>' +
'<div class="clear">' +
'</div>' +
'</div>';
// Message content
html += '</div>';
$(one_message).append(html).addClass('message-reading');
// Click events
$(one_content + ' a.reply').click(function() {
return replyInboxMessage(id, from, subject, content);
});
$(one_content + ' a.remove').click(function() {
return deleteInboxMessage(id);
});
// Unread message
if(status == 'unread') {
// Update our database
var xml = getDB('inbox', id).replace(/<status>unread<\/status>/i,'<status>read</status>');
setDB('inbox', id, xml);
// Remove the unread class
$(one_message).removeClass('message-unread');
// Send it to the server!
storeInbox();
}
// Check the unread messages
checkInboxMessages();
}
// Hides a normal message content
function hideInboxMessage(id) {
// Define the paths
var inbox = '#inbox .';
var one_message = inbox + 'one-message.' + id;
// Reset this message
$(one_message).removeClass('message-reading');
$(one_message + ' .message-content').remove();
}
// Replies to a given normal message
function replyInboxMessage(id, from, subject, body) {
// We switch to the writing div
newInboxMessage();
// Inbox path
var inbox = '#inbox .';
// Generate the body
var body = '\n' + '____________' + '\n\n' + truncate(body, 120);
// We apply the generated values to the form
$(inbox + 'inbox-new-to-input').val(from);
$(inbox + 'inbox-new-subject-input').val(subject);
$(document).oneTime(10, function() {
$(inbox + 'inbox-new-textarea').val(body).focus().selectRange(1, 0);
});
return false;
}
// Loads the inbox messages
function loadInbox() {
// Read the local database
for(var i = 0; i < sessionStorage.length; i++) {
// Get the pointer values
var current = sessionStorage.key(i);
// If the pointer is on a stored message
if(explodeThis('_', current, 0) == 'inbox') {
// Get the current value
var value = $(XMLFromString(sessionStorage.getItem(current)));
// Display the current message
displayInboxMessage(
value.find('from').text().revertHtmlEnc(),
value.find('subject').text().revertHtmlEnc(),
value.find('content').text().revertHtmlEnc(),
value.find('status').text().revertHtmlEnc(),
value.find('id').text().revertHtmlEnc(),
value.find('date').text().revertHtmlEnc()
);
}
}
// Check new messages
checkInboxMessages();
}
// Wait event for file attaching
function waitInboxAttach() {
$('#inbox .wait').show();
}
// Success event for file attaching
function handleInboxAttach(responseXML) {
// Data selector
var dData = $(responseXML).find('jappix');
// Process the returned data
if(dData.find('error').size()) {
openThisError(4);
logThis('Error while attaching the file: ' + dData.find('error').text(), 1);
}
else {
// Get the file values
var fName = dData.find('title').text();
var fType = dData.find('type').text();
var fURL = dData.find('href').text();
// Hide the attach link, show the unattach one
$('#inbox .inbox-new-file input').hide();
$('#inbox .inbox-new-file').append('<a class="file ' + encodeQuotes(fileCategory(explodeThis('/', fType, 1))) + ' talk-images" href="' + encodeQuotes(fURL) + '" target="_blank">' + fName.htmlEnc() + '</a><a href="#" class="remove one-button talk-images">' + _e("Remove") + '</a>');
// Set values to the file link
$('#inbox .inbox-new-file a.file').attr('data-attachedtitle', fName)
.attr('data-attachedhref', fURL);
// Click events
$('#inbox .inbox-new-file a.remove').click(function() {
$('#inbox .inbox-new-file a').remove();
$('#inbox .inbox-new-file input').show();
return false;
});
logThis('File attached.', 3);
}
// Reset the attach bubble
$('#inbox .inbox-new-file input[type=file]').val('');
$('#inbox .wait').hide();
}
// Plugin launcher
function launchInbox() {
// Define the pats
var inbox = '#inbox .';
// Define the buddy search vars
var destination = inbox + 'inbox-new-to';
var dHovered = destination + ' ul li.hovered:first';
// Send the message when enter pressend
$(inbox + 'inbox-new input').keyup(function(e) {
if(e.keyCode == 13) {
if(exists(dHovered))
addBuddySearch(destination, $(dHovered).attr('data-xid'));
else
checkInboxMessage();
}
});
// Buddy search
$(inbox + 'inbox-new-to-input').keyup(function(e) {
if(e.keyCode != 13) {
// New buddy search
if((e.keyCode != 40) && (e.keyCode != 38))
createBuddySearch(destination);
// Navigating with keyboard in the results
arrowsBuddySearch(e, destination);
}
})
// Buddy search lost focus
.blur(function() {
if(!$(destination + ' ul').attr('mouse-hover'))
resetBuddySearch(destination);
})
// Buddy search got focus
.focus(function() {
var value = $(this).val();
// Add a comma at the end
if(value && !value.match(/^(.+)((,)(\s)?)$/))
$(this).val(value + ', ');
});
// Click events
$(inbox + 'a-delete-messages').click(purgeInbox);
$(inbox + 'a-new-message').click(newInboxMessage);
$(inbox + 'a-show-messages').click(showInboxMessages);
$(inbox + 'inbox-new-send a').click(checkInboxMessage);
$(inbox + 'bottom .finish').click(function() {
return closeInbox();
});
// File upload
var attach_options = {
dataType: 'xml',
beforeSubmit: waitInboxAttach,
success: handleInboxAttach
};
// Upload form submit event
$('#inbox .inbox-new-file').submit(function() {
if($('#inbox .wait').is(':hidden') && $('#inbox .inbox-new-file input[type=file]').val())
$(this).ajaxSubmit(attach_options);
return false;
});
// Upload input change event
$('#inbox .inbox-new-file input[type=file]').change(function() {
if($('#inbox .wait').is(':hidden') && $(this).val())
$('#inbox .inbox-new-file').ajaxSubmit(attach_options);
return false;
});
}

View file

@ -0,0 +1,340 @@
/*
Jappix - An open social platform
These are the integratebox JS scripts for Jappix
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 03/12/11
*/
// Opens the integratebox popup
function openIntegrateBox() {
// Popup HTML content
var html =
'<div class="top">' + _e("Media viewer") + '</div>' +
'<div class="content"></div>' +
'<div class="bottom">' +
'<div class="wait wait-medium"></div>' +
'<a href="#" class="finish close">' + _e("Close") + '</a>' +
'<a href="#" class="finish next disabled" title="' + _e("Next") + '">&gt;</a>' +
'<a href="#" class="finish previous disabled" title="' + _e("Previous") + '">&lt;</a>' +
'</div>';
// Create the popup
createPopup('integratebox', html);
// Associate the events
launchIntegratebox();
}
// Closes the integratebox popup
function closeIntegrateBox() {
// Destroy the popup
destroyPopup('integratebox');
return false;
}
// Generates the integratebox HTML code
function codeIntegrateBox(serv, url) {
var code = '';
// Protocol to use
var protocol = 'http';
if(isHTTPS())
protocol = 'https';
// Legacy browser
var legacy = false;
if((BrowserDetect.browser == 'Explorer') && (BrowserDetect.version < 9))
legacy = true;
// Switch to get the good DOM code
switch(serv) {
case 'youtube':
if(legacy)
code = '<object width="640" height="385"><param name="movie" value="http://www.youtube.com/v/' + url + '&amp;autoplay=1"></param><embed src="http://www.youtube.com/v/' + encodeQuotes(url) + '&amp;autoplay=1" type="application/x-shockwave-flash" width="640" height="385"></embed></object>';
else
code = '<object width="640" height="385" data="' + encodeQuotes(protocol) + '://www.youtube.com/embed/' + encodeQuotes(url) + '?autoplay=1" type="text/html"><a href="http://www.youtube.com/watch?v=' + encodeQuotes(url) + '" target="_blank">http://www.youtube.com/watch?v=' + encodeQuotes(url) + '</a></object>';
break;
case 'dailymotion':
code = '<object width="640" height="385"><param name="movie" value="http://www.dailymotion.com/swf/video/' + url + '&amp;autoplay=1"></param><param name="allowFullScreen" value="false"></param><embed type="application/x-shockwave-flash" src="http://www.dailymotion.com/swf/video/' + encodeQuotes(url) + '&amp;autoplay=1" width="640" height="385" allowfullscreen="true" allowscriptaccess="always"></embed></object>';
break;
case 'vimeo':
code = '<object width="640" height="385"><param name="allowfullscreen" value="true" /><param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=' + encodeQuotes(url) + '&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=&amp;fullscreen=1&amp;autoplay=1" /><embed src="http://vimeo.com/moogaloop.swf?clip_id=' + encodeQuotes(url) + '&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=&amp;fullscreen=1&amp;autoplay=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="640" height="385"></embed></object>';
break;
case 'theora':
case 'video':
code = '<video width="640" height="385" src="' + encodeQuotes(url) + '" controls autoplay><a href="' + encodeQuotes(url) + '" target="_blank">' + encodeQuotes(url) + '</a></video>';
break;
case 'vorbis':
case 'audio':
code = '<audio src="' + encodeQuotes(url) + '" controls autoplay><a href="' + encodeQuotes(url) + '" target="_blank">' + encodeQuotes(url) + '</a></audio>';
break;
case 'image':
code = '<a href="' + encodeQuotes(url) + '" target="_blank"><img alt="" src="' + encodeQuotes(url) + '" /></a>';
break;
}
return code;
}
// Applies a given integratebox element
function applyIntegrateBox(url, service, url_list, services_list, comments_e_list, comments_n_list, width_style) {
// Close the integratebox
closeIntegrateBox();
// Media integration not wanted?
if(getDB('options', 'integratemedias') == '0')
return true;
// Apply the HTML code
var dom_code = codeIntegrateBox(service, url);
// Any code: apply it!
if(dom_code) {
// We show the integratebox
openIntegrateBox();
// We add the code to the DOM
$('#integratebox .content').prepend('<div class="one-media">' + dom_code + '</div>');
// Image waiting icon
if(service == 'image') {
var waitItem = $('#integratebox .wait');
// Show it while it is loading
waitItem.show();
// Hide it when it is loaded
$('#integratebox img').load(function() {
waitItem.hide();
// Center the image vertically
$(this).oneTime(10, function() {
$(this).css('margin-top', (($('#integratebox .content').height() - $(this).height()) / 2));
});
});
}
// Large style?
var comments_id = genID();
if(width_style == 'large') {
// Make the popup large
$('#integratebox .popup').addClass('large');
// Add the right content
$('#integratebox .content').after(
'<div class="comments" data-id="' + encodeQuotes(comments_id) + '">' +
'<div class="comments-content">' +
'<div class="one-comment loading"><span class="icon talk-images"></span>' + _e("Loading comments...") + '</div>' +
'</div>' +
'</div>'
);
}
// Previous and next items?
var url_array = stringToArray(url_list);
var services_array = stringToArray(services_list);
var comments_e_array = stringToArray(comments_e_list);
var comments_n_array = stringToArray(comments_n_list);
var index = indexArrayValue(url_array, url);
// Any comments?
if(exists('#integratebox .comments')) {
if(comments_e_array[index] && comments_n_array[index])
getCommentsMicroblog(comments_e_array[index], comments_n_array[index], comments_id);
else
$('#integratebox .comments .comments-content').html('<div class="one-comment loading"><span class="icon talk-images"></span>' + _e("Comments locked!") + '</div>');
}
// Get the previous values
var previous_url = url_array[index - 1];
var previous_services = services_array[index - 1];
// Get the next values
var next_url = url_array[index + 1];
var next_services = services_array[index + 1];
// Enable/disable buttons
if(previous_url && previous_services)
$('#integratebox .bottom .finish.previous').removeClass('disabled');
else
$('#integratebox .bottom .finish.previous').addClass('disabled');
if(next_url && next_services)
$('#integratebox .bottom .finish.next').removeClass('disabled');
else
$('#integratebox .bottom .finish.next').addClass('disabled');
// Click events
$('#integratebox .bottom .finish.previous, #integratebox .bottom .finish.next').click(function() {
// Not acceptable?
if($(this).is('.disabled'))
return false;
// Apply the event!
if($(this).is('.previous'))
applyIntegrateBox(previous_url, previous_services, url_list, services_list, comments_e_list, comments_n_list, width_style);
else
applyIntegrateBox(next_url, next_services, url_list, services_list, comments_e_list, comments_n_list, width_style);
return false;
});
if(width_style == 'large')
$('#integratebox .content a:has(img)').click(function() {
if(next_url && next_services)
applyIntegrateBox(next_url, next_services, url_list, services_list, comments_e_list, comments_n_list, width_style);
return false;
});
return false;
}
// Nothing: return true to be able to open the URL in a new tab
return true;
}
// Checks whether the file ext can use integratebox or not
function canIntegrateBox(ext) {
// Can use?
if(ext && ((ext == 'jpg') || (ext == 'jpeg') || (ext == 'png') || (ext == 'gif') || (ext == 'ogg') || (ext == 'oga') || (ext == 'ogv')))
return true;
return false;
}
// Filters a string to apply the integratebox links
function filterIntegrateBox(data) {
// Encapsulates the string into two <div /> elements
var xml = $('<div><div>' + data + '</div></div>').contents();
// Loop the <a /> elements
$(xml).find('a').each(function() {
// Initialize this element
var href = $(this).attr('href');
var to, url, service, event;
// XMPP ID
if(href.match(/^xmpp:(.+)/i))
to = RegExp.$1;
// YouTube video box
else if(href.match(/(\w{3,5})(:)(\S+)((\.youtube\.com\/watch(\?v|\?\S+v|\#\!v|\#\!\S+v)\=)|(youtu\.be\/))([^& ]+)((&amp;\S)|(&\S)|\s|$)/gim)) {
url = RegExp.$8;
service = 'youtube';
}
// Dailymotion video box
else if(href.match(/(\w{3,5})(:)(\S+)\.dailymotion\.com\/video\/([\w\-]+)((\#[\w\-]+)|\s|$)/gim)) {
url = RegExp.$4;
service = 'dailymotion';
}
// Vimeo video box
else if(href.match(/((\w{3,5})(:)(\S+)(vimeo|www\.vimeo)\.com\/([\w\-]+))/gim)) {
url = RegExp.$1;
service = 'vimeo';
}
// Theora video box
else if(href.match(/((\w{3,5})(:)(\S+)(\.)(ogv|ogg))/gim)) {
url = RegExp.$1;
service = 'theora';
}
// Vorbis audio box
else if(href.match(/((\w{3,5})(:)(\S+)(\.oga))/gim)) {
url = RegExp.$1;
service = 'vorbis';
}
// Image box
else if(href.match(/((\w{3,5})(:)(\S+)(\.)(jpg|jpeg|png|gif|tif|bmp))/gim)) {
url = RegExp.$1;
service = 'image';
}
// Define the good event
if(to)
event = 'xmppLink(\'' + encodeOnclick(to) + '\')';
else if(url && service)
event = 'applyIntegrateBox(\'' + encodeOnclick(url) + '\', \'' + encodeOnclick(service) + '\')';
// Any click event to apply?
if(event) {
// Regenerate the link element (for onclick)
var new_a = '<a';
var element_a = (this);
// Attributes
$(element_a.attributes).each(function(index) {
// Read the current attribute
var current_attr = element_a.attributes[index];
// Apply the current attribute
new_a += ' ' + encodeQuotes(current_attr.name) + '="' + encodeQuotes(current_attr.value) + '"';
});
// Add onclick attribute
new_a += ' onclick="return ' + event + ';"';
// Value
new_a += '>' + $(this).text().htmlEnc() + '</a>';
// Replace it!
$(this).replaceWith(new_a);
}
});
// Regenerate the HTML code (include string into a div to be readable)
var string = $(xml).html();
return string;
}
// Plugin launcher
function launchIntegratebox() {
// Click event
$('#integratebox .bottom .finish.close').click(closeIntegrateBox);
}
// Plugin keyup event
$(document).keyup(function(e) {
// Previous item?
if((exists('#integratebox .bottom .finish.previous:not(.disabled)')) && (e.keyCode == 37)) {
$('#integratebox .bottom .finish.previous').click();
return false;
}
// Next item?
if((exists('#integratebox .bottom .finish.next:not(.disabled)')) && (e.keyCode == 39)) {
$('#integratebox .bottom .finish.next').click();
return false;
}
});

View file

@ -0,0 +1,386 @@
/*
Jappix - An open social platform
These are the interface JS scripts for Jappix
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 26/08/11
*/
// Changes the title of the document
function pageTitle(title) {
// Anonymous mode?
var head_name = getName();
if(isAnonymous())
head_name = ANONYMOUS_ROOM + ' (' + _e("anonymous mode") + ')';
// We change the title to give essential informations
switch(title) {
case 'home':
document.title = SERVICE_NAME + ' • ' + _e("An open social network");
break;
case 'talk':
document.title = 'Jappix • ' + head_name;
break;
case 'new':
document.title = '[' + pendingEvents() + '] Jappix • ' + head_name;
break;
case 'wait':
document.title = 'Jappix • ' + _e("Please wait...");
break;
}
}
// Creates a general-wait item
function showGeneralWait() {
// Item exists?
if(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;
}
// Removes the general-wait item
function removeGeneralWait() {
$('#general-wait').remove();
}
// Generates a file upload valid form content
function generateFileShare() {
return '<input type="hidden" name="MAX_FILE_SIZE" value="' + encodeQuotes(JAPPIX_MAX_FILE_SIZE) + '">' +
'<input type="hidden" name="user" value="' + encodeQuotes(getXID()) + '" />' +
'<input type="hidden" name="location" value="' + encodeQuotes(generateURL(JAPPIX_LOCATION)) + '" />' +
'<input type="hidden" name="id" value="' + (new Date()).getTime() + '" />' +
'<input type="file" name="file" required="" />' +
'<input type="submit" value="' + _e("Send") + '" />';
}
// Switches to the given chan
function switchChan(id) {
if(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')
autoScroll(id);
// Manage input focus
inputFocus();
}
return false;
}
// Loads the complete chat switcher
function loadChatSwitch() {
// Path
var more_content = '#page-switch .more-content';
// Yet displayed?
if(exists(more_content))
return closeBubbles();
// Add the bubble
showBubble(more_content);
// Append the content
$('#page-switch .more').append(
'<div class="more-content bubble removable">' +
$('#page-switch .chans').html() +
'</div>'
);
return false;
}
// Puts the selected smiley in the good page-engine input
function insertSmiley(smiley, hash) {
// 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();
});
return false;
}
// Deletes all the associated elements of the chat we want to remove
function deleteThisChat(hash) {
$('#' + hash + ', #page-switch .' + hash).remove();
}
// Closes the given chat
function quitThisChat(xid, hash, type) {
if(type == 'groupchat') {
// Send our unavailable presence
sendPresence(xid + '/' + getMUCNick(hash), 'unavailable');
// Remove all presence database entries for this groupchat
for(var i = 0; i < sessionStorage.length; i++) {
// Get the pointer values
var current = sessionStorage.key(i);
var cXID = explodeThis('_', current, 1);
// If the pointer is on a presence from this groupchat
if((explodeThis('_', current, 0) == 'presence') && (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
removeDB('presence', cXID);
presenceFunnel(cXID, cHash);
}
}
}
else
chatStateSend('gone', xid, hash);
// Get the chat ID which is before
var previous = $('#' + hash).prev().attr('id');
// Remove the chat
deleteThisChat(hash);
// Reset the switcher
if(!exists('#page-switch .switcher.activechan'))
switchChan(previous);
// Reset the notifications
chanCleanNotify(hash);
return false;
}
// Generates the chat logs
function generateChatLog(xid, hash) {
// 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 = getXMPPTime('local');
var type = $('#' + hash).attr('data-type');
// 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('./php/generate-chat.php', { content: content, xid: xid, nick: nick, avatar: avatar, date: date, type: type }, function(data) {
// Handled!
$(path + 'tooltip-waitlog').replaceWith('<a class="tooltip-actionlog" href="./php/download-chat.php?id=' + data + '" target="_blank">' + _e("Download file!") + '</a>');
});
return false;
}
// Notifies the user from a new incoming message
function messageNotify(hash, type) {
// 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 || !isFocused()) {
if(!active) {
if(type == 'personnal')
$(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(exists('#' + hash + '[data-counter]'))
pending = parseInt($('#' + hash).attr('data-counter')) + 1;
$('#' + hash).attr('data-counter', pending);
}
// Update the page title
updateTitle();
}
// Returns the number of pending events
function pendingEvents() {
// Count the number of notifications
var number = 0;
$('.one-counter[data-counter]').each(function() {
number = number + parseInt($(this).attr('data-counter'));
});
return number;
}
// Updates the page title
function updateTitle() {
// Any pending events?
if(exists('.one-counter[data-counter]'))
pageTitle('new');
else
pageTitle('talk');
}
// Cleans the given chat notifications
function chanCleanNotify(hash) {
// 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
updateTitle();
}
// Scrolls to the last chat message
function autoScroll(hash) {
// Avoid a JS error
if(exists('#' + hash)) {
var container = document.getElementById('chat-content-' + hash);
// Scroll down!
container.scrollTop = container.scrollHeight;
}
}
// Shows all the buddies in the buddy-list
function showAllBuddies(from) {
// Put a marker
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
$('#buddy-list .group-buddies').show();
$('#buddy-list .group span').text('-');
// We show the disconnected buddies
$('.hidden-buddy').show();
// We show all the groups
$('#buddy-list .one-group').show();
if(SEARCH_FILTERED)
funnelFilterBuddySearch();
// Store this in the options
if((from == 'roster') && loadedOptions()) {
setDB('options', 'roster-showall', '1');
storeOptions();
}
}
// Shows only the online buddies in the buddy-list
function showOnlineBuddies(from) {
// Remove the marker
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
$('#buddy-list .group-buddies').show();
$('#buddy-list .group span').text('-');
// We hide the disconnected buddies
$('.hidden-buddy').hide();
// We check the groups to hide
updateGroups();
if(SEARCH_FILTERED)
funnelFilterBuddySearch();
// Store this in the options
if((from == 'roster') && loadedOptions()) {
setDB('options', 'roster-showall', '0');
storeOptions();
}
}
// Focuses on the right input
function inputFocus() {
// No popup shown
if(!exists('.popup'))
$(document).oneTime(10, function() {
$('.focusable:visible:first').focus();
});
}
// Plugin launcher
function launchInterface() {
// Focus on the first visible input
$(window).focus(inputFocus);
}
// Launch this plugin!
$(document).ready(launchInterface);

193
jappixmini/jappix/js/iq.js Normal file
View file

@ -0,0 +1,193 @@
/*
Jappix - An open social platform
These are the IQ JS scripts for Jappix
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 27/08/11
*/
// Handles an incoming IQ packet
function handleIQ(iq) {
// Gets the IQ content
var iqNode = iq.getNode();
var iqFrom = fullXID(getStanzaFrom(iq));
var iqID = iq.getID();
var iqQueryXMLNS = iq.getQueryXMLNS();
var iqQuery = iq.getQuery();
var iqType = iq.getType();
// Build the response
var iqResponse = new JSJaCIQ();
iqResponse.setID(iqID);
iqResponse.setTo(iqFrom);
iqResponse.setType('result');
// OOB request
if((iqQueryXMLNS == NS_IQOOB) && (iqType == 'set')) {
/* REF: http://xmpp.org/extensions/xep-0066.html */
handleOOB(iqFrom, iqID, 'iq', iqNode);
logThis('Received IQ OOB request: ' + iqFrom);
}
// OOB reply
else if(getDB('send/url', iqID)) {
// Get the values
var oob_url = getDB('send/url', iqID);
var oob_desc = getDB('send/desc', iqID);
var notif_id = hex_md5(oob_url + oob_desc + iqType + iqFrom + iqID);
// Error?
if($(iqNode).find('error').size()) {
// Rejected?
if($(iqNode).find('error not-acceptable').size())
newNotification('send_reject', iqFrom, [iqFrom, oob_url, 'iq', iqID, iqNode], oob_desc, notif_id);
// Failed?
else
newNotification('send_fail', iqFrom, [iqFrom, oob_url, 'iq', iqID, iqNode], oob_desc, notif_id);
// Remove the file
$.get(oob_url + '&action=remove');
}
// Success?
else if(iqType == 'result')
newNotification('send_accept', iqFrom, [iqFrom, oob_url, 'iq', iqID, iqNode], oob_desc, notif_id);
}
// Software version query
else if((iqQueryXMLNS == NS_VERSION) && (iqType == 'get')) {
/* REF: http://xmpp.org/extensions/xep-0092.html */
var iqQuery = iqResponse.setQuery(NS_VERSION);
iqQuery.appendChild(iq.buildNode('name', {'xmlns': NS_VERSION}, 'Jappix'));
iqQuery.appendChild(iq.buildNode('version', {'xmlns': NS_VERSION}, JAPPIX_VERSION));
iqQuery.appendChild(iq.buildNode('os', {'xmlns': NS_VERSION}, BrowserDetect.OS));
con.send(iqResponse);
logThis('Received software version query: ' + iqFrom);
}
// Last activity query
else if((iqQueryXMLNS == NS_LAST) && (iqType == 'get')) {
/* REF: http://xmpp.org/extensions/xep-0012.html */
var iqQuery = iqResponse.setQuery(NS_LAST);
iqQuery.setAttribute('seconds', getLastActivity());
con.send(iqResponse);
logThis('Received last activity query: ' + iqFrom);
}
// Privacy lists push
else if((iqQueryXMLNS == NS_PRIVACY) && (iqType == 'set')) {
// REF : http://xmpp.org/extensions/xep-0016.html
// Roster push
con.send(iqResponse);
// Get the lists
$(iqQuery).find('list').each(function() {
getPrivacy($(this).attr('name'));
});
logThis('Received privacy lists push: ' + iqFrom);
}
// Roster push
else if((iqQueryXMLNS == NS_ROSTER) && (iqType == 'set')) {
// REF : http://xmpp.org/extensions/xep-0092.html
// Roster push
con.send(iqResponse);
// Get the values
$(iqQuery).find('item').each(function() {
parseRoster($(this), 'presence');
});
logThis('Received roster push: ' + iqFrom);
}
// Roster Item Exchange query
else if($(iqNode).find('x[xmlns=' + NS_ROSTERX + ']').size()) {
// Open a new notification
newNotification('rosterx', iqFrom, [iqNode], '');
logThis('Roster Item Exchange from: ' + iqFrom);
}
// Disco info query
else if((iqQueryXMLNS == NS_DISCO_INFO) && (iqType == 'get')) {
/* REF: http://xmpp.org/extensions/xep-0030.html */
var iqQuery = iqResponse.setQuery(NS_DISCO_INFO);
// We set the name of the client
iqQuery.appendChild(iq.buildNode('identity', {
'category': 'client',
'type': 'web',
'name': 'Jappix',
'xmlns': NS_DISCO_INFO
}));
// We set all the supported features
var fArray = myDiscoInfos();
for(i in fArray)
iqQuery.appendChild(iq.buildNode('feature', {'var': fArray[i], 'xmlns': NS_DISCO_INFO}));
con.send(iqResponse);
logThis('Received disco#infos query: ' + iqFrom);
}
// User time query
else if($(iqNode).find('time').size() && (iqType == 'get')) {
/* REF: http://xmpp.org/extensions/xep-0202.html */
var iqTime = iqResponse.appendNode('time', {'xmlns': NS_URN_TIME});
iqTime.appendChild(iq.buildNode('tzo', {'xmlns': NS_URN_TIME}, getDateTZO()));
iqTime.appendChild(iq.buildNode('utc', {'xmlns': NS_URN_TIME}, getXMPPTime('utc')));
con.send(iqResponse);
logThis('Received local time query: ' + iqFrom);
}
// Ping
else if($(iqNode).find('ping').size() && (iqType == 'get')) {
/* REF: http://xmpp.org/extensions/xep-0199.html */
con.send(iqResponse);
logThis('Received a ping: ' + iqFrom);
}
// Not implemented
else if(!$(iqNode).find('error').size() && ((iqType == 'get') || (iqType == 'set'))) {
// Append stanza content
for(var i = 0; i < iqNode.childNodes.length; i++)
iqResponse.getNode().appendChild(iqNode.childNodes.item(i).cloneNode(true));
// Append error content
var iqError = iqResponse.appendNode('error', {'xmlns': NS_CLIENT, 'code': '501', 'type': 'cancel'});
iqError.appendChild(iq.buildNode('feature-not-implemented', {'xmlns': NS_STANZAS}));
iqError.appendChild(iq.buildNode('text', {'xmlns': NS_STANZAS}, _e("The feature requested is not implemented by the recipient or server and therefore cannot be processed.")));
con.send(iqResponse);
logThis('Received an unsupported IQ query from: ' + iqFrom);
}
}

View file

@ -0,0 +1,896 @@
/*
Jappix - An open social platform
These are the datepicker JS script
-------------------------------------------------
Licenses: MIT, GPL, AGPL
Authors: Stefan Petre, Vanaryon
Last revision: 19/12/10
*/
(function ($) {
var DatePicker = function () {
var ids = {},
views = {
years: 'datepickerViewYears',
moths: 'datepickerViewMonths',
days: 'datepickerViewDays'
},
tpl = {
wrapper: '<div class="datepicker"><div class="datepickerBorderT" /><div class="datepickerBorderB" /><div class="datepickerBorderL" /><div class="datepickerBorderR" /><div class="datepickerBorderTL" /><div class="datepickerBorderTR" /><div class="datepickerBorderBL" /><div class="datepickerBorderBR" /><div class="datepickerContainer"><table cellspacing="0" cellpadding="0"><tbody><tr></tr></tbody></table></div></div>',
head: [
'<td>',
'<table cellspacing="0" cellpadding="0">',
'<thead>',
'<tr>',
'<th class="datepickerGoPrev"><a href="#"><span><%=prev%></span></a></th>',
'<th colspan="6" class="datepickerMonth"><a href="#"><span></span></a></th>',
'<th class="datepickerGoNext"><a href="#"><span><%=next%></span></a></th>',
'</tr>',
'<tr class="datepickerDoW">',
'<th><span><%=week%></span></th>',
'<th><span><%=day1%></span></th>',
'<th><span><%=day2%></span></th>',
'<th><span><%=day3%></span></th>',
'<th><span><%=day4%></span></th>',
'<th><span><%=day5%></span></th>',
'<th><span><%=day6%></span></th>',
'<th><span><%=day7%></span></th>',
'</tr>',
'</thead>',
'</table></td>'
],
space : '<td class="datepickerSpace"><div></div></td>',
days: [
'<tbody class="datepickerDays">',
'<tr>',
'<th class="datepickerWeek"><a href="#"><span><%=weeks[0].week%></span></a></th>',
'<td class="<%=weeks[0].days[0].classname%>"><a href="#"><span><%=weeks[0].days[0].text%></span></a></td>',
'<td class="<%=weeks[0].days[1].classname%>"><a href="#"><span><%=weeks[0].days[1].text%></span></a></td>',
'<td class="<%=weeks[0].days[2].classname%>"><a href="#"><span><%=weeks[0].days[2].text%></span></a></td>',
'<td class="<%=weeks[0].days[3].classname%>"><a href="#"><span><%=weeks[0].days[3].text%></span></a></td>',
'<td class="<%=weeks[0].days[4].classname%>"><a href="#"><span><%=weeks[0].days[4].text%></span></a></td>',
'<td class="<%=weeks[0].days[5].classname%>"><a href="#"><span><%=weeks[0].days[5].text%></span></a></td>',
'<td class="<%=weeks[0].days[6].classname%>"><a href="#"><span><%=weeks[0].days[6].text%></span></a></td>',
'</tr>',
'<tr>',
'<th class="datepickerWeek"><a href="#"><span><%=weeks[1].week%></span></a></th>',
'<td class="<%=weeks[1].days[0].classname%>"><a href="#"><span><%=weeks[1].days[0].text%></span></a></td>',
'<td class="<%=weeks[1].days[1].classname%>"><a href="#"><span><%=weeks[1].days[1].text%></span></a></td>',
'<td class="<%=weeks[1].days[2].classname%>"><a href="#"><span><%=weeks[1].days[2].text%></span></a></td>',
'<td class="<%=weeks[1].days[3].classname%>"><a href="#"><span><%=weeks[1].days[3].text%></span></a></td>',
'<td class="<%=weeks[1].days[4].classname%>"><a href="#"><span><%=weeks[1].days[4].text%></span></a></td>',
'<td class="<%=weeks[1].days[5].classname%>"><a href="#"><span><%=weeks[1].days[5].text%></span></a></td>',
'<td class="<%=weeks[1].days[6].classname%>"><a href="#"><span><%=weeks[1].days[6].text%></span></a></td>',
'</tr>',
'<tr>',
'<th class="datepickerWeek"><a href="#"><span><%=weeks[2].week%></span></a></th>',
'<td class="<%=weeks[2].days[0].classname%>"><a href="#"><span><%=weeks[2].days[0].text%></span></a></td>',
'<td class="<%=weeks[2].days[1].classname%>"><a href="#"><span><%=weeks[2].days[1].text%></span></a></td>',
'<td class="<%=weeks[2].days[2].classname%>"><a href="#"><span><%=weeks[2].days[2].text%></span></a></td>',
'<td class="<%=weeks[2].days[3].classname%>"><a href="#"><span><%=weeks[2].days[3].text%></span></a></td>',
'<td class="<%=weeks[2].days[4].classname%>"><a href="#"><span><%=weeks[2].days[4].text%></span></a></td>',
'<td class="<%=weeks[2].days[5].classname%>"><a href="#"><span><%=weeks[2].days[5].text%></span></a></td>',
'<td class="<%=weeks[2].days[6].classname%>"><a href="#"><span><%=weeks[2].days[6].text%></span></a></td>',
'</tr>',
'<tr>',
'<th class="datepickerWeek"><a href="#"><span><%=weeks[3].week%></span></a></th>',
'<td class="<%=weeks[3].days[0].classname%>"><a href="#"><span><%=weeks[3].days[0].text%></span></a></td>',
'<td class="<%=weeks[3].days[1].classname%>"><a href="#"><span><%=weeks[3].days[1].text%></span></a></td>',
'<td class="<%=weeks[3].days[2].classname%>"><a href="#"><span><%=weeks[3].days[2].text%></span></a></td>',
'<td class="<%=weeks[3].days[3].classname%>"><a href="#"><span><%=weeks[3].days[3].text%></span></a></td>',
'<td class="<%=weeks[3].days[4].classname%>"><a href="#"><span><%=weeks[3].days[4].text%></span></a></td>',
'<td class="<%=weeks[3].days[5].classname%>"><a href="#"><span><%=weeks[3].days[5].text%></span></a></td>',
'<td class="<%=weeks[3].days[6].classname%>"><a href="#"><span><%=weeks[3].days[6].text%></span></a></td>',
'</tr>',
'<tr>',
'<th class="datepickerWeek"><a href="#"><span><%=weeks[4].week%></span></a></th>',
'<td class="<%=weeks[4].days[0].classname%>"><a href="#"><span><%=weeks[4].days[0].text%></span></a></td>',
'<td class="<%=weeks[4].days[1].classname%>"><a href="#"><span><%=weeks[4].days[1].text%></span></a></td>',
'<td class="<%=weeks[4].days[2].classname%>"><a href="#"><span><%=weeks[4].days[2].text%></span></a></td>',
'<td class="<%=weeks[4].days[3].classname%>"><a href="#"><span><%=weeks[4].days[3].text%></span></a></td>',
'<td class="<%=weeks[4].days[4].classname%>"><a href="#"><span><%=weeks[4].days[4].text%></span></a></td>',
'<td class="<%=weeks[4].days[5].classname%>"><a href="#"><span><%=weeks[4].days[5].text%></span></a></td>',
'<td class="<%=weeks[4].days[6].classname%>"><a href="#"><span><%=weeks[4].days[6].text%></span></a></td>',
'</tr>',
'<tr>',
'<th class="datepickerWeek"><a href="#"><span><%=weeks[5].week%></span></a></th>',
'<td class="<%=weeks[5].days[0].classname%>"><a href="#"><span><%=weeks[5].days[0].text%></span></a></td>',
'<td class="<%=weeks[5].days[1].classname%>"><a href="#"><span><%=weeks[5].days[1].text%></span></a></td>',
'<td class="<%=weeks[5].days[2].classname%>"><a href="#"><span><%=weeks[5].days[2].text%></span></a></td>',
'<td class="<%=weeks[5].days[3].classname%>"><a href="#"><span><%=weeks[5].days[3].text%></span></a></td>',
'<td class="<%=weeks[5].days[4].classname%>"><a href="#"><span><%=weeks[5].days[4].text%></span></a></td>',
'<td class="<%=weeks[5].days[5].classname%>"><a href="#"><span><%=weeks[5].days[5].text%></span></a></td>',
'<td class="<%=weeks[5].days[6].classname%>"><a href="#"><span><%=weeks[5].days[6].text%></span></a></td>',
'</tr>',
'</tbody>'
],
months: [
'<tbody class="<%=className%>">',
'<tr>',
'<td colspan="2"><a href="#"><span><%=data[0]%></span></a></td>',
'<td colspan="2"><a href="#"><span><%=data[1]%></span></a></td>',
'<td colspan="2"><a href="#"><span><%=data[2]%></span></a></td>',
'<td colspan="2"><a href="#"><span><%=data[3]%></span></a></td>',
'</tr>',
'<tr>',
'<td colspan="2"><a href="#"><span><%=data[4]%></span></a></td>',
'<td colspan="2"><a href="#"><span><%=data[5]%></span></a></td>',
'<td colspan="2"><a href="#"><span><%=data[6]%></span></a></td>',
'<td colspan="2"><a href="#"><span><%=data[7]%></span></a></td>',
'</tr>',
'<tr>',
'<td colspan="2"><a href="#"><span><%=data[8]%></span></a></td>',
'<td colspan="2"><a href="#"><span><%=data[9]%></span></a></td>',
'<td colspan="2"><a href="#"><span><%=data[10]%></span></a></td>',
'<td colspan="2"><a href="#"><span><%=data[11]%></span></a></td>',
'</tr>',
'</tbody>'
]
},
defaults = {
flat: false,
starts: 1,
prev: '&#9664;',
next: '&#9654;',
lastSel: false,
mode: 'single',
view: 'days',
calendars: 1,
format: 'Y-m-d',
position: 'bottom',
eventName: 'click',
onRender: function(){return {};},
onChange: function(){return true;},
onShow: function(){return true;},
onBeforeShow: function(){return true;},
onHide: function(){return true;},
locale: {
days: [_e("Sunday"), _e("Monday"), _e("Tuesday"), _e("Wednesday"), _e("Thursday"), _e("Friday"), _e("Saturday"), _e("Sunday")],
daysShort: [cut(_e("Sunday"), 3), cut(_e("Monday"), 3), cut(_e("Tuesday"), 3), cut(_e("Wednesday"), 3), cut(_e("Thursday"), 3), cut(_e("Friday"), 3), cut(_e("Saturday"), 3), cut(_e("Sunday"), 3)],
daysMin: [cut(_e("Sunday"), 2), cut(_e("Monday"), 2), cut(_e("Tuesday"), 2), cut(_e("Wednesday"), 2), cut(_e("Thursday"), 2), cut(_e("Friday"), 2), cut(_e("Saturday"), 2), cut(_e("Sunday"), 2)],
months: [_e("January"), _e("February"), _e("March"), _e("April"), _e("May"), _e("June"), _e("July"), _e("August"), _e("September"), _e("October"), _e("November"), _e("December")],
monthsShort: [cut(_e("January"), 3), cut(_e("February"), 3), cut(_e("March"), 3), cut(_e("April"), 3), cut(_e("May"), 3), cut(_e("June"), 3), cut(_e("July"), 3), cut(_e("August"), 3), cut(_e("September"), 3), cut(_e("October"), 3), cut(_e("November"), 3), cut(_e("December"), 3)],
weekMin: ''
}
},
fill = function(el) {
var options = $(el).data('datepicker');
var cal = $(el);
var currentCal = Math.floor(options.calendars/2), date, data, dow, month, cnt = 0, week, days, indic, indic2, html, tblCal;
cal.find('td>table tbody').remove();
for (var i = 0; i < options.calendars; i++) {
date = new Date(options.current);
date.addMonths(-currentCal + i);
tblCal = cal.find('table').eq(i+1);
switch (tblCal[0].className) {
case 'datepickerViewDays':
dow = formatDate(date, 'B, Y');
break;
case 'datepickerViewMonths':
dow = date.getFullYear();
break;
case 'datepickerViewYears':
dow = (date.getFullYear()-6) + ' - ' + (date.getFullYear()+5);
break;
}
tblCal.find('thead tr:first th:eq(1) span').text(dow);
dow = date.getFullYear()-6;
data = {
data: [],
className: 'datepickerYears'
}
for ( var j = 0; j < 12; j++) {
data.data.push(dow + j);
}
html = tmpl(tpl.months.join(''), data);
date.setDate(1);
data = {weeks:[], test: 10};
month = date.getMonth();
var dow = (date.getDay() - options.starts) % 7;
date.addDays(-(dow + (dow < 0 ? 7 : 0)));
week = -1;
cnt = 0;
while (cnt < 42) {
indic = parseInt(cnt/7,10);
indic2 = cnt%7;
if (!data.weeks[indic]) {
week = date.getWeekNumber();
data.weeks[indic] = {
week: week,
days: []
};
}
data.weeks[indic].days[indic2] = {
text: date.getDate(),
classname: []
};
if (month != date.getMonth()) {
data.weeks[indic].days[indic2].classname.push('datepickerNotInMonth');
}
if (date.getDay() == 0) {
data.weeks[indic].days[indic2].classname.push('datepickerSunday');
}
if (date.getDay() == 6) {
data.weeks[indic].days[indic2].classname.push('datepickerSaturday');
}
var fromUser = options.onRender(date);
var val = date.valueOf();
if (fromUser.selected || options.date == val || $.inArray(val, options.date) > -1 || (options.mode == 'range' && val >= options.date[0] && val <= options.date[1])) {
data.weeks[indic].days[indic2].classname.push('datepickerSelected');
}
if (fromUser.disabled) {
data.weeks[indic].days[indic2].classname.push('datepickerDisabled');
}
if (fromUser.className) {
data.weeks[indic].days[indic2].classname.push(fromUser.className);
}
data.weeks[indic].days[indic2].classname = data.weeks[indic].days[indic2].classname.join(' ');
cnt++;
date.addDays(1);
}
html = tmpl(tpl.days.join(''), data) + html;
data = {
data: options.locale.monthsShort,
className: 'datepickerMonths'
};
html = tmpl(tpl.months.join(''), data) + html;
tblCal.append(html);
}
},
parseDate = function (date, format) {
if (date.constructor == Date) {
return new Date(date);
}
var parts = date.split(/\W+/);
var against = format.split(/\W+/), d, m, y, h, min, now = new Date();
for (var i = 0; i < parts.length; i++) {
switch (against[i]) {
case 'd':
case 'e':
d = parseInt(parts[i],10);
break;
case 'm':
m = parseInt(parts[i], 10)-1;
break;
case 'Y':
case 'y':
y = parseInt(parts[i], 10);
y += y > 100 ? 0 : (y < 29 ? 2000 : 1900);
break;
case 'H':
case 'I':
case 'k':
case 'l':
h = parseInt(parts[i], 10);
break;
case 'P':
case 'p':
if (/pm/i.test(parts[i]) && h < 12) {
h += 12;
} else if (/am/i.test(parts[i]) && h >= 12) {
h -= 12;
}
break;
case 'M':
min = parseInt(parts[i], 10);
break;
}
}
return new Date(
y === undefined ? now.getFullYear() : y,
m === undefined ? now.getMonth() : m,
d === undefined ? now.getDate() : d,
h === undefined ? now.getHours() : h,
min === undefined ? now.getMinutes() : min,
0
);
},
formatDate = function(date, format) {
var m = date.getMonth();
var d = date.getDate();
var y = date.getFullYear();
var wn = date.getWeekNumber();
var w = date.getDay();
var s = {};
var hr = date.getHours();
var pm = (hr >= 12);
var ir = (pm) ? (hr - 12) : hr;
var dy = date.getDayOfYear();
if (ir == 0) {
ir = 12;
}
var min = date.getMinutes();
var sec = date.getSeconds();
var parts = format.split(''), part;
for ( var i = 0; i < parts.length; i++ ) {
part = parts[i];
switch (parts[i]) {
case 'a':
part = date.getDayName();
break;
case 'A':
part = date.getDayName(true);
break;
case 'b':
part = date.getMonthName();
break;
case 'B':
part = date.getMonthName(true);
break;
case 'C':
part = 1 + Math.floor(y / 100);
break;
case 'd':
part = (d < 10) ? ("0" + d) : d;
break;
case 'e':
part = d;
break;
case 'H':
part = (hr < 10) ? ("0" + hr) : hr;
break;
case 'I':
part = (ir < 10) ? ("0" + ir) : ir;
break;
case 'j':
part = (dy < 100) ? ((dy < 10) ? ("00" + dy) : ("0" + dy)) : dy;
break;
case 'k':
part = hr;
break;
case 'l':
part = ir;
break;
case 'm':
part = (m < 9) ? ("0" + (1+m)) : (1+m);
break;
case 'M':
part = (min < 10) ? ("0" + min) : min;
break;
case 'p':
case 'P':
part = pm ? "PM" : "AM";
break;
case 's':
part = Math.floor(date.getTime() / 1000);
break;
case 'S':
part = (sec < 10) ? ("0" + sec) : sec;
break;
case 'u':
part = w + 1;
break;
case 'w':
part = w;
break;
case 'y':
part = ('' + y).substr(2, 2);
break;
case 'Y':
part = y;
break;
}
parts[i] = part;
}
return parts.join('');
},
extendDate = function(options) {
if (Date.prototype.tempDate) {
return;
}
Date.prototype.tempDate = null;
Date.prototype.months = options.months;
Date.prototype.monthsShort = options.monthsShort;
Date.prototype.days = options.days;
Date.prototype.daysShort = options.daysShort;
Date.prototype.getMonthName = function(fullName) {
return this[fullName ? 'months' : 'monthsShort'][this.getMonth()];
};
Date.prototype.getDayName = function(fullName) {
return this[fullName ? 'days' : 'daysShort'][this.getDay()];
};
Date.prototype.addDays = function (n) {
this.setDate(this.getDate() + n);
this.tempDate = this.getDate();
};
Date.prototype.addMonths = function (n) {
if (this.tempDate == null) {
this.tempDate = this.getDate();
}
this.setDate(1);
this.setMonth(this.getMonth() + n);
this.setDate(Math.min(this.tempDate, this.getMaxDays()));
};
Date.prototype.addYears = function (n) {
if (this.tempDate == null) {
this.tempDate = this.getDate();
}
this.setDate(1);
this.setFullYear(this.getFullYear() + n);
this.setDate(Math.min(this.tempDate, this.getMaxDays()));
};
Date.prototype.getMaxDays = function() {
var tmpDate = new Date(Date.parse(this)),
d = 28, m;
m = tmpDate.getMonth();
d = 28;
while (tmpDate.getMonth() == m) {
d ++;
tmpDate.setDate(d);
}
return d - 1;
};
Date.prototype.getFirstDay = function() {
var tmpDate = new Date(Date.parse(this));
tmpDate.setDate(1);
return tmpDate.getDay();
};
Date.prototype.getWeekNumber = function() {
var tempDate = new Date(this);
tempDate.setDate(tempDate.getDate() - (tempDate.getDay() + 6) % 7 + 3);
var dms = tempDate.valueOf();
tempDate.setMonth(0);
tempDate.setDate(4);
return Math.round((dms - tempDate.valueOf()) / (604800000)) + 1;
};
Date.prototype.getDayOfYear = function() {
var now = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0);
var then = new Date(this.getFullYear(), 0, 0, 0, 0, 0);
var time = now - then;
return Math.floor(time / 24*60*60*1000);
};
},
layout = function (el) {
var options = $(el).data('datepicker');
var cal = $('#' + options.id);
if (!options.extraHeight) {
var divs = $(el).find('div');
options.extraHeight = divs.get(0).offsetHeight + divs.get(1).offsetHeight;
options.extraWidth = divs.get(2).offsetWidth + divs.get(3).offsetWidth;
}
var tbl = cal.find('table:first').get(0);
var width = tbl.offsetWidth;
var height = tbl.offsetHeight;
cal.css({
width: width + options.extraWidth + 'px',
height: height + options.extraHeight + 'px'
}).find('div.datepickerContainer').css({
width: width + 'px',
height: height + 'px'
});
},
click = function(ev) {
if ($(ev.target).is('span')) {
ev.target = ev.target.parentNode;
}
var el = $(ev.target);
if (el.is('a')) {
ev.target.blur();
if (el.hasClass('datepickerDisabled')) {
return false;
}
var options = $(this).data('datepicker');
var parentEl = el.parent();
var tblEl = parentEl.parent().parent().parent();
var tblIndex = $('table', this).index(tblEl.get(0)) - 1;
var tmp = new Date(options.current);
var changed = false;
var fillIt = false;
if (parentEl.is('th')) {
if (parentEl.hasClass('datepickerWeek') && options.mode == 'range' && !parentEl.next().hasClass('datepickerDisabled')) {
var val = parseInt(parentEl.next().text(), 10);
tmp.addMonths(tblIndex - Math.floor(options.calendars/2));
if (parentEl.next().hasClass('datepickerNotInMonth')) {
tmp.addMonths(val > 15 ? -1 : 1);
}
tmp.setDate(val);
options.date[0] = (tmp.setHours(0,0,0,0)).valueOf();
tmp.setHours(23,59,59,0);
tmp.addDays(6);
options.date[1] = tmp.valueOf();
fillIt = true;
changed = true;
options.lastSel = false;
} else if (parentEl.hasClass('datepickerMonth')) {
tmp.addMonths(tblIndex - Math.floor(options.calendars/2));
switch (tblEl.get(0).className) {
case 'datepickerViewDays':
tblEl.get(0).className = 'datepickerViewMonths';
el.find('span').text(tmp.getFullYear());
break;
case 'datepickerViewMonths':
tblEl.get(0).className = 'datepickerViewYears';
el.find('span').text((tmp.getFullYear()-6) + ' - ' + (tmp.getFullYear()+5));
break;
case 'datepickerViewYears':
tblEl.get(0).className = 'datepickerViewDays';
el.find('span').text(formatDate(tmp, 'B, Y'));
break;
}
} else if (parentEl.parent().parent().is('thead')) {
switch (tblEl.get(0).className) {
case 'datepickerViewDays':
options.current.addMonths(parentEl.hasClass('datepickerGoPrev') ? -1 : 1);
break;
case 'datepickerViewMonths':
options.current.addYears(parentEl.hasClass('datepickerGoPrev') ? -1 : 1);
break;
case 'datepickerViewYears':
options.current.addYears(parentEl.hasClass('datepickerGoPrev') ? -12 : 12);
break;
}
fillIt = true;
}
} else if (parentEl.is('td') && !parentEl.hasClass('datepickerDisabled')) {
switch (tblEl.get(0).className) {
case 'datepickerViewMonths':
options.current.setMonth(tblEl.find('tbody.datepickerMonths td').index(parentEl));
options.current.setFullYear(parseInt(tblEl.find('thead th.datepickerMonth span').text(), 10));
options.current.addMonths(Math.floor(options.calendars/2) - tblIndex);
tblEl.get(0).className = 'datepickerViewDays';
break;
case 'datepickerViewYears':
options.current.setFullYear(parseInt(el.text(), 10));
tblEl.get(0).className = 'datepickerViewMonths';
break;
default:
var val = parseInt(el.text(), 10);
tmp.addMonths(tblIndex - Math.floor(options.calendars/2));
if (parentEl.hasClass('datepickerNotInMonth')) {
tmp.addMonths(val > 15 ? -1 : 1);
}
tmp.setDate(val);
switch (options.mode) {
case 'multiple':
val = (tmp.setHours(0,0,0,0)).valueOf();
if ($.inArray(val, options.date) > -1) {
$.each(options.date, function(nr, dat){
if (dat == val) {
options.date.splice(nr,1);
return false;
}
});
} else {
options.date.push(val);
}
break;
case 'range':
if (!options.lastSel) {
options.date[0] = (tmp.setHours(0,0,0,0)).valueOf();
}
val = (tmp.setHours(23,59,59,0)).valueOf();
if (val < options.date[0]) {
options.date[1] = options.date[0] + 86399000;
options.date[0] = val - 86399000;
} else {
options.date[1] = val;
}
options.lastSel = !options.lastSel;
break;
default:
options.date = tmp.valueOf();
break;
}
break;
}
fillIt = true;
changed = true;
}
if (fillIt) {
fill(this);
}
if (changed) {
options.onChange.apply(this, prepareDate(options));
}
}
return false;
},
prepareDate = function (options) {
var tmp;
if (options.mode == 'single') {
tmp = new Date(options.date);
return [formatDate(tmp, options.format), tmp, options.el];
} else {
tmp = [[],[], options.el];
$.each(options.date, function(nr, val){
var date = new Date(val);
tmp[0].push(formatDate(date, options.format));
tmp[1].push(date);
});
return tmp;
}
},
getViewport = function () {
var m = document.compatMode == 'CSS1Compat';
return {
l : window.pageXOffset || (m ? document.documentElement.scrollLeft : document.body.scrollLeft),
t : window.pageYOffset || (m ? document.documentElement.scrollTop : document.body.scrollTop),
w : window.innerWidth || (m ? document.documentElement.clientWidth : document.body.clientWidth),
h : window.innerHeight || (m ? document.documentElement.clientHeight : document.body.clientHeight)
};
},
isChildOf = function(parentEl, el, container) {
if (parentEl == el) {
return true;
}
if (parentEl.contains) {
return parentEl.contains(el);
}
if ( parentEl.compareDocumentPosition ) {
return !!(parentEl.compareDocumentPosition(el) & 16);
}
var prEl = el.parentNode;
while(prEl && prEl != container) {
if (prEl == parentEl)
return true;
prEl = prEl.parentNode;
}
return false;
},
show = function (ev) {
var cal = $('#' + $(this).data('datepickerId'));
if (!cal.is(':visible')) {
var calEl = cal.get(0);
fill(calEl);
var options = cal.data('datepicker');
options.onBeforeShow.apply(this, [cal.get(0)]);
var pos = $(this).offset();
var viewPort = getViewport();
var top = pos.top;
var left = pos.left;
var oldDisplay = $.curCSS(calEl, 'display');
cal.css({
visibility: 'hidden',
display: 'block'
});
layout(calEl);
switch (options.position){
case 'top':
top -= calEl.offsetHeight;
break;
case 'left':
left -= calEl.offsetWidth;
break;
case 'right':
left += this.offsetWidth;
break;
case 'bottom':
top += this.offsetHeight;
break;
}
if (top + calEl.offsetHeight > viewPort.t + viewPort.h) {
top = pos.top - calEl.offsetHeight;
}
if (top < viewPort.t) {
top = pos.top + this.offsetHeight + calEl.offsetHeight;
}
if (left + calEl.offsetWidth > viewPort.l + viewPort.w) {
left = pos.left - calEl.offsetWidth;
}
if (left < viewPort.l) {
left = pos.left + this.offsetWidth
}
cal.css({
visibility: 'visible',
display: 'block',
top: top + 'px',
left: left + 'px'
});
if (options.onShow.apply(this, [cal.get(0)]) != false) {
cal.show();
}
$(document).bind('mousedown', {cal: cal, trigger: this}, hide);
}
return false;
},
hide = function (ev) {
if (ev.target != ev.data.trigger && !isChildOf(ev.data.cal.get(0), ev.target, ev.data.cal.get(0))) {
if (ev.data.cal.data('datepicker').onHide.apply(this, [ev.data.cal.get(0)]) != false) {
ev.data.cal.hide();
}
$(document).unbind('mousedown', hide);
}
};
return {
init: function(options){
options = $.extend({}, defaults, options||{});
extendDate(options.locale);
options.calendars = Math.max(1, parseInt(options.calendars,10)||1);
options.mode = /single|multiple|range/.test(options.mode) ? options.mode : 'single';
return this.each(function(){
if (!$(this).data('datepicker')) {
options.el = this;
if (options.date.constructor == String) {
options.date = parseDate(options.date, options.format);
options.date.setHours(0,0,0,0);
}
if (options.mode != 'single') {
if (options.date.constructor != Array) {
options.date = [options.date.valueOf()];
if (options.mode == 'range') {
options.date.push(((new Date(options.date[0])).setHours(23,59,59,0)).valueOf());
}
} else {
for (var i = 0; i < options.date.length; i++) {
options.date[i] = (parseDate(options.date[i], options.format).setHours(0,0,0,0)).valueOf();
}
if (options.mode == 'range') {
options.date[1] = ((new Date(options.date[1])).setHours(23,59,59,0)).valueOf();
}
}
} else {
options.date = options.date.valueOf();
}
if (!options.current) {
options.current = new Date();
} else {
options.current = parseDate(options.current, options.format);
}
options.current.setDate(1);
options.current.setHours(0,0,0,0);
var id = 'datepicker_' + parseInt(Math.random() * 1000), cnt;
options.id = id;
$(this).data('datepickerId', options.id);
var cal = $(tpl.wrapper).attr('id', id).bind('click', click).data('datepicker', options);
if (options.className) {
cal.addClass(options.className);
}
var html = '';
for (var i = 0; i < options.calendars; i++) {
cnt = options.starts;
if (i > 0) {
html += tpl.space;
}
html += tmpl(tpl.head.join(''), {
week: options.locale.weekMin,
prev: options.prev,
next: options.next,
day1: options.locale.daysMin[(cnt++)%7],
day2: options.locale.daysMin[(cnt++)%7],
day3: options.locale.daysMin[(cnt++)%7],
day4: options.locale.daysMin[(cnt++)%7],
day5: options.locale.daysMin[(cnt++)%7],
day6: options.locale.daysMin[(cnt++)%7],
day7: options.locale.daysMin[(cnt++)%7]
});
}
cal
.find('tr:first').append(html)
.find('table').addClass(views[options.view]);
fill(cal.get(0));
if (options.flat) {
cal.appendTo(this).show().css('position', 'relative');
layout(cal.get(0));
} else {
cal.appendTo(document.body);
$(this).bind(options.eventName, show);
}
}
});
},
showPicker: function() {
return this.each( function () {
if ($(this).data('datepickerId')) {
show.apply(this);
}
});
},
hidePicker: function() {
return this.each( function () {
if ($(this).data('datepickerId')) {
$('#' + $(this).data('datepickerId')).hide();
}
});
},
setDate: function(date, shiftTo){
return this.each(function(){
if ($(this).data('datepickerId')) {
var cal = $('#' + $(this).data('datepickerId'));
var options = cal.data('datepicker');
options.date = date;
if (options.date.constructor == String) {
options.date = parseDate(options.date, options.format);
options.date.setHours(0,0,0,0);
}
if (options.mode != 'single') {
if (options.date.constructor != Array) {
options.date = [options.date.valueOf()];
if (options.mode == 'range') {
options.date.push(((new Date(options.date[0])).setHours(23,59,59,0)).valueOf());
}
} else {
for (var i = 0; i < options.date.length; i++) {
options.date[i] = (parseDate(options.date[i], options.format).setHours(0,0,0,0)).valueOf();
}
if (options.mode == 'range') {
options.date[1] = ((new Date(options.date[1])).setHours(23,59,59,0)).valueOf();
}
}
} else {
options.date = options.date.valueOf();
}
if (shiftTo) {
options.current = new Date (options.mode != 'single' ? options.date[0] : options.date);
}
fill(cal.get(0));
}
});
},
getDate: function(formated) {
if (this.size() > 0) {
return prepareDate($('#' + $(this).data('datepickerId')).data('datepicker'))[formated ? 0 : 1];
}
},
clear: function(){
return this.each(function(){
if ($(this).data('datepickerId')) {
var cal = $('#' + $(this).data('datepickerId'));
var options = cal.data('datepicker');
if (options.mode != 'single') {
options.date = [];
fill(cal.get(0));
}
}
});
},
fixLayout: function(){
return this.each(function(){
if ($(this).data('datepickerId')) {
var cal = $('#' + $(this).data('datepickerId'));
var options = cal.data('datepicker');
if (options.flat) {
layout(cal.get(0));
}
}
});
}
};
}();
$.fn.extend({
DatePicker: DatePicker.init,
DatePickerHide: DatePicker.hidePicker,
DatePickerShow: DatePicker.showPicker,
DatePickerSetDate: DatePicker.setDate,
DatePickerGetDate: DatePicker.getDate,
DatePickerClear: DatePicker.clear,
DatePickerLayout: DatePicker.fixLayout
});
})(jQuery);
(function(){
var cache = {};
this.tmpl = function tmpl(str, data){
// Figure out if we're getting a template, or if we need to
// load the template - and be sure to cache the result.
var fn = !/\W/.test(str) ?
cache[str] = cache[str] ||
tmpl(document.getElementById(str).innerHTML) :
// Generate a reusable function that will serve as a template
// generator (and which will be cached).
new Function("obj",
"var p=[],print=function(){p.push.apply(p,arguments);};" +
// Introduce the data as local variables using with(){}
"with(obj){p.push('" +
// Convert the template into pure JavaScript
str
.replace(/[\r\t\n]/g, " ")
.split("<%").join("\t")
.replace(/((^|%>)[^\t]*)'/g, "$1\r")
.replace(/\t=(.*?)%>/g, "',$1,'")
.split("\t").join("');")
.split("%>").join("p.push('")
.split("\r").join("\\'")
+ "');}return p.join('');");
// Provide some basic currying to the user
return data ? fn( data ) : fn;
};
})();

View file

@ -0,0 +1,785 @@
/*!
* jQuery Form Plugin
* version: 2.49 (18-OCT-2010)
* @requires jQuery v1.3.2 or later
*
* Examples and documentation at: http://malsup.com/jquery/form/
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*/
;(function($) {
/*
Usage Note:
-----------
Do not use both ajaxSubmit and ajaxForm on the same form. These
functions are intended to be exclusive. Use ajaxSubmit if you want
to bind your own submit handler to the form. For example,
$(document).ready(function() {
$('#myForm').bind('submit', function(e) {
e.preventDefault(); // <-- important
$(this).ajaxSubmit({
target: '#output'
});
});
});
Use ajaxForm when you want the plugin to manage all the event binding
for you. For example,
$(document).ready(function() {
$('#myForm').ajaxForm({
target: '#output'
});
});
When using ajaxForm, the ajaxSubmit function will be invoked for you
at the appropriate time.
*/
/**
* ajaxSubmit() provides a mechanism for immediately submitting
* an HTML form using AJAX.
*/
$.fn.ajaxSubmit = function(options) {
// fast fail if nothing selected (http://dev.jquery.com/ticket/2752)
if (!this.length) {
log('ajaxSubmit: skipping submit process - no element selected');
return this;
}
if (typeof options == 'function') {
options = { success: options };
}
var url = $.trim(this.attr('action'));
if (url) {
// clean url (don't include hash vaue)
url = (url.match(/^([^#]+)/)||[])[1];
}
url = url || window.location.href || '';
options = $.extend(true, {
url: url,
type: this.attr('method') || 'GET',
iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank'
}, options);
// hook for manipulating the form data before it is extracted;
// convenient for use with rich editors like tinyMCE or FCKEditor
var veto = {};
this.trigger('form-pre-serialize', [this, options, veto]);
if (veto.veto) {
log('ajaxSubmit: submit vetoed via form-pre-serialize trigger');
return this;
}
// provide opportunity to alter form data before it is serialized
if (options.beforeSerialize && options.beforeSerialize(this, options) === false) {
log('ajaxSubmit: submit aborted via beforeSerialize callback');
return this;
}
var n,v,a = this.formToArray(options.semantic);
if (options.data) {
options.extraData = options.data;
for (n in options.data) {
if(options.data[n] instanceof Array) {
for (var k in options.data[n]) {
a.push( { name: n, value: options.data[n][k] } );
}
}
else {
v = options.data[n];
v = $.isFunction(v) ? v() : v; // if value is fn, invoke it
a.push( { name: n, value: v } );
}
}
}
// give pre-submit callback an opportunity to abort the submit
if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) {
log('ajaxSubmit: submit aborted via beforeSubmit callback');
return this;
}
// fire vetoable 'validate' event
this.trigger('form-submit-validate', [a, this, options, veto]);
if (veto.veto) {
log('ajaxSubmit: submit vetoed via form-submit-validate trigger');
return this;
}
var q = $.param(a);
if (options.type.toUpperCase() == 'GET') {
options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
options.data = null; // data is null for 'get'
}
else {
options.data = q; // data is the query string for 'post'
}
var $form = this, callbacks = [];
if (options.resetForm) {
callbacks.push(function() { $form.resetForm(); });
}
if (options.clearForm) {
callbacks.push(function() { $form.clearForm(); });
}
// perform a load on the target only if dataType is not provided
if (!options.dataType && options.target) {
var oldSuccess = options.success || function(){};
callbacks.push(function(data) {
var fn = options.replaceTarget ? 'replaceWith' : 'html';
$(options.target)[fn](data).each(oldSuccess, arguments);
});
}
else if (options.success) {
callbacks.push(options.success);
}
options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg
var context = options.context || options; // jQuery 1.4+ supports scope context
for (var i=0, max=callbacks.length; i < max; i++) {
callbacks[i].apply(context, [data, status, xhr || $form, $form]);
}
};
// are there files to upload?
var fileInputs = $('input:file', this).length > 0;
var mp = 'multipart/form-data';
var multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp);
// options.iframe allows user to force iframe mode
// 06-NOV-09: now defaulting to iframe mode if file input is detected
if (options.iframe !== false && (fileInputs || options.iframe || multipart)) {
// hack to fix Safari hang (thanks to Tim Molendijk for this)
// see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
if (options.closeKeepAlive) {
$.get(options.closeKeepAlive, fileUpload);
}
else {
fileUpload();
}
}
else {
$.ajax(options);
}
// fire 'notify' event
this.trigger('form-submit-notify', [this, options]);
return this;
// private function for handling file uploads (hat tip to YAHOO!)
function fileUpload() {
var form = $form[0];
if ($(':input[name=submit],:input[id=submit]', form).length) {
// if there is an input with a name or id of 'submit' then we won't be
// able to invoke the submit fn on the form (at least not x-browser)
alert('Error: Form elements must not have name or id of "submit".');
return;
}
var s = $.extend(true, {}, $.ajaxSettings, options);
s.context = s.context || s;
var id = 'jqFormIO' + (new Date().getTime()), fn = '_'+id;
window[fn] = function() {
var f = $io.data('form-plugin-onload');
if (f) {
f();
window[fn] = undefined;
try { delete window[fn]; } catch(e){}
}
}
var $io = $('<iframe id="' + id + '" name="' + id + '" src="'+ s.iframeSrc +'" onload="window[\'_\'+this.id]()" />');
var io = $io[0];
$io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
var xhr = { // mock object
aborted: 0,
responseText: null,
responseXML: null,
status: 0,
statusText: 'n/a',
getAllResponseHeaders: function() {},
getResponseHeader: function() {},
setRequestHeader: function() {},
abort: function() {
this.aborted = 1;
$io.attr('src', s.iframeSrc); // abort op in progress
}
};
var g = s.global;
// trigger ajax global events so that activity/block indicators work like normal
if (g && ! $.active++) {
$.event.trigger("ajaxStart");
}
if (g) {
$.event.trigger("ajaxSend", [xhr, s]);
}
if (s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false) {
if (s.global) {
$.active--;
}
return;
}
if (xhr.aborted) {
return;
}
var cbInvoked = false;
var timedOut = 0;
// add submitting element to data if we know it
var sub = form.clk;
if (sub) {
var n = sub.name;
if (n && !sub.disabled) {
s.extraData = s.extraData || {};
s.extraData[n] = sub.value;
if (sub.type == "image") {
s.extraData[n+'.x'] = form.clk_x;
s.extraData[n+'.y'] = form.clk_y;
}
}
}
// take a breath so that pending repaints get some cpu time before the upload starts
function doSubmit() {
// make sure form attrs are set
var t = $form.attr('target'), a = $form.attr('action');
// update form attrs in IE friendly way
form.setAttribute('target',id);
if (form.getAttribute('method') != 'POST') {
form.setAttribute('method', 'POST');
}
if (form.getAttribute('action') != s.url) {
form.setAttribute('action', s.url);
}
// ie borks in some cases when setting encoding
if (! s.skipEncodingOverride) {
$form.attr({
encoding: 'multipart/form-data',
enctype: 'multipart/form-data'
});
}
// support timout
if (s.timeout) {
setTimeout(function() { timedOut = true; cb(); }, s.timeout);
}
// add "extra" data to form if provided in options
var extraInputs = [];
try {
if (s.extraData) {
for (var n in s.extraData) {
extraInputs.push(
$('<input type="hidden" name="'+n+'" value="'+s.extraData[n]+'" />')
.appendTo(form)[0]);
}
}
// add iframe to doc and submit the form
$io.appendTo('body');
$io.data('form-plugin-onload', cb);
form.submit();
}
finally {
// reset attrs and remove "extra" input elements
form.setAttribute('action',a);
if(t) {
form.setAttribute('target', t);
} else {
$form.removeAttr('target');
}
$(extraInputs).remove();
}
}
if (s.forceSync) {
doSubmit();
}
else {
setTimeout(doSubmit, 10); // this lets dom updates render
}
var data, doc, domCheckCount = 50;
function cb() {
if (cbInvoked) {
return;
}
$io.removeData('form-plugin-onload');
var ok = true;
try {
if (timedOut) {
throw 'timeout';
}
// extract the server response from the iframe
doc = io.contentWindow ? io.contentWindow.document : io.contentDocument ? io.contentDocument : io.document;
var isXml = s.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc);
log('isXml='+isXml);
if (!isXml && window.opera && (doc.body == null || doc.body.innerHTML == '')) {
if (--domCheckCount) {
// in some browsers (Opera) the iframe DOM is not always traversable when
// the onload callback fires, so we loop a bit to accommodate
log('requeing onLoad callback, DOM not available');
setTimeout(cb, 250);
return;
}
// let this fall through because server response could be an empty document
//log('Could not access iframe DOM after mutiple tries.');
//throw 'DOMException: not available';
}
//log('response detected');
cbInvoked = true;
xhr.responseText = doc.documentElement ? doc.documentElement.innerHTML : null;
xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
xhr.getResponseHeader = function(header){
var headers = {'content-type': s.dataType};
return headers[header];
};
var scr = /(json|script)/.test(s.dataType);
if (scr || s.textarea) {
// see if user embedded response in textarea
var ta = doc.getElementsByTagName('textarea')[0];
if (ta) {
xhr.responseText = ta.value;
}
else if (scr) {
// account for browsers injecting pre around json response
var pre = doc.getElementsByTagName('pre')[0];
var b = doc.getElementsByTagName('body')[0];
if (pre) {
xhr.responseText = pre.innerHTML;
}
else if (b) {
xhr.responseText = b.innerHTML;
}
}
}
else if (s.dataType == 'xml' && !xhr.responseXML && xhr.responseText != null) {
xhr.responseXML = toXml(xhr.responseText);
}
data = $.httpData(xhr, s.dataType);
}
catch(e){
log('error caught:',e);
ok = false;
xhr.error = e;
$.handleError(s, xhr, 'error', e);
}
// ordering of these callbacks/triggers is odd, but that's how $.ajax does it
if (ok) {
s.success.call(s.context, data, 'success', xhr);
if (g) {
$.event.trigger("ajaxSuccess", [xhr, s]);
}
}
if (g) {
$.event.trigger("ajaxComplete", [xhr, s]);
}
if (g && ! --$.active) {
$.event.trigger("ajaxStop");
}
if (s.complete) {
s.complete.call(s.context, xhr, ok ? 'success' : 'error');
}
// clean up
setTimeout(function() {
$io.removeData('form-plugin-onload');
$io.remove();
xhr.responseXML = null;
}, 100);
}
function toXml(s, doc) {
if (window.ActiveXObject) {
doc = new ActiveXObject('Microsoft.XMLDOM');
doc.async = 'false';
doc.loadXML(s);
}
else {
doc = (new DOMParser()).parseFromString(s, 'text/xml');
}
return (doc && doc.documentElement && doc.documentElement.tagName != 'parsererror') ? doc : null;
}
}
};
/**
* ajaxForm() provides a mechanism for fully automating form submission.
*
* The advantages of using this method instead of ajaxSubmit() are:
*
* 1: This method will include coordinates for <input type="image" /> elements (if the element
* is used to submit the form).
* 2. This method will include the submit element's name/value data (for the element that was
* used to submit the form).
* 3. This method binds the submit() method to the form for you.
*
* The options argument for ajaxForm works exactly as it does for ajaxSubmit. ajaxForm merely
* passes the options argument along after properly binding events for submit elements and
* the form itself.
*/
$.fn.ajaxForm = function(options) {
// in jQuery 1.3+ we can fix mistakes with the ready state
if (this.length === 0) {
var o = { s: this.selector, c: this.context };
if (!$.isReady && o.s) {
log('DOM not ready, queuing ajaxForm');
$(function() {
$(o.s,o.c).ajaxForm(options);
});
return this;
}
// is your DOM ready? http://docs.jquery.com/Tutorials:Introducing_$(document).ready()
log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)'));
return this;
}
return this.ajaxFormUnbind().bind('submit.form-plugin', function(e) {
if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed
e.preventDefault();
$(this).ajaxSubmit(options);
}
}).bind('click.form-plugin', function(e) {
var target = e.target;
var $el = $(target);
if (!($el.is(":submit,input:image"))) {
// is this a child element of the submit el? (ex: a span within a button)
var t = $el.closest(':submit');
if (t.length == 0) {
return;
}
target = t[0];
}
var form = this;
form.clk = target;
if (target.type == 'image') {
if (e.offsetX != undefined) {
form.clk_x = e.offsetX;
form.clk_y = e.offsetY;
} else if (typeof $.fn.offset == 'function') { // try to use dimensions plugin
var offset = $el.offset();
form.clk_x = e.pageX - offset.left;
form.clk_y = e.pageY - offset.top;
} else {
form.clk_x = e.pageX - target.offsetLeft;
form.clk_y = e.pageY - target.offsetTop;
}
}
// clear form vars
setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100);
});
};
// ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
$.fn.ajaxFormUnbind = function() {
return this.unbind('submit.form-plugin click.form-plugin');
};
/**
* formToArray() gathers form element data into an array of objects that can
* be passed to any of the following ajax functions: $.get, $.post, or load.
* Each object in the array has both a 'name' and 'value' property. An example of
* an array for a simple login form might be:
*
* [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
*
* It is this array that is passed to pre-submit callback functions provided to the
* ajaxSubmit() and ajaxForm() methods.
*/
$.fn.formToArray = function(semantic) {
var a = [];
if (this.length === 0) {
return a;
}
var form = this[0];
var els = semantic ? form.getElementsByTagName('*') : form.elements;
if (!els) {
return a;
}
var i,j,n,v,el,max,jmax;
for(i=0, max=els.length; i < max; i++) {
el = els[i];
n = el.name;
if (!n) {
continue;
}
if (semantic && form.clk && el.type == "image") {
// handle image inputs on the fly when semantic == true
if(!el.disabled && form.clk == el) {
a.push({name: n, value: $(el).val()});
a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
}
continue;
}
v = $.fieldValue(el, true);
if (v && v.constructor == Array) {
for(j=0, jmax=v.length; j < jmax; j++) {
a.push({name: n, value: v[j]});
}
}
else if (v !== null && typeof v != 'undefined') {
a.push({name: n, value: v});
}
}
if (!semantic && form.clk) {
// input type=='image' are not found in elements array! handle it here
var $input = $(form.clk), input = $input[0];
n = input.name;
if (n && !input.disabled && input.type == 'image') {
a.push({name: n, value: $input.val()});
a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
}
}
return a;
};
/**
* Serializes form data into a 'submittable' string. This method will return a string
* in the format: name1=value1&amp;name2=value2
*/
$.fn.formSerialize = function(semantic) {
//hand off to jQuery.param for proper encoding
return $.param(this.formToArray(semantic));
};
/**
* Serializes all field elements in the jQuery object into a query string.
* This method will return a string in the format: name1=value1&amp;name2=value2
*/
$.fn.fieldSerialize = function(successful) {
var a = [];
this.each(function() {
var n = this.name;
if (!n) {
return;
}
var v = $.fieldValue(this, successful);
if (v && v.constructor == Array) {
for (var i=0,max=v.length; i < max; i++) {
a.push({name: n, value: v[i]});
}
}
else if (v !== null && typeof v != 'undefined') {
a.push({name: this.name, value: v});
}
});
//hand off to jQuery.param for proper encoding
return $.param(a);
};
/**
* Returns the value(s) of the element in the matched set. For example, consider the following form:
*
* <form><fieldset>
* <input name="A" type="text" />
* <input name="A" type="text" />
* <input name="B" type="checkbox" value="B1" />
* <input name="B" type="checkbox" value="B2"/>
* <input name="C" type="radio" value="C1" />
* <input name="C" type="radio" value="C2" />
* </fieldset></form>
*
* var v = $(':text').fieldValue();
* // if no values are entered into the text inputs
* v == ['','']
* // if values entered into the text inputs are 'foo' and 'bar'
* v == ['foo','bar']
*
* var v = $(':checkbox').fieldValue();
* // if neither checkbox is checked
* v === undefined
* // if both checkboxes are checked
* v == ['B1', 'B2']
*
* var v = $(':radio').fieldValue();
* // if neither radio is checked
* v === undefined
* // if first radio is checked
* v == ['C1']
*
* The successful argument controls whether or not the field element must be 'successful'
* (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
* The default value of the successful argument is true. If this value is false the value(s)
* for each element is returned.
*
* Note: This method *always* returns an array. If no valid value can be determined the
* array will be empty, otherwise it will contain one or more values.
*/
$.fn.fieldValue = function(successful) {
for (var val=[], i=0, max=this.length; i < max; i++) {
var el = this[i];
var v = $.fieldValue(el, successful);
if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length)) {
continue;
}
v.constructor == Array ? $.merge(val, v) : val.push(v);
}
return val;
};
/**
* Returns the value of the field element.
*/
$.fieldValue = function(el, successful) {
var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
if (successful === undefined) {
successful = true;
}
if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
(t == 'checkbox' || t == 'radio') && !el.checked ||
(t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
tag == 'select' && el.selectedIndex == -1)) {
return null;
}
if (tag == 'select') {
var index = el.selectedIndex;
if (index < 0) {
return null;
}
var a = [], ops = el.options;
var one = (t == 'select-one');
var max = (one ? index+1 : ops.length);
for(var i=(one ? index : 0); i < max; i++) {
var op = ops[i];
if (op.selected) {
var v = op.value;
if (!v) { // extra pain for IE...
v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value;
}
if (one) {
return v;
}
a.push(v);
}
}
return a;
}
return $(el).val();
};
/**
* Clears the form data. Takes the following actions on the form's input fields:
* - input text fields will have their 'value' property set to the empty string
* - select elements will have their 'selectedIndex' property set to -1
* - checkbox and radio inputs will have their 'checked' property set to false
* - inputs of type submit, button, reset, and hidden will *not* be effected
* - button elements will *not* be effected
*/
$.fn.clearForm = function() {
return this.each(function() {
$('input,select,textarea', this).clearFields();
});
};
/**
* Clears the selected form elements.
*/
$.fn.clearFields = $.fn.clearInputs = function() {
return this.each(function() {
var t = this.type, tag = this.tagName.toLowerCase();
if (t == 'text' || t == 'password' || tag == 'textarea') {
this.value = '';
}
else if (t == 'checkbox' || t == 'radio') {
this.checked = false;
}
else if (tag == 'select') {
this.selectedIndex = -1;
}
});
};
/**
* Resets the form data. Causes all form elements to be reset to their original value.
*/
$.fn.resetForm = function() {
return this.each(function() {
// guard against an input with the name of 'reset'
// note that IE reports the reset function as an 'object'
if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType)) {
this.reset();
}
});
};
/**
* Enables or disables any matching elements.
*/
$.fn.enable = function(b) {
if (b === undefined) {
b = true;
}
return this.each(function() {
this.disabled = !b;
});
};
/**
* Checks/unchecks any matching checkboxes or radio buttons and
* selects/deselects and matching option elements.
*/
$.fn.selected = function(select) {
if (select === undefined) {
select = true;
}
return this.each(function() {
var t = this.type;
if (t == 'checkbox' || t == 'radio') {
this.checked = select;
}
else if (this.tagName.toLowerCase() == 'option') {
var $sel = $(this).parent('select');
if (select && $sel[0] && $sel[0].type == 'select-one') {
// deselect all other options
$sel.find('option').selected(false);
}
this.selected = select;
}
});
};
// helper fn for console logging
// set $.fn.ajaxSubmit.debug to true to enable debug logging
function log() {
if ($.fn.ajaxSubmit.debug) {
var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,'');
if (window.console && window.console.log) {
window.console.log(msg);
}
else if (window.opera && window.opera.postError) {
window.opera.postError(msg);
}
}
};
})(jQuery);

7179
jappixmini/jappix/js/jquery.js vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,116 @@
(function($) {
$.extend({
placeholder : {
settings : {
focusClass: 'placeholderFocus',
activeClass: 'placeholder',
overrideSupport: false,
preventRefreshIssues: true
},
debug : false,
log : function(msg){
if(!$.placeholder.debug) return;
msg = "[Placeholder] " + msg;
$.placeholder.hasFirebug ?
console.log(msg) :
$.placeholder.hasConsoleLog ?
window.console.log(msg) :
alert(msg);
},
hasFirebug : "console" in window && "firebug" in window.console,
hasConsoleLog: "console" in window && "log" in window.console
}
});
// check browser support for placeholder
$.support.placeholder = 'placeholder' in document.createElement('input');
// Replace the val function to never return placeholders
$.fn.plVal = $.fn.val;
$.fn.val = function(value) {
$.placeholder.log('in val');
if(this[0]) {
$.placeholder.log('have found an element');
var el = $(this[0]);
if(value != undefined)
{
$.placeholder.log('in setter');
var currentValue = el.plVal();
var returnValue = $(this).plVal(value);
if(el.hasClass($.placeholder.settings.activeClass) && currentValue == el.attr('placeholder')){
el.removeClass($.placeholder.settings.activeClass);
}
return returnValue;
}
if(el.hasClass($.placeholder.settings.activeClass) && el.plVal() == el.attr('placeholder')) {
$.placeholder.log('returning empty because its a placeholder');
return '';
} else {
$.placeholder.log('returning original val');
return el.plVal();
}
}
$.placeholder.log('returning undefined');
return undefined;
};
// Clear placeholder values upon page reload
$(window).bind('beforeunload.placeholder', function() {
var els = $('input.placeholderActive' );
if(els.length > 0)
els.val('').attr('autocomplete','off');
});
// plugin code
$.fn.placeholder = function(opts) {
opts = $.extend({},$.placeholder.settings, opts);
// we don't have to do anything if the browser supports placeholder
if(!opts.overrideSupport && $.support.placeholder)
return this;
return this.each(function() {
var $el = $(this);
// skip if we do not have the placeholder attribute
if(!$el.is('[placeholder]'))
return;
// we cannot do password fields, but supported browsers can
if($el.is(':password'))
return;
// Prevent values from being reapplied on refresh
if(opts.preventRefreshIssues)
$el.attr('autocomplete','off');
$el.bind('focus.placeholder', function(){
var $el = $(this);
if(this.value == $el.attr('placeholder') && $el.hasClass(opts.activeClass))
$el.val('')
.removeClass(opts.activeClass)
.addClass(opts.focusClass);
});
$el.bind('blur.placeholder', function(){
var $el = $(this);
$el.removeClass(opts.focusClass);
if(this.value == '')
$el.val($el.attr('placeholder'))
.addClass(opts.activeClass);
});
$el.triggerHandler('blur');
// Prevent incorrect form values being posted
$el.parents('form').submit(function(){
$el.triggerHandler('focus.placeholder');
});
});
};
})(jQuery);

View file

@ -0,0 +1,14 @@
$.fn.selectRange = function(start, end) {
return this.each(function() {
if (this.setSelectionRange) {
this.focus();
this.setSelectionRange(start, end);
} else if (this.createTextRange) {
var range = this.createTextRange();
range.collapse(true);
range.moveEnd('character', end);
range.moveStart('character', start);
range.select();
}
});
};

View file

@ -0,0 +1,138 @@
/**
* jQuery.timers - Timer abstractions for jQuery
* Written by Blair Mitchelmore (blair DOT mitchelmore AT gmail DOT com)
* Licensed under the WTFPL (http://sam.zoy.org/wtfpl/).
* Date: 2009/10/16
*
* @author Blair Mitchelmore
* @version 1.2
*
**/
jQuery.fn.extend({
everyTime: function(interval, label, fn, times) {
return this.each(function() {
jQuery.timer.add(this, interval, label, fn, times);
});
},
oneTime: function(interval, label, fn) {
return this.each(function() {
jQuery.timer.add(this, interval, label, fn, 1);
});
},
stopTime: function(label, fn) {
return this.each(function() {
jQuery.timer.remove(this, label, fn);
});
}
});
jQuery.extend({
timer: {
global: [],
guid: 1,
dataKey: "jQuery.timer",
regex: /^([0-9]+(?:\.[0-9]*)?)\s*(.*s)?$/,
powers: {
// Yeah this is major overkill...
'ms': 1,
'cs': 10,
'ds': 100,
's': 1000,
'das': 10000,
'hs': 100000,
'ks': 1000000
},
timeParse: function(value) {
if (value == undefined || value == null)
return null;
var result = this.regex.exec(jQuery.trim(value.toString()));
if (result[2]) {
var num = parseFloat(result[1]);
var mult = this.powers[result[2]] || 1;
return num * mult;
} else {
return value;
}
},
add: function(element, interval, label, fn, times) {
var counter = 0;
if (jQuery.isFunction(label)) {
if (!times)
times = fn;
fn = label;
label = interval;
}
interval = jQuery.timer.timeParse(interval);
if (typeof interval != 'number' || isNaN(interval) || interval < 0)
return;
if (typeof times != 'number' || isNaN(times) || times < 0)
times = 0;
times = times || 0;
var timers = jQuery.data(element, this.dataKey) || jQuery.data(element, this.dataKey, {});
if (!timers[label])
timers[label] = {};
fn.timerID = fn.timerID || this.guid++;
var handler = function() {
if ((++counter > times && times !== 0) || fn.call(element, counter) === false)
jQuery.timer.remove(element, label, fn);
};
handler.timerID = fn.timerID;
if (!timers[label][fn.timerID])
timers[label][fn.timerID] = window.setInterval(handler,interval);
this.global.push( element );
},
remove: function(element, label, fn) {
var timers = jQuery.data(element, this.dataKey), ret;
if ( timers ) {
if (!label) {
for ( label in timers )
this.remove(element, label, fn);
} else if ( timers[label] ) {
if ( fn ) {
if ( fn.timerID ) {
window.clearInterval(timers[label][fn.timerID]);
delete timers[label][fn.timerID];
}
} else {
for ( var fn in timers[label] ) {
window.clearInterval(timers[label][fn]);
delete timers[label][fn];
}
}
for ( ret in timers[label] ) break;
if ( !ret ) {
ret = null;
delete timers[label];
}
}
for ( ret in timers ) break;
if ( !ret )
jQuery.removeData(element, this.dataKey);
}
}
}
});
jQuery(window).bind("unload", function() {
jQuery.each(jQuery.timer.global, function(index, item) {
jQuery.timer.remove(item);
});
});

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,116 @@
// jXHR.js (JSON-P XHR)
// v0.1 (c) Kyle Simpson
// MIT License
// modified by gueron Jonathan to work with strophe lib
// for http://www.iadvize.com
(function(global){
var SETTIMEOUT = global.setTimeout, // for better compression
doc = global.document,
callback_counter = 0;
global.jXHR = function() {
var script_url,
script_loaded,
jsonp_callback,
scriptElem,
publicAPI = null;
function removeScript() { try { scriptElem.parentNode.removeChild(scriptElem); } catch (err) { } }
function reset() {
script_loaded = false;
script_url = "";
removeScript();
scriptElem = null;
fireReadyStateChange(0);
}
function ThrowError(msg) {
try {
publicAPI.onerror.call(publicAPI,msg,script_url);
} catch (err) {
//throw new Error(msg);
}
}
function handleScriptLoad() {
if ((this.readyState && this.readyState!=="complete" && this.readyState!=="loaded") || script_loaded) { return; }
this.onload = this.onreadystatechange = null; // prevent memory leak
script_loaded = true;
if (publicAPI.readyState !== 4) ThrowError("handleScriptLoad: Script failed to load ["+script_url+"].");
removeScript();
}
function parseXMLString(xmlStr) {
var xmlDoc = null;
if(window.DOMParser) {
var parser = new DOMParser();
xmlDoc = parser.parseFromString(xmlStr,"text/xml");
}
else {
xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async="false";
xmlDoc.loadXML(xmlStr);
}
return xmlDoc;
}
function fireReadyStateChange(rs,args) {
args = args || [];
publicAPI.readyState = rs;
if (rs == 4) {
publicAPI.responseText = args[0].reply;
publicAPI.responseXML = parseXMLString(args[0].reply);
}
if (typeof publicAPI.onreadystatechange === "function") publicAPI.onreadystatechange.apply(publicAPI,args);
}
publicAPI = {
onerror:null,
onreadystatechange:null,
readyState:0,
status:200,
responseBody: null,
responseText: null,
responseXML: null,
open:function(method,url){
reset();
var internal_callback = "cb"+(callback_counter++);
(function(icb){
global.jXHR[icb] = function() {
try { fireReadyStateChange.call(publicAPI,4,arguments); }
catch(err) {
publicAPI.readyState = -1;
ThrowError("Script failed to run ["+script_url+"].");
}
global.jXHR[icb] = null;
};
})(internal_callback);
script_url = url + '?callback=?jXHR&data=';
script_url = script_url.replace(/=\?jXHR/,"=jXHR."+internal_callback);
fireReadyStateChange(1);
},
send:function(data){
script_url = script_url + encodeURIComponent(data);
SETTIMEOUT(function(){
scriptElem = doc.createElement("script");
scriptElem.setAttribute("type","text/javascript");
scriptElem.onload = scriptElem.onreadystatechange = function(){handleScriptLoad.call(scriptElem);};
scriptElem.setAttribute("src",script_url);
doc.getElementsByTagName("head")[0].appendChild(scriptElem);
},0);
fireReadyStateChange(2);
},
abort:function(){},
setRequestHeader:function(){}, // noop
getResponseHeader:function(){return "";}, // basically noop
getAllResponseHeaders:function(){return [];} // ditto
};
reset();
return publicAPI;
};
})(window);

View file

@ -0,0 +1,38 @@
/*
Jappix - An open social platform
These are the links JS script for Jappix
-------------------------------------------------
License: AGPL
Authors: Vanaryon, Maranda
Last revision: 26/08/11
*/
// Apply links in a string
function applyLinks(string, mode, style) {
// Special stuffs
var style, target;
// Links style
if(!style)
style = '';
else
style = ' style="' + style + '"';
// Open in new tabs
if(mode != 'xhtml-im')
target = ' target="_blank"';
else
target = '';
// XMPP address
string = string.replace(/(\s|<br \/>|^)(([a-zA-Z0-9\._-]+)@([a-zA-Z0-9\.\/_-]+))(,|\s|$)/gi, '$1<a href="xmpp:$2" target="_blank"' + style + '>$2</a>$5');
// Simple link
string = string.replace(/(\s|<br \/>|^|\()((https?|ftp|file|xmpp|irc|mailto|vnc|webcal|ssh|ldap|smb|magnet|spotify)(:)([^<>'"\s\)]+))/gim, '$1<a href="$2"' + target + style + '>$2</a>');
return string;
}

View file

@ -0,0 +1,62 @@
/*
Jappix - An open social platform
These are the Jappix Me tool functions for Jappix
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 16/01/12
*/
// Opens the Me tools
function openMe() {
// Popup HTML content
var html =
'<div class="top">' + _e("Public profile") + '</div>' +
'<div class="content">' +
'<a class="me-images logo" href="https://me.jappix.com/" target="_blank"></a>' +
'<div class="infos">' +
'<p class="infos-title">' + _e("Your profile anywhere on the Web.") + '</p>' +
'<p>' + printf(_e("%s is a Jappix.com service which makes your XMPP profile public. It is easier to share it. No XMPP account is required to view your social channel, your current position and your contact details."), '<a href="https://me.jappix.com/" target="_blank">Jappix Me</a>') + '</p>' +
'<p>' + _e("Furthermore, every picture you post in your social channel is added to a beautiful picture timeline. You can now view the pictures you shared year by year.") + '</p>' +
'<p>' + _e("You can also use your XMPP avatar as a single avatar for every website, blog and forum you use. When you change it on XMPP, the new avatar appears everywhere. What a genious improvement!") + '</p>' +
'</div>' +
'<a class="go one-button" href="https://me.jappix.com/new" target="_blank">' + _e("Yay, let's create my public profile!") + '</a>' +
'</div>' +
'<div class="bottom">' +
'<a href="#" class="finish">' + _e("Close") + '</a>' +
'</div>';
// Create the popup
createPopup('me', html);
// Associate the events
launchMe();
logThis('Public profile tool opened.');
}
// Closes the Me tools
function closeMe() {
// Destroy the popup
destroyPopup('me');
return false;
}
// Plugin launcher
function launchMe() {
// Click events
$('#me .content a.go').click(function() {
closeMe();
});
$('#me .bottom .finish').click(closeMe);
}

View file

@ -0,0 +1,900 @@
/*
Jappix - An open social platform
These are the messages JS scripts for Jappix
-------------------------------------------------
License: AGPL
Authors: Vanaryon, Maranda
Last revision: 01/09/11
*/
// Handles the incoming message packets
function handleMessage(message) {
// Error packet? Stop!
if(handleErrorReply(message))
return;
// We get the message items
var from = fullXID(getStanzaFrom(message));
var id = message.getID();
var type = message.getType();
var body = trim(message.getBody());
var node = message.getNode();
var subject = trim(message.getSubject());
// We generate some values
var xid = bareXID(from);
var resource = thisResource(from);
var hash = hex_md5(xid);
var xHTML = $(node).find('html body').size();
var GCUser = false;
// This message comes from a groupchat user
if(isPrivate(xid) && ((type == 'chat') || !type) && resource) {
GCUser = true;
xid = from;
hash = hex_md5(xid);
}
// Get message date
var time, stamp, d_stamp;
// Read the delay
var delay = readMessageDelay(node);
// Any delay?
if(delay) {
time = relativeDate(delay);
d_stamp = Date.jab2date(delay);
}
// No delay: get actual time
else {
time = getCompleteTime();
d_stamp = new Date();
}
// Get the date stamp
stamp = extractStamp(d_stamp);
// Received message
if(hasReceived(message))
return messageReceived(hash, id);
// Chatstate message
if(node && !delay && ((((type == 'chat') || !type) && !exists('#page-switch .' + hash + ' .unavailable')) || (type == 'groupchat'))) {
/* REF: http://xmpp.org/extensions/xep-0085.html */
// Re-process the hash
var chatstate_hash = hash;
if(type == 'groupchat')
chatstate_hash = hex_md5(from);
// Do something depending of the received state
if($(node).find('active').size()) {
displayChatState('active', chatstate_hash, type);
// Tell Jappix the entity supports chatstates
$('#' + chatstate_hash + ' .message-area').attr('data-chatstates', 'true');
logThis('Active chatstate received from: ' + from);
}
else if($(node).find('composing').size())
displayChatState('composing', chatstate_hash, type);
else if($(node).find('paused').size())
displayChatState('paused', chatstate_hash, type);
else if($(node).find('inactive').size())
displayChatState('inactive', chatstate_hash, type);
else if($(node).find('gone').size())
displayChatState('gone', chatstate_hash, type);
}
// Invite message
if($(node).find('x[xmlns=' + NS_MUC_USER + '] invite').size()) {
// We get the needed values
var iFrom = $(node).find('x[xmlns=' + NS_MUC_USER + '] invite').attr('from');
var iRoom = $(node).find('x[xmlns=' + NS_XCONFERENCE + ']').attr('jid');
// Old invite method?
if(!iRoom)
iRoom = from;
// We display the notification
newNotification('invite_room', iFrom, [iRoom], body);
logThis('Invite Request from: ' + iFrom + ' to join: ' + iRoom);
return false;
}
// Request message
if(message.getChild('confirm', NS_HTTP_AUTH)) {
// Open a new notification
newNotification('request', xid, [message], body);
logThis('HTTP Request from: ' + xid);
return false;
}
// OOB message
if(message.getChild('x', NS_XOOB)) {
handleOOB(from, id, 'x', node);
logThis('Message OOB request from: ' + xid);
return false;
}
// Roster Item Exchange message
if(message.getChild('x', NS_ROSTERX)) {
// Open a new notification
newNotification('rosterx', xid, [message], body);
logThis('Roster Item Exchange from: ' + xid);
return false;
}
// Normal message
if((type == 'normal') && body) {
// Message date
var messageDate = delay;
// No message date?
if(!messageDate)
messageDate = getXMPPTime('utc');
// Message ID
var messageID = hex_md5(xid + subject + messageDate);
// We store the received message
storeInboxMessage(xid, subject, body, 'unread', messageID, messageDate);
// Display the inbox message
if(exists('#inbox'))
displayInboxMessage(xid, subject, body, 'unread', messageID, messageDate);
// Check we have new messages (play a sound if any unread messages)
if(checkInboxMessages())
soundPlay(2);
// Send it to the server
storeInbox();
return false;
}
// PubSub event
if($(node).find('event').attr('xmlns') == NS_PUBSUB_EVENT) {
// We get the needed values
var iParse = $(node).find('event items');
var iNode = iParse.attr('node');
// Turn around the different result cases
if(iNode) {
switch(iNode) {
// Mood
case NS_MOOD:
// Retrieve the values
var iMood = iParse.find('mood');
var fValue = '';
var tText = '';
// There's something
if(iMood.children().size()) {
// Read the value
fValue = node.getElementsByTagName('mood').item(0).childNodes.item(0).nodeName;
// Read the text
tText = iMood.find('text').text();
// Avoid errors
if(!fValue)
fValue = '';
}
// Store the PEP event (and display it)
storePEP(xid, 'mood', fValue, tText);
break;
// Activity
case NS_ACTIVITY:
// Retrieve the values
var iActivity = iParse.find('activity');
var sValue = '';
var tText = '';
// There's something
if(iActivity.children().size()) {
// Read the value
fValue = node.getElementsByTagName('activity').item(0).childNodes.item(0).nodeName;
// Read the text
tText = iActivity.find('text').text();
// Avoid errors
if(!fValue)
fValue = '';
}
// Store the PEP event (and display it)
storePEP(xid, 'activity', fValue, tText);
break;
// Tune
case NS_TUNE:
// Retrieve the values
var iTune = iParse.find('tune');
var tArtist = iTune.find('artist').text();
var tSource = iTune.find('source').text();
var tTitle = iTune.find('title').text();
var tURI = iTune.find('uri').text();
// Store the PEP event (and display it)
storePEP(xid, 'tune', tArtist, tTitle, tSource, tURI);
break;
// Geolocation
case NS_GEOLOC:
// Retrieve the values
var iGeoloc = iParse.find('geoloc');
var tLat = iGeoloc.find('lat').text();
var tLon = iGeoloc.find('lon').text();
// Any extra-values?
var tLocality = iGeoloc.find('locality').text();
var tRegion = iGeoloc.find('region').text();
var tCountry = iGeoloc.find('country').text();
var tHuman = humanPosition(tLocality, tRegion, tCountry);
// Store the PEP event (and display it)
storePEP(xid, 'geoloc', tLat, tLon, tHuman);
break;
// Microblog
case NS_URN_MBLOG:
displayMicroblog(message, xid, hash, 'mixed', 'push');
break;
// Inbox
case NS_URN_INBOX:
// Do not handle friend's notifications
if(xid == getXID())
handleNotifications(message);
break;
}
}
return false;
}
// If this is a room topic message
if(subject && (type == 'groupchat')) {
// Filter the vars
var filter_subject = subject.replace(/\n+/g, ' ');
var filteredSubject = filterThisMessage(filter_subject, resource, true);
var filteredName = resource.htmlEnc();
// Display the new subject at the top
$('#' + hash + ' .top .name .bc-infos .muc-topic').replaceWith('<span class="muc-topic" title="' + filter_subject + '">' + filteredSubject + '</span>');
// Display the new subject as a system message
if(resource) {
var topic_body = filteredName + ' ' + _e("changed the subject to:") + ' ' + filterThisMessage(subject, resource, true);
displayMessage(type, from, hash, filteredName, topic_body, time, stamp, 'system-message', false);
}
}
// If the message has a content
if(xHTML || body) {
var filteredMessage;
var notXHTML = true;
// IE bug fix
if((BrowserDetect.browser == 'Explorer') && (BrowserDetect.version < 9))
xHTML = 0;
//If this is a xHTML message
if(xHTML) {
notXHTML = false;
// Filter the xHTML message
body = filterThisXHTML(node);
}
// Groupchat message
if(type == 'groupchat') {
/* REF: http://xmpp.org/extensions/xep-0045.html */
// We generate the message type and time
var message_type = 'user-message';
// This is an old message
if(delay && resource)
message_type = 'old-message';
// This is a system message
else if(!resource)
message_type = 'system-message';
var nickQuote = '';
// If this is not an old message
if(message_type == 'user-message') {
var myNick = getMUCNick(hash);
// If an user quoted our nick (with some checks)
var regex = new RegExp('((^)|( )|(@))' + escapeRegex(myNick) + '(($)|(:)|(,)|( ))', 'gi');
if(body.match(regex) && (myNick != resource) && (message_type == 'user-message'))
nickQuote = ' my-nick';
// We notify the user if there's a new personnal message
if(nickQuote) {
messageNotify(hash, 'personnal');
soundPlay(1);
}
// We notify the user there's a new unread muc message
else
messageNotify(hash, 'unread');
}
// Display the received message
displayMessage(type, from, hash, resource.htmlEnc(), body, time, stamp, message_type, notXHTML, nickQuote);
}
// Chat message
else if((type == 'chat') || !type) {
// Gets the nickname of the user
var fromName = resource;
var chatType = 'chat';
// Must send a receipt notification?
if(hasReceipt(message) && (id != null))
sendReceived(type, from, id);
// It does not come from a groupchat user, get the full name
if(!GCUser)
fromName = getBuddyName(xid);
else
chatType = 'private';
// If the chat isn't yet opened, open it !
if(!exists('#' + hash)) {
// We create a new chat
chatCreate(hash, xid, fromName, chatType);
// We tell the user that a new chat has started
soundPlay(0);
}
else
soundPlay(1);
// Display the received message
displayMessage(type, xid, hash, fromName.htmlEnc(), body, time, stamp, 'user-message', notXHTML, '', 'him');
// We notify the user
messageNotify(hash, 'personnal');
}
return false;
}
return false;
}
// Sends a given message
function sendMessage(hash, type) {
// Get the values
var message_area = $('#' + hash + ' .message-area');
var body = trim(message_area.val());
var xid = unescape(message_area.attr('data-to'));
// If the user didn't entered any message, stop
if(!body || !xid)
return false;
try {
// We send the message through the XMPP network
var aMsg = new JSJaCMessage();
aMsg.setTo(xid);
// Set an ID
var id = genID();
aMsg.setID(id);
// /help shortcut
if(body.match(/^\/help\s*(.*)/)) {
// Help text
var help_text = '<p class="help" xmlns="http://www.w3.org/1999/xhtml">';
help_text += '<b>' + _e("Available shortcuts:") + '</b>';
// Shortcuts array
var shortcuts = [];
// Common shortcuts
shortcuts.push(printf(_e("%s removes the chat logs"), '<em>/clear</em>'));
shortcuts.push(printf(_e("%s joins a groupchat"), '<em>/join jid</em>'));
shortcuts.push(printf(_e("%s closes the chat"), '<em>/part</em>'));
shortcuts.push(printf(_e("%s shows the user profile"), '<em>/whois jid</em>'));
// Groupchat shortcuts
if(type == 'groupchat') {
shortcuts.push(printf(_e("%s sends a message to the room"), '<em>/say message</em>'));
shortcuts.push(printf(_e("%s changes your nickname"), '<em>/nick nickname</em>'));
shortcuts.push(printf(_e("%s sends a message to someone in the room"), '<em>/msg nickname message</em>'));
shortcuts.push(printf(_e("%s changes the room topic"), '<em>/topic subject</em>'));
shortcuts.push(printf(_e("%s kicks an user of the room"), '<em>/kick nickname reason</em>'));
shortcuts.push(printf(_e("%s bans an user of the room"), '<em>/ban nickname reason</em>'));
shortcuts.push(printf(_e("%s invites someone to join the room"), '<em>/invite jid message</em>'));
}
// Generate the code from the array
shortcuts = shortcuts.sort();
for(s in shortcuts)
help_text += shortcuts[s] + '<br />';
help_text += '</p>';
// Display the message
displayMessage(type, xid, hash, 'help', help_text, getCompleteTime(), getTimeStamp(), 'system-message', false);
// Reset chatstate
chatStateSend('active', xid, hash);
}
// /clear shortcut
else if(body.match(/^\/clear/)) {
cleanChat(hex_md5(xid));
// Reset chatstate
chatStateSend('active', xid, hash);
}
// /join shortcut
else if(body.match(/^\/join (\S+)\s*(.*)/)) {
// Join
var room = generateXID(RegExp.$1, 'groupchat');
var pass = RegExp.$2;
checkChatCreate(room, 'groupchat');
// Reset chatstate
chatStateSend('active', xid, hash);
}
// /part shortcut
else if(body.match(/^\/part\s*(.*)/) && (!isAnonymous() || (isAnonymous() && (xid != generateXID(ANONYMOUS_ROOM, 'groupchat')))))
quitThisChat(xid, hex_md5(xid), type);
// /whois shortcut
else if(body.match(/^\/whois(( (\S+))|($))/)) {
var whois_xid = RegExp.$3;
// Groupchat WHOIS
if(type == 'groupchat') {
var nXID = getMUCUserXID(xid, whois_xid);
if(!nXID)
openThisInfo(6);
else
openUserInfos(nXID);
}
// Chat or private WHOIS
else {
if(!whois_xid)
openUserInfos(xid);
else
openUserInfos(whois_xid);
}
// Reset chatstate
chatStateSend('active', xid, hash);
}
// Chat message type
else if(type == 'chat') {
aMsg.setType('chat');
// Generates the correct message depending of the choosen style
var notXHTML = true;
var genMsg = generateMessage(aMsg, body, hash);
if(genMsg == 'XHTML')
notXHTML = false;
// Receipt request
var receipt_request = receiptRequest(hash);
if(receipt_request)
aMsg.appendNode('request', {'xmlns': NS_URN_RECEIPTS});
// Chatstate
aMsg.appendNode('active', {'xmlns': NS_CHATSTATES});
// Send it!
con.send(aMsg, handleErrorReply);
// Filter the xHTML message (for us!)
if(!notXHTML)
body = filterThisXHTML(aMsg.getNode());
// Finally we display the message we just sent
var my_xid = getXID();
displayMessage('chat', my_xid, hash, getBuddyName(my_xid).htmlEnc(), body, getCompleteTime(), getTimeStamp(), 'user-message', notXHTML, '', 'me', id);
// Receipt timer
if(receipt_request)
checkReceived(hash, id);
}
// Groupchat message type
else if(type == 'groupchat') {
// /say shortcut
if(body.match(/^\/say (.+)/)) {
body = body.replace(/^\/say (.+)/, '$1');
aMsg.setType('groupchat');
generateMessage(aMsg, body, hash);
con.send(aMsg, handleErrorReply);
}
// /nick shortcut
else if(body.match(/^\/nick (.+)/)) {
var nick = body.replace(/^\/nick (.+)/, '$1');
// Does not exist yet?
if(!getMUCUserXID(xid, nick)) {
// Send a new presence
sendPresence(xid + '/' + nick, '', getUserShow(), getUserStatus(), '', false, false, handleErrorReply);
// Change the stored nickname
$('#' + hex_md5(xid)).attr('data-nick', escape(nick));
// Reset chatstate
chatStateSend('active', xid, hash);
}
}
// /msg shortcut
else if(body.match(/^\/msg (\S+)\s+(.+)/)) {
var nick = RegExp.$1;
var body = RegExp.$2;
var nXID = getMUCUserXID(xid, nick);
// We check if the user exists
if(!nXID)
openThisInfo(6);
// If the private message is not empty
else if(body) {
aMsg.setType('chat');
aMsg.setTo(nXID);
generateMessage(aMsg, body, hash);
con.send(aMsg, handleErrorReply);
}
}
// /topic shortcut
else if(body.match(/^\/topic (.+)/)) {
var topic = body.replace(/^\/topic (.+)/, '$1');
aMsg.setType('groupchat');
aMsg.setSubject(topic);
con.send(aMsg, handleMessageError);
// Reset chatstate
chatStateSend('active', xid, hash);
}
// /ban shortcut
else if(body.match(/^\/ban (\S+)\s*(.*)/)) {
var nick = RegExp.$1;
var reason = RegExp.$2;
var nXID = getMUCUserRealXID(xid, nick);
// We check if the user exists
if(!nXID)
openThisInfo(6);
else {
// We generate the ban IQ
var iq = new JSJaCIQ();
iq.setTo(xid);
iq.setType('set');
var iqQuery = iq.setQuery(NS_MUC_ADMIN);
var item = iqQuery.appendChild(iq.buildNode('item', {'affiliation': 'outcast', 'jid': nXID, 'xmlns': NS_MUC_ADMIN}));
if(reason)
item.appendChild(iq.buildNode('reason', {'xmlns': NS_MUC_ADMIN}, reason));
con.send(iq, handleErrorReply);
}
// Reset chatstate
chatStateSend('active', xid, hash);
}
// /kick shortcut
else if(body.match(/^\/kick (\S+)\s*(.*)/)) {
var nick = RegExp.$1;
var reason = RegExp.$2;
var nXID = getMUCUserXID(xid, nick);
// We check if the user exists
if(!nXID)
openThisInfo(6);
else {
// We generate the kick IQ
var iq = new JSJaCIQ();
iq.setTo(xid);
iq.setType('set');
var iqQuery = iq.setQuery(NS_MUC_ADMIN);
var item = iqQuery.appendChild(iq.buildNode('item', {'nick': nick, 'role': 'none', 'xmlns': NS_MUC_ADMIN}));
if(reason)
item.appendChild(iq.buildNode('reason', {'xmlns': NS_MUC_ADMIN}, reason));
con.send(iq, handleErrorReply);
}
// Reset chatstate
chatStateSend('active', xid, hash);
}
// /invite shortcut
else if(body.match(/^\/invite (\S+)\s*(.*)/)) {
var i_xid = RegExp.$1;
var reason = RegExp.$2;
var x = aMsg.appendNode('x', {'xmlns': NS_MUC_USER});
var aNode = x.appendChild(aMsg.buildNode('invite', {'to': i_xid, 'xmlns': NS_MUC_USER}));
if(reason)
aNode.appendChild(aMsg.buildNode('reason', {'xmlns': NS_MUC_USER}, reason));
con.send(aMsg, handleErrorReply);
// Reset chatstate
chatStateSend('active', xid, hash);
}
// No shortcut, this is a message
else {
aMsg.setType('groupchat');
// Chatstate
aMsg.appendNode('active', {'xmlns': NS_CHATSTATES});
generateMessage(aMsg, body, hash);
con.send(aMsg, handleMessageError);
logThis('Message sent to: ' + xid + ' / ' + type, 3);
}
}
// We reset the message input
$('#' + hash + ' .message-area').val('');
}
finally {
return false;
}
}
// Generates the correct message area style
function generateStyle(hash) {
// Initialize the vars
var styles = '#' + hash + ' div.bubble-style';
var checkbox = styles + ' input[type=checkbox]';
var color = styles + ' a.color.selected';
var style = '';
// Loop the input values
$(checkbox).filter(':checked').each(function() {
// If there is a previous element
if(style)
style += ' ';
// Get the current style
switch($(this).attr('class')) {
case 'bold':
style += 'font-weight: bold;';
break;
case 'italic':
style += 'font-style: italic;';
break;
case 'underline':
style += 'text-decoration: underline;';
break;
}
});
// Get the color value
$(color).each(function() {
style += 'color: #' + $(this).attr('data-color');
});
return style;
}
// Generates the correct message code
function generateMessage(aMsg, body, hash) {
// Create the classical body
aMsg.setBody(body);
// Get the style
var style = $('#' + hash + ' .message-area').attr('style');
// A message style is choosen
if(style) {
// Explode the message body new lines (to create one <p /> element by line)
var new_lines = new Array(body);
if(body.match(/\n/))
new_lines = body.split('\n');
// Create the XML elements
var aHtml = aMsg.appendNode('html', {'xmlns': NS_XHTML_IM});
var aBody = aHtml.appendChild(aMsg.buildNode('body', {'xmlns': NS_XHTML}));
// Use the exploded body array to create one element per entry
for(i in new_lines) {
// Current line
var cLine = new_lines[i];
// Blank line, we put a <br />
if(cLine.match(/(^)(\s+)($)/) || !cLine)
aBody.appendChild(aMsg.buildNode('br', {'xmlns': NS_XHTML}));
// Line with content, we put a <p />
else {
// HTML encode the line
cLine = cLine.htmlEnc();
// Filter the links
cLine = applyLinks(cLine, 'xhtml-im', style);
// Append the filtered line
$(aBody).append($('<p style="' + style + '">' + cLine + '</p>'));
}
}
return 'XHTML';
}
return 'PLAIN';
}
// Displays a given message in a chat tab
function displayMessage(type, xid, hash, name, body, time, stamp, message_type, is_xhtml, nick_quote, mode, id) {
// Generate some stuffs
var has_avatar = false;
var xid_hash = '';
if(!nick_quote)
nick_quote = '';
if(message_type != 'system-message') {
has_avatar = true;
xid_hash = hex_md5(xid);
}
// Can scroll?
var cont_scroll = document.getElementById('chat-content-' + hash);
var can_scroll = false;
if(!cont_scroll.scrollTop || ((cont_scroll.clientHeight + cont_scroll.scrollTop) == cont_scroll.scrollHeight))
can_scroll = true;
// Any ID?
var data_id = '';
if(id)
data_id = ' data-id="' + id + '"';
// Filter the message
var filteredMessage = filterThisMessage(body, name, is_xhtml);
// Display the received message in the room
var messageCode = '<div class="one-line ' + message_type + nick_quote + '"' + data_id + '>';
// Name color attribute
if(type == 'groupchat')
attribute = ' style="color: ' + generateColor(name) + ';" class="name';
else {
attribute = ' class="name';
if(mode)
attribute += ' ' + mode;
}
// Close the class attribute
if(message_type == 'system-message')
attribute += ' hidden"';
else
attribute += '"';
// Filter the previous displayed message
var last = $('#' + hash + ' .one-group:last');
var last_name = last.find('b.name').attr('data-xid');
var last_type = last.attr('data-type');
var last_stamp = parseInt(last.attr('data-stamp'));
var grouped = false;
// We can group it with another previous message
if((last_name == xid) && (message_type == last_type) && ((stamp - last_stamp) <= 1800))
grouped = true;
// Is it a /me command?
if(body.match(/(^|>)(\/me )([^<]+)/))
filteredMessage = '<i>' + filteredMessage + '</i>';
messageCode += filteredMessage + '</div>';
// Must group it?
var group_path = ' .one-group:last';
if(!grouped) {
// Generate message headers
var message_head = '';
// Any avatar to add?
if(has_avatar)
message_head += '<div class="avatar-container"><img class="avatar" src="' + './img/others/default-avatar.png' + '" alt="" /></div>';
// Add the date & the name
message_head += '<span class="date">' + time + '</span><b data-xid="' + encodeQuotes(xid) + '" ' + attribute + '>' + name + '</b>';
// Generate message code
group_path = '';
messageCode = '<div class="one-group ' + xid_hash + '" data-type="' + message_type + '" data-stamp="' + stamp + '">' + message_head + messageCode + '</div>';
}
// Archive message
if(hash == 'archives')
$('#archives .logs' + group_path).append(messageCode);
// Instant message
else {
// Write the code in the DOM
$('#' + hash + ' .content' + group_path).append(messageCode);
// Must get the avatar?
if(has_avatar && xid)
getAvatar(xid, 'cache', 'true', 'forget');
}
// Scroll to this message
if(can_scroll)
autoScroll(hash);
}

File diff suppressed because it is too large Load diff

1623
jappixmini/jappix/js/mini.js Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,592 @@
/*
Jappix - An open social platform
These are the Jappix Mobile lightweight JS script
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 10/07/11
*/
/* BEGIN CONNECTION FUNCTIONS */
function doLogin(aForm) {
try {
// Reset the panels
resetPanel();
// Get the values
var xid = aForm.xid.value;
var username, domain;
// A domain is specified
if(xid.indexOf('@') != -1) {
username = getXIDNick(xid);
domain = getXIDHost(xid);
// Domain is locked and not the same
if((LOCK_HOST == 'on') && (domain != HOST_MAIN)) {
showThis('error');
return false;
}
}
// No "@" in the XID, we should add the default domain
else {
username = xid;
domain = HOST_MAIN;
}
var pwd = aForm.pwd.value;
var reg = false;
if(aForm.reg)
reg = aForm.reg.checked;
// Enough parameters
if(username && domain && pwd) {
// Show the info notification
showThis('info');
// We define the http binding parameters
oArgs = new Object();
if(HOST_BOSH_MAIN)
oArgs.httpbase = HOST_BOSH_MAIN;
else
oArgs.httpbase = HOST_BOSH;
// We create the new http-binding connection
con = new JSJaCHttpBindingConnection(oArgs);
// And we handle everything that happen
con.registerHandler('message', handleMessage);
con.registerHandler('presence', handlePresence);
con.registerHandler('iq', handleIQ);
con.registerHandler('onconnect', handleConnected);
con.registerHandler('onerror', handleError);
con.registerHandler('ondisconnect', handleDisconnected);
// We retrieve what the user typed in the login inputs
oArgs = new Object();
oArgs.username = username;
oArgs.domain = domain;
oArgs.resource = JAPPIX_RESOURCE + ' Mobile (' + (new Date()).getTime() + ')';
oArgs.pass = pwd;
oArgs.secure = true;
oArgs.xmllang = XML_LANG;
// Register?
if(reg)
oArgs.register = true;
// We connect !
con.connect(oArgs);
}
// Not enough parameters
else
showThis('error');
}
catch(e) {
// An error happened
resetPanel('error');
}
finally {
return false;
}
}
function doLogout() {
con.disconnect();
}
/* END CONNECTION FUNCTIONS */
/* BEGIN SHOW/HIDE FUNCTIONS */
function showThis(id) {
document.getElementById(id).style.display = 'block';
}
function hideThis(id) {
document.getElementById(id).style.display = 'none';
}
function resetPanel(id) {
// Hide the opened panels
hideThis('info');
hideThis('error');
//Show the target panel
if(id)
showThis(id);
}
function resetDOM() {
// Reset the "secret" input values
document.getElementById('pwd').value = '';
// Remove the useless DOM elements
var body = document.getElementsByTagName('body')[0];
body.removeChild(document.getElementById('talk'));
body.removeChild(document.getElementById('chat'));
}
/* END SHOW/HIDE FUNCTIONS */
/* BEGIN SYSTEM FUNCTIONS */
function exists(id) {
if(!document.getElementById(id))
return false;
else
return true;
}
function _e(string) {
return string;
}
function encodeOnclick(str) {
return str.replace(/'/g, '\\$&').replace(/"/g, '&quot;');
}
function getJappixLocation() {
var url = window.location.href;
// If the URL has variables, remove them
if(url.indexOf('?') != -1)
url = url.split('?')[0];
if(url.indexOf('#') != -1)
url = url.split('#')[0];
// No "/" at the end
if(!url.match(/(.+)\/$/))
url += '/';
return url;
}
/* END SYSTEM FUNCTIONS */
/* BEGIN HANDLING FUNCTIONS */
function handleMessage(msg) {
var type = msg.getType();
if(type == 'chat' || type == 'normal') {
// Get the body
var body = msg.getBody();
if(body) {
// Get the values
var xid = cutResource(msg.getFrom());
var hash = hex_md5(xid);
var nick = getNick(xid, hash);
// No nickname?
if(!nick)
nick = xid;
// Create the chat if it does not exist
chat(xid, nick);
// Display the message
displayMessage(xid, body, nick, hash);
}
}
}
function handlePresence(pre) {
// Define the variables
var xid = cutResource(pre.getFrom());
var hash = hex_md5(xid);
var type = pre.getType();
var show = pre.getShow();
// Online buddy: show it!
if(!type) {
showThis('buddy-' + hash);
// Display the correct presence
switch(show) {
case 'chat':
displayPresence(hash, show);
break;
case 'away':
displayPresence(hash, show);
break;
case 'xa':
displayPresence(hash, show);
break;
case 'dnd':
displayPresence(hash, show);
break;
default:
displayPresence(hash, 'available');
break;
}
}
else
hideThis('buddy-' + hash);
}
function handleIQ(iq) {
// Get the content
var iqFrom = iq.getFrom();
var iqID = iq.getID();
var iqQueryXMLNS = iq.getQueryXMLNS();
var iqType = iq.getType();
// Create the response
if((iqType == 'get') && ((iqQueryXMLNS == NS_DISCO_INFO) || (iqQueryXMLNS == NS_VERSION))) {
var iqResponse = new JSJaCIQ();
iqResponse.setID(iqID);
iqResponse.setTo(iqFrom);
iqResponse.setType('result');
}
// Disco#infos query
if((iqQueryXMLNS == NS_DISCO_INFO) && (iqType == 'get')) {
/* REF: http://xmpp.org/extensions/xep-0030.html */
var iqQuery = iqResponse.setQuery(NS_DISCO_INFO);
// We set the name of the client
iqQuery.appendChild(iq.appendNode('identity', {
'category': 'client',
'type': 'mobile',
'name': 'Jappix Mobile'
}));
// We set all the supported features
var fArray = new Array(
NS_DISCO_INFO,
NS_VERSION
);
for(i in fArray)
iqQuery.appendChild(iq.buildNode('feature', {'var': fArray[i]}));
con.send(iqResponse);
}
// Software version query
else if((iqQueryXMLNS == NS_VERSION) && (iqType == 'get')) {
/* REF: http://xmpp.org/extensions/xep-0092.html */
var iqQuery = iqResponse.setQuery(NS_VERSION);
iqQuery.appendChild(iq.buildNode('name', 'Jappix Mobile'));
iqQuery.appendChild(iq.buildNode('version', JAPPIX_VERSION));
iqQuery.appendChild(iq.buildNode('os', BrowserDetect.OS));
con.send(iqResponse);
}
}
function handleConnected() {
// Reset the elements
hideThis('home');
resetPanel();
// Create the talk page
document.getElementsByTagName('body')[0].innerHTML +=
'<div id="talk">' +
'<div class="header">' +
'<div class="mobile-images"></div>' +
'<button onclick="doLogout();">' + _e("Disconnect") + '</button>' +
'</div>' +
'<div id="roster"></div>' +
'</div>' +
'<div id="chat">' +
'<div class="header">' +
'<div class="mobile-images"></div>' +
'<button onclick="returnToRoster();">' + _e("Previous") + '</button>' +
'</div>' +
'<div id="chans"></div>' +
'</div>';
// Get the roster items
getRoster();
}
function handleError(error) {
resetPanel('error');
}
function handleDisconnected() {
// Reset the elements
resetDOM();
// Show the home page
showThis('home');
}
function handleRoster(iq) {
// Error: send presence anyway
if(!iq || (iq.getType() != 'result'))
return sendPresence('', 'available', 1);
// Define some pre-vars
var current, xid, nick, oneBuddy, oneID, hash;
var roster = document.getElementById('roster');
// Get roster items
var iqNode = iq.getNode();
var bItems = iqNode.getElementsByTagName('item');
// Display each elements from the roster
for(var i = 0; i < bItems.length; i++) {
// Get the values
current = iqNode.getElementsByTagName('item').item(i);
xid = current.getAttribute('jid').htmlEnc();
nick = current.getAttribute('name');
hash = hex_md5(xid);
// No defined nick?
if(!nick)
nick = getDirectNick(xid);
// Display the values
oneBuddy = document.createElement('a');
oneID = 'buddy-' + hash;
oneBuddy.setAttribute('href', '#');
oneBuddy.setAttribute('id', oneID);
oneBuddy.setAttribute('class', 'one-buddy');
oneBuddy.setAttribute('onclick', 'return chat(\'' + encodeOnclick(xid) + '\', \'' + encodeOnclick(nick) + '\');');
oneBuddy.innerHTML = nick.htmlEnc();
roster.appendChild(oneBuddy);
}
// Start handling buddies presence
sendPresence('', 'available', 1);
}
/* END HANDLING FUNCTIONS */
/* BEGIN SENDING FUNCTIONS */
function sendMessage(aForm) {
try {
var body = aForm.body.value;
var xid = aForm.xid.value;
var hash = hex_md5(xid);
if(body && xid) {
// Send the message
var aMsg = new JSJaCMessage();
aMsg.setTo(xid);
aMsg.setType('chat');
aMsg.setBody(body);
con.send(aMsg);
// Clear our input
aForm.body.value = '';
// Display the message we sent
displayMessage(xid, body, 'me', hash);
}
}
finally {
return false;
}
}
function sendPresence(type, show, priority, status) {
var presence = new JSJaCPresence();
if(type)
presence.setType(type);
if(show)
presence.setShow(show);
if(priority)
presence.setPriority(priority);
if(status)
presence.setStatus(status);
con.send(presence);
}
/* END SENDING FUNCTIONS */
/* BEGIN GETTING FUNCTIONS */
function getRoster() {
iq = new JSJaCIQ();
iq.setType('get');
iq.setQuery(NS_ROSTER);
con.send(iq, handleRoster);
}
function getDirectNick(xid) {
return explodeThis('@', xid, 0);
}
function getNick(xid, hash) {
var path = 'buddy-' + hash;
if(exists(path))
return document.getElementById(path).innerHTML;
else
getDirectNick(xid);
}
/* END GETTING FUNCTIONS */
/* BEGIN RESOURCES FUNCTIONS */
function explodeThis(toEx, toStr, i) {
// Get the index of our char to explode
var index = toStr.indexOf(toEx);
// We split if necessary the string
if(index != -1) {
if(i == 0)
toStr = toStr.substr(0, index);
else
toStr = toStr.substr(index + 1);
}
// We return the value
return toStr;
}
function cutResource(aXID) {
return explodeThis('/', aXID, 0);
}
function getXIDNick(aXID) {
return explodeThis('@', aXID, 0);
}
function getXIDHost(aXID) {
return explodeThis('@', aXID, 1);
}
/* END RESOURCES FUNCTIONS */
/* BEGIN CHAT FUNCTIONS */
function filter(msg) {
var msg = msg
// Encode in HTML
.htmlEnc()
// Highlighted text
.replace(/(\s|^)\*(.+)\*(\s|$)/gi,'$1<em>$2</em>$3');
// Links
msg = applyLinks(msg, 'mini');
return msg;
}
function displayMessage(xid, body, nick, hash) {
// Get the path
var path = 'content-' + hash;
// Display the message
html = '<span><b';
if(nick == 'me')
html += ' class="me">' + _e("You");
else
html += ' class="him">' + nick;
html += '</b> ' + filter(body) + '</span>';
document.getElementById(path).innerHTML += html;
// Scroll to the last element
document.getElementById(path).lastChild.scrollIntoView();
}
function returnToRoster() {
// Hide the chats
hideThis('chat');
// Show the roster
showThis('talk');
}
function chatSwitch(hash) {
// Hide the roster page
hideThis('talk');
// Hide the other chats
var divs = document.getElementsByTagName('div');
for(var i = 0; i < divs.length; i++) {
if(divs.item(i).getAttribute('class') == 'one-chat')
divs.item(i).style.display = 'none';
}
// Show the chat
showThis('chat');
showThis(hash);
}
function createChat(xid, nick, hash) {
// Define the variables
var chat = document.getElementById('chans');
var oneChat = document.createElement('div');
// Apply the DOM modification
oneChat.setAttribute('id', 'chat-' + hash);
oneChat.setAttribute('class', 'one-chat');
oneChat.innerHTML = '<p>' + nick + '</p><div id="content-' + hash + '"></div><form action="#" method="post" onsubmit="return sendMessage(this);"><input type="text" name="body" /><input type="hidden" name="xid" value="' + xid + '" /><input type="submit" class="submit" value="OK" /></form>';
chat.appendChild(oneChat);
}
function chat(xid, nick) {
var hash = hex_md5(xid);
// If the chat was not yet opened
if(!exists('chat-' + hash)) {
// No nick?
if(!nick)
nick = getNick(xid, hash);
// Create the chat
createChat(xid, nick, hash);
}
// Switch to the chat
chatSwitch('chat-' + hash);
return false;
}
/* END CHAT FUNCTIONS */
/* BEGIN PRESENCE FUNCTIONS */
function displayPresence(hash, show) {
document.getElementById('buddy-' + hash).setAttribute('class', 'one-buddy ' + show);
}
/* END PRESENCE FUNCTIONS */
/* BEGIN DOCUMENT EVENTS FUNCTIONS */
onbeforeunload = doLogout;
/* END DOCUMENT EVENTS FUNCTIONS */

View file

@ -0,0 +1,373 @@
/*
Jappix - An open social platform
These are the mucadmin JS scripts for Jappix
-------------------------------------------------
License: AGPL
Authors: Vanaryon, Maranda
Last revision: 03/03/11
*/
// Opens the MUC admin popup
function openMucAdmin(xid, aff) {
// Popup HTML content
var html_full =
'<div class="top">' + _e("MUC administration") + '</div>' +
'<div class="content">' +
'<div class="head mucadmin-head">' +
'<div class="head-text mucadmin-head-text">' + _e("You administrate this room") + '</div>' +
'<div class="mucadmin-head-jid">' + xid + '</div>' +
'</div>' +
'<div class="mucadmin-forms">' +
'<div class="mucadmin-topic">' +
'<fieldset>' +
'<legend>' + _e("Subject") + '</legend>' +
'<label for="topic-text">' + _e("Enter new subject") + '</label>' +
'<textarea id="topic-text" name="room-topic" rows="8" cols="60" ></textarea>' +
'</fieldset>' +
'</div>' +
'<div class="mucadmin-conf">' +
'<fieldset>' +
'<legend>' + _e("Configuration") + '</legend>' +
'<div class="results mucadmin-results"></div>' +
'</fieldset>' +
'</div>' +
'<div class="mucadmin-aut">' +
'<fieldset>' +
'<legend>' + _e("Authorizations") + '</legend>' +
'<label>' + _e("Member list") + '</label>' +
'<div class="aut-member aut-group">' +
'<a href="#" class="aut-add" onclick="return addInputMucAdmin(\'\', \'member\');">' + _e("Add an input") + '</a>' +
'</div>' +
'<label>' + _e("Owner list") + '</label>' +
'<div class="aut-owner aut-group">' +
'<a href="#" class="aut-add" onclick="return addInputMucAdmin(\'\', \'owner\');">' + _e("Add an input") + '</a>' +
'</div>' +
'<label>' + _e("Administrator list") + '</label>' +
'<div class="aut-admin aut-group">' +
'<a href="#" class="aut-add" onclick="return addInputMucAdmin(\'\', \'admin\');">' + _e("Add an input") + '</a>' +
'</div>' +
'<label>' + _e("Outcast list") + '</label>' +
'<div class="aut-outcast aut-group">' +
'<a href="#" class="aut-add" onclick="return addInputMucAdmin(\'\', \'outcast\');">' + _e("Add an input") + '</a>' +
'</div>' +
'</fieldset>' +
'</div>' +
'<div class="mucadmin-others">' +
'<fieldset>' +
'<legend>' + _e("Others") + '</legend>' +
'<label>' + _e("Destroy this MUC") + '</label>' +
'<a href="#" onclick="return destroyMucAdmin();">' + _e("Yes, let's do it!") + '</a>' +
'</fieldset>' +
'</div>' +
'</div>' +
'</div>' +
'<div class="bottom">' +
'<div class="wait wait-medium"></div>' +
'<a href="#" class="finish save">' + _e("Save") + '</a>' +
'<a href="#" class="finish cancel">' + _e("Cancel") + '</a>' +
'</div>';
var html_partial =
'<div class="top">' + _e("MUC administration") + '</div>' +
'<div class="content">' +
'<div class="head mucadmin-head">' +
'<div class="head-text mucadmin-head-text">' + _e("You administrate this room") + '</div>' +
'<div class="mucadmin-head-jid">' + xid + '</div>' +
'</div>' +
'<div class="mucadmin-forms">' +
'<div class="mucadmin-aut">' +
'<fieldset>' +
'<legend>' + _e("Authorizations") + '</legend>' +
'<label>' + _e("Member list") + '</label>' +
'<div class="aut-member aut-group">' +
'<a href="#" class="aut-add" onclick="return addInputMucAdmin(\'\', \'member\');">' + _e("Add an input") + '</a>' +
'</div>' +
'<label>' + _e("Outcast list") + '</label>' +
'<div class="aut-outcast aut-group">' +
'<a href="#" class="aut-add" onclick="return addInputMucAdmin(\'\', \'outcast\');">' + _e("Add an input") + '</a>' +
'</div>' +
'</fieldset>' +
'</div>' +
'</div>' +
'</div>' +
'<div class="bottom">' +
'<div class="wait wait-medium"></div>' +
'<a href="#" class="finish save">' + _e("Save") + '</a>' +
'<a href="#" class="finish cancel">' + _e("Cancel") + '</a>' +
'</div>';
// Create the popup
if(aff == 'owner')
createPopup('mucadmin', html_full);
if(aff == 'admin')
createPopup('mucadmin', html_partial);
// Associate the events
launchMucAdmin();
// We get the affiliated user's privileges
if(aff == 'owner') {
queryMucAdmin(xid, 'member');
queryMucAdmin(xid, 'owner');
queryMucAdmin(xid, 'admin');
queryMucAdmin(xid, 'outcast');
// We query the room to edit
dataForm(xid, 'muc', '', '', 'mucadmin');
} else if(aff == 'admin') {
queryMucAdmin(xid, 'member');
queryMucAdmin(xid, 'outcast');
}
}
// Closes the MUC admin popup
function closeMucAdmin() {
// Destroy the popup
destroyPopup('mucadmin');
return false;
}
// Removes a MUC admin input
function removeInputMucAdmin(element) {
var path = $(element).parent();
// We first hide the container of the input
path.hide();
// Then, we add a special class to the input
path.find('input').addClass('aut-dustbin');
return false;
}
// Adds a MUC admin input
function addInputMucAdmin(xid, affiliation) {
var hash = hex_md5(xid + affiliation);
// Add the HTML code
$('#mucadmin .aut-' + affiliation + ' .aut-add').after(
'<div class="one-aut ' + hash + '">' +
'<input id="aut-' + affiliation + '" name="' + affiliation + '" type="text" class="mucadmin-i" value="' + xid + '" />' +
'<a href="#" class="aut-remove">[-]</a>' +
'</div>'
);
// Click event
$('#mucadmin .' + hash + ' .aut-remove').click(function() {
return removeInputMucAdmin(this);
});
// Focus on the input we added
if(!xid)
$(document).oneTime(10, function() {
$('#mucadmin .' + hash + ' input').focus();
});
return false;
}
// Handles the MUC admin form
function handleMucAdminAuth(iq) {
// We got the authorizations results
$(iq.getQuery()).find('item').each(function() {
// We parse the received xml
var xid = $(this).attr('jid');
var affiliation = $(this).attr('affiliation');
// We create one input for one XID
addInputMucAdmin(xid, affiliation);
});
// Hide the wait icon
$('#mucadmin .wait').hide();
logThis('MUC admin items received: ' + fullXID(getStanzaFrom(iq)));
}
// Queries the MUC admin form
function queryMucAdmin(xid, type) {
// Show the wait icon
$('#mucadmin .wait').show();
// New IQ
var iq = new JSJaCIQ();
iq.setTo(xid);
iq.setType('get');
var iqQuery = iq.setQuery(NS_MUC_ADMIN);
iqQuery.appendChild(iq.buildNode('item', {'affiliation': type, 'xmlns': NS_MUC_ADMIN}));
con.send(iq, handleMucAdminAuth);
}
// Sends the new chat-room topic
function sendMucAdminTopic(xid) {
// We get the new topic
var topic = $('.mucadmin-topic textarea').val();
// We send the new topic if not blank
if(topic) {
var m = new JSJaCMessage();
m.setTo(xid);
m.setType('groupchat');
m.setSubject(topic);
con.send(m);
logThis('MUC admin topic sent: ' + topic, 3);
}
}
// Sends the MUC admin auth form
function sendMucAdminAuth(xid) {
// We define the values array
var types = new Array('member', 'owner', 'admin', 'outcast');
for(i in types) {
// We get the current type
var tType = types[i];
// We loop for all the elements
$('.mucadmin-aut .aut-' + tType + ' input').each(function() {
// We set the iq headers
var iq = new JSJaCIQ();
iq.setTo(xid);
iq.setType('set');
var iqQuery = iq.setQuery(NS_MUC_ADMIN);
// We get the needed values
var value = $(this).val();
// If there's a value
if(value)
var item = iqQuery.appendChild(iq.buildNode('item', {'jid': value, 'xmlns': NS_MUC_ADMIN}));
// It the user had removed the XID
if($(this).hasClass('aut-dustbin') && value)
item.setAttribute('affiliation', 'none');
// If the value is not blank and okay
else if(value)
item.setAttribute('affiliation', tType);
// We send the iq !
con.send(iq, handleErrorReply);
});
}
logThis('MUC admin authorizations form sent: ' + xid, 3);
}
// Checks if the MUC room was destroyed
function handleDestroyMucAdminIQ(iq) {
if(!handleErrorReply(iq)) {
// We close the groupchat
var room = fullXID(getStanzaFrom(iq));
var hash = hex_md5(room);
quitThisChat(room, hash, 'groupchat');
// We close the muc admin popup
closeMucAdmin();
// We tell the user that all is okay
openThisInfo(5);
// We remove the user's favorite
if(existDB('favorites', room))
removeThisFavorite(room, explodeThis('@', room, 0));
logThis('MUC admin destroyed: ' + room, 3);
}
// We hide the wait icon
$('#mucadmin .wait').hide();
}
// Destroys a MUC room
function destroyMucAdminIQ(xid) {
// We ask the server to delete the room
var iq = new JSJaCIQ();
iq.setTo(xid);
iq.setType('set');
var iqQuery = iq.setQuery(NS_MUC_OWNER);
iqQuery.appendChild(iq.buildNode('destroy', {'xmlns': NS_MUC_OWNER}));
con.send(iq, handleDestroyMucAdminIQ);
logThis('MUC admin destroy sent: ' + xid, 3);
return false;
}
// Performs the MUC room destroy functions
function destroyMucAdmin() {
// We get the XID of the current room
var xid = $('#mucadmin .mucadmin-head-jid').text();
// We show the wait icon
$('#mucadmin .wait').show();
// We send the iq
destroyMucAdminIQ(xid);
}
// Sends all the MUC admin stuffs
function sendMucAdmin() {
// We get the XID of the current room
var xid = $('#mucadmin .mucadmin-head-jid').text();
// We change the room topic
sendMucAdminTopic(xid);
// We send the needed queries
sendDataForm('x', 'submit', 'submit', $('#mucadmin .mucadmin-results').attr('data-session'), xid, '', '', 'mucadmin');
sendMucAdminAuth(xid);
}
// Saves the MUC admin elements
function saveMucAdmin() {
// We send the new options
sendMucAdmin();
// And we quit the popup
return closeMucAdmin();
}
// Plugin launcher
function launchMucAdmin() {
// Click events
$('#mucadmin .bottom .finish').click(function() {
if($(this).is('.cancel'))
return closeMucAdmin();
if($(this).is('.save'))
return saveMucAdmin();
});
}

View file

@ -0,0 +1,259 @@
/*
Jappix - An open social platform
These are the music JS scripts for Jappix
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 25/04/11
*/
// Opens the music bubble
function openMusic() {
var path = '.music-content';
// Show the music bubble
showBubble(path);
$(document).oneTime(10, function() {
$(path + ' input').focus();
});
return false;
}
// Parses the music search XML
function parseMusic(xml, type) {
var path = '.music-content ';
var content = path + '.list';
var path_type = content + ' .' + type;
// Create the result container
if(!exists(path_type)) {
var code = '<div class="' + type + '"></div>';
if(type == 'local')
$(content).prepend(code);
else
$(content).append(code);
}
// Fill the results
$(xml).find('track').each(function() {
// Parse the XML
var id = $(this).find('id').text();
var title = $(this).find('name').text();
var artist = $(this).find('artist').text();
var source = $(this).find('source').text();
var duration = $(this).find('duration').text();
var uri = $(this).find('url').text();
var mime = $(this).find('type').text();
// No ID?
if(!id)
id = hex_md5(uri);
// No MIME?
if(!mime)
mime = 'audio/ogg';
// Local URL?
if(type == 'local')
uri = generateURL(uri);
// Append the HTML code
$(path_type).append('<a href="#" class="song" data-id="' + id + '">' + title + '</a>');
// Current playing song?
var current_song = $(path_type + ' a[data-id=' + id + ']');
if(exists('.music-audio[data-id=' + id + ']'))
current_song.addClass('playing');
// Click event
current_song.click(function() {
return addMusic(id, title, artist, source, duration, uri, mime, type);
});
});
// The search is finished
if(exists(content + ' .jamendo') && exists(content + ' .local')) {
// Get the result values
var jamendo = $(content + ' .jamendo').text();
var local = $(content + ' .local').text();
// Enable the input
$(path + 'input').val('').removeAttr('disabled');
// No result
if(!jamendo && !local)
$(path + '.no-results').show();
// We must put a separator between the categories
if(jamendo && local)
$(content + ' .local').addClass('special');
}
}
// Sends the music search requests
function searchMusic() {
var path = '.music-content ';
// We get the input string
var string = $(path + 'input').val();
// We lock the search input
$(path + 'input').attr('disabled', true);
// We reset the results
$(path + '.list div').remove();
$(path + '.no-results').hide();
// Get the Jamendo results
$.get('./php/music-search.php', {searchquery: string, location: 'jamendo'}, function(data) {
parseMusic(data, 'jamendo');
});
// Get the local results
$.get('./php/music-search.php', {searchquery: string, location: JAPPIX_LOCATION}, function(data) {
parseMusic(data, 'local');
});
}
// Performs an action on the music player
function actionMusic(action) {
try {
// Initialize
var playThis = document.getElementById('top-content').getElementsByTagName('audio')[0];
// Nothing to play, exit
if(!playThis)
return false;
var stopButton = $('#top-content a.stop');
// User play a song
if(action == 'play') {
stopButton.show();
playThis.load();
playThis.play();
playThis.addEventListener('ended', function() {
actionMusic('stop');
}, true);
logThis('Music is now playing.');
}
// User stop the song or the song came to its end
else if(action == 'stop') {
stopButton.hide();
playThis.pause();
$('#top-content .music').removeClass('actived');
$('.music-content .list a').removeClass('playing');
$('.music-audio').remove();
publishMusic();
logThis('Music is now stopped.');
}
}
catch(e) {}
finally {
return false;
}
}
// Publishes the current title over PEP
function publishMusic(title, artist, source, duration, uri) {
// We share the tune on PEP if enabled
if(enabledPEP()) {
/* REF: http://xmpp.org/extensions/xep-0118.html */
var iq = new JSJaCIQ();
iq.setType('set');
// Create the main PubSub nodes
var pubsub = iq.appendNode('pubsub', {'xmlns': NS_PUBSUB});
var publish = pubsub.appendChild(iq.buildNode('publish', {'node': NS_TUNE, 'xmlns': NS_PUBSUB}));
var item = publish.appendChild(iq.buildNode('item', {'xmlns': NS_PUBSUB}));
var tune = item.appendChild(iq.buildNode('tune', {'xmlns': NS_TUNE}));
// Enough data?
if(title || artist || source || uri) {
// Data array
var nodes = new Array(
'title',
'artist',
'source',
'length',
'uri'
);
var values = new Array(
title,
artist,
source,
length,
uri
);
// Create the children nodes
for(i in nodes) {
if(values[i])
tune.appendChild(iq.buildNode(nodes[i], {'xmlns': NS_TUNE}, values[i]));
}
}
con.send(iq);
logThis('New tune sent: ' + title, 3);
}
}
// Adds a music title to the results
function addMusic(id, title, artist, source, duration, uri, mime, type) {
var path = '.music-content ';
// We remove & create a new audio tag
$('.music-audio').remove();
$(path + '.player').prepend('<audio class="music-audio" type="' + mime + '" data-id="' + id + '" />');
// We apply the new source to the player
if(type == 'jamendo')
$('.music-audio').attr('src', 'http://api.jamendo.com/get2/stream/track/redirect/?id=' + id + '&streamencoding=ogg2');
else
$('.music-audio').attr('src', uri);
// We play the target sound
actionMusic('play');
// We set the actived class
$('#top-content .music').addClass('actived');
// We set a current played track indicator
$(path + '.list a').removeClass('playing');
$(path + 'a[data-id=' + id + ']').addClass('playing');
// We publish what we listen
publishMusic(title, artist, source, duration, uri);
return false;
}
// Plugin launcher
function launchMusic() {
// When music search string submitted
$('.music-content input').keyup(function(e) {
// Enter : send
if(e.keyCode == 13 && $(this).val())
searchMusic();
// Escape : quit
if(e.keyCode == 27)
closeBubbles();
});
}

View file

@ -0,0 +1,131 @@
/*
Jappix - An open social platform
These are the buddy name related JS scripts for Jappix
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 29/04/11
*/
// Gets an user name for buddy add tool
function getAddUserName(xid) {
var iq = new JSJaCIQ();
iq.setType('get');
iq.setTo(xid);
iq.appendNode('vCard', {'xmlns': NS_VCARD});
con.send(iq, handleAddUserName);
}
// Handles an user name for buddy add tool
function handleAddUserName(iq) {
// Was it an obsolete request?
if(!exists('.add-contact-name-get[data-for=' + escape(bareXID(getStanzaFrom(iq))) + ']'))
return false;
// Reset the waiting item
$('.add-contact-name-get').hide().removeAttr('data-for');
// Get the names
if(iq.getType() == 'result') {
var full_name = generateBuddyName(iq)[0];
if(full_name)
$('.add-contact-name').val(full_name);
}
return false;
}
// Generates the good buddy name from a vCard IQ reply
function generateBuddyName(iq) {
// Get the IQ content
var xml = $(iq.getNode()).find('vCard');
// Get the full name & the nickname
var pFull = xml.find('FN:first').text();
var pNick = xml.find('NICKNAME:first').text();
// No full name?
if(!pFull) {
// Get the given name
var pN = xml.find('N:first');
var pGiven = pN.find('GIVEN:first').text();
if(pGiven) {
pFull = pGiven;
// Get the family name (optional)
var pFamily = pN.find('FAMILY:first').text();
if(pFamily)
pFull += ' ' + pFamily;
}
}
return [pFull, pNick];
}
// Returns the given XID buddy name
function getBuddyName(xid) {
// Initialize
var cname, bname;
// Cut the XID resource
xid = bareXID(xid);
// This is me?
if(isAnonymous() && !xid)
bname = _e("You");
else if(xid == getXID())
bname = getName();
// Not me!
else {
cname = $('#buddy-list .buddy[data-xid=' + escape(xid) + ']:first .buddy-name').html();
// If the complete name exists
if(cname)
bname = cname.revertHtmlEnc();
// Else, we just get the nickname of the buddy
else
bname = getXIDNick(xid);
}
return bname;
}
// Gets the nickname of the user
function getNick() {
// Try to read the user nickname
var nick = getDB('profile', 'nick');
// No nick?
if(!nick)
nick = con.username;
return nick;
}
// Gets the full name of the user
function getName() {
// Try to read the user name
var name = getDB('profile', 'name');
// No name? Use the nickname instead!
if(!name)
name = getNick();
return name;
}
// Gets the MUC nickname of the user
function getMUCNick(id) {
return unescape($('#' + id).attr('data-nick'));
}

View file

@ -0,0 +1,422 @@
/*
Jappix - An open social platform
These are the notification JS scripts for Jappix
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 27/08/11
*/
// Resets the notifications alert if no one remaining
function closeEmptyNotifications() {
if(!$('.one-notification').size())
closeBubbles();
}
// Checks if there are pending notifications
function checkNotifications() {
// Define the selectors
var notif = '#top-content .notifications';
var nothing = '.notifications-content .nothing';
var empty = '.notifications-content .empty';
// Get the notifications number
var number = $('.one-notification').size();
// Remove the red notify bubble
$(notif + ' .notify').remove();
// Any notification?
if(number) {
$(notif).prepend('<div class="notify one-counter" data-counter="' + number + '">' + number + '</div>');
$(nothing).hide();
$(empty).show();
}
// No notification!
else {
$(empty).hide();
$(nothing).show();
// Purge the social inbox node
purgeNotifications();
}
// Update the page title
updateTitle();
}
// Creates a new notification
function newNotification(type, from, data, body, id, inverse) {
if(!type || !from)
return;
// Generate an ID hash
if(!id)
var id = hex_md5(type + from);
// Generate the text to be displayed
var text, action, code;
var yes_path = 'href="#"';
// User things
from = bareXID(from);
var hash = hex_md5(from);
switch(type) {
case 'subscribe':
// Get the name to display
var display_name = data[1];
if(!display_name)
display_name = data[0];
text = '<b>' + display_name.htmlEnc() + '</b> ' + _e("would like to add you as a friend.") + ' ' + _e("Do you accept?");
break;
case 'invite_room':
text = '<b>' + getBuddyName(from).htmlEnc() + '</b> ' + _e("would like you to join this chatroom:") + ' <em>' + data[0].htmlEnc() + '</em> ' + _e("Do you accept?");
break;
case 'request':
text = '<b>' + from.htmlEnc() + '</b> ' + _e("would like to get authorization.") + ' ' + _e("Do you accept?");
break;
case 'send':
yes_path = 'href="' + encodeQuotes(data[1]) + '" target="_blank"';
text = '<b>' + getBuddyName(from).htmlEnc() + '</b> ' + printf(_e("would like to send you a file: “%s”.").htmlEnc(), '<em>' + truncate(body, 25).htmlEnc() + '</em>') + ' ' + _e("Do you accept?");
break;
case 'send_pending':
text = '<b>' + getBuddyName(from).htmlEnc() + '</b> ' + printf(_e("has received a file exchange request: “%s”.").htmlEnc(), '<em>' + truncate(body, 25).htmlEnc() + '</em>');
break;
case 'send_accept':
text = '<b>' + getBuddyName(from).htmlEnc() + '</b> ' + printf(_e("has accepted to received your file: “%s”.").htmlEnc(), '<em>' + truncate(body, 25).htmlEnc() + '</em>');
break;
case 'send_reject':
text = '<b>' + getBuddyName(from).htmlEnc() + '</b> ' + printf(_e("has rejected to receive your file: “%s”.").htmlEnc(), '<em>' + truncate(body, 25).htmlEnc() + '</em>');
break;
case 'send_fail':
text = '<b>' + getBuddyName(from).htmlEnc() + '</b> ' + printf(_e("could not receive your file: “%s”.").htmlEnc(), '<em>' + truncate(body, 25).htmlEnc() + '</em>');
break;
case 'rosterx':
text = printf(_e("Do you want to see the friends %s suggests you?").htmlEnc(), '<b>' + getBuddyName(from).htmlEnc() + '</b>');
break;
case 'comment':
text = '<b>' + data[0].htmlEnc() + '</b> ' + printf(_e("commented an item you follow: “%s”.").htmlEnc(), '<em>' + truncate(body, 25).htmlEnc() + '</em>');
break;
case 'like':
text = '<b>' + data[0].htmlEnc() + '</b> ' + printf(_e("liked your post: “%s”.").htmlEnc(), '<em>' + truncate(body, 25).htmlEnc() + '</em>');
break;
case 'quote':
text = '<b>' + data[0].htmlEnc() + '</b> ' + printf(_e("quoted you somewhere: “%s”.").htmlEnc(), '<em>' + truncate(body, 25).htmlEnc() + '</em>');
break;
case 'wall':
text = '<b>' + data[0].htmlEnc() + '</b> ' + printf(_e("published on your wall: “%s”.").htmlEnc(), '<em>' + truncate(body, 25).htmlEnc() + '</em>');
break;
case 'photo':
text = '<b>' + data[0].htmlEnc() + '</b> ' + printf(_e("tagged you in a photo (%s).").htmlEnc(), '<em>' + truncate(body, 25).htmlEnc() + '</em>');
break;
case 'video':
text = '<b>' + data[0].htmlEnc() + '</b> ' + printf(_e("tagged you in a video (%s).").htmlEnc(), '<em>' + truncate(body, 25).htmlEnc() + '</em>');
break;
default:
break;
}
// No text?
if(!text)
return;
// Action links?
if((type == 'send_pending') || (type == 'send_accept') || (type == 'send_reject') || (type == 'send_fail') || (type == 'comment') || (type == 'like') || (type == 'quote') || (type == 'wall') || (type == 'photo') || (type == 'video')) {
action = '<a href="#" class="no">' + _e("Hide") + '</a>';
// Any parent link?
if((type == 'comment') && data[2])
action = '<a href="#" class="yes">' + _e("Show") + '</a>' + action;
}
else
action = '<a ' + yes_path + ' class="yes">' + _e("Yes") + '</a><a href="#" class="no">' + _e("No") + '</a>';
if(text) {
// We display the notification
if(!exists('.notifications-content .' + id)) {
// We create the html markup depending of the notification type
code = '<div class="one-notification ' + id + ' ' + hash + '" title="' + encodeQuotes(body) + '" data-type="' + encodeQuotes(type) + '">' +
'<div class="avatar-container">' +
'<img class="avatar" src="' + './img/others/default-avatar.png' + '" alt="" />' +
'</div>' +
'<p class="notification-text">' + text + '</p>' +
'<p class="notification-actions">' +
'<span class="talk-images" />' +
action +
'</p>' +
'</div>';
// Add the HTML code
if(inverse)
$('.notifications-content .nothing').before(code);
else
$('.notifications-content .empty').after(code);
// Play a sound to alert the user
soundPlay(2);
// The yes click function
$('.' + id + ' a.yes').click(function() {
actionNotification(type, data, 'yes', id);
if(($(this).attr('href') == '#') && ($(this).attr('target') != '_blank'))
return false;
});
// The no click function
$('.' + id + ' a.no').click(function() {
return actionNotification(type, data, 'no', id);
});
// Get the user avatar
getAvatar(from, 'cache', 'true', 'forget');
}
}
// We tell the user he has a new pending notification
checkNotifications();
logThis('New notification: ' + from, 3);
}
// Performs an action on a given notification
function actionNotification(type, data, value, id) {
// We launch a function depending of the type
if((type == 'subscribe') && (value == 'yes'))
acceptSubscribe(data[0], data[1]);
else if((type == 'subscribe') && (value == 'no'))
sendSubscribe(data[0], 'unsubscribed');
else if((type == 'invite_room') && (value == 'yes'))
checkChatCreate(data[0], 'groupchat');
else if(type == 'request')
requestReply(value, data[0]);
if((type == 'send') && (value == 'yes'))
replyOOB(data[0], data[3], 'accept', data[2], data[4]);
else if((type == 'send') && (value == 'no'))
replyOOB(data[0], data[3], 'reject', data[2], data[4]);
else if((type == 'rosterx') && (value == 'yes'))
openRosterX(data[0]);
else if((type == 'comment') || (type == 'like') || (type == 'quote') || (type == 'wall') || (type == 'photo') || (type == 'video')) {
if(value == 'yes') {
// Get the microblog item
fromInfosMicroblog(data[2]);
// Append the marker
$('#channel .top.individual').append('<input type="hidden" name="comments" value="' + encodeQuotes(data[1]) + '" />');
}
removeNotification(data[3]);
}
// We remove the notification
$('.notifications-content .' + id).remove();
// We check if there's any other pending notification
closeEmptyNotifications();
checkNotifications();
return false;
}
// Clear the social notifications
function clearNotifications() {
// Remove notifications
$('.one-notification').remove();
// Refresh
closeEmptyNotifications();
checkNotifications();
return false;
}
// Gets the pending social notifications
function getNotifications() {
var iq = new JSJaCIQ();
iq.setType('get');
var pubsub = iq.appendNode('pubsub', {'xmlns': NS_PUBSUB});
pubsub.appendChild(iq.buildNode('items', {'node': NS_URN_INBOX, 'xmlns': NS_PUBSUB}));
con.send(iq, handleNotifications);
logThis('Getting social notifications...');
}
// Handles the social notifications
function handleNotifications(iq) {
// Any error?
if((iq.getType() == 'error') && $(iq.getNode()).find('item-not-found').size()) {
// The node may not exist, create it!
setupMicroblog('', NS_URN_INBOX, '1', '1000000', 'whitelist', 'open', true);
logThis('Error while getting social notifications, trying to reconfigure the Pubsub node!', 2);
}
// Selector
var items = $(iq.getNode()).find('item');
// Should we inverse?
var inverse = true;
if(items.size() == 1)
inverse = false;
// Parse notifications
items.each(function() {
// Parse the current item
var current_item = $(this).attr('id');
var current_type = $(this).find('link[rel=via]:first').attr('title');
var current_href = $(this).find('link[rel=via]:first').attr('href');
var current_parent_href = $(this).find('link[rel=related]:first').attr('href');
var current_xid = explodeThis(':', $(this).find('source author uri').text(), 1);
var current_name = $(this).find('source author name').text();
var current_text = $(this).find('content[type=text]:first').text();
var current_bname = getBuddyName(current_xid);
var current_id = hex_md5(current_type + current_xid + current_href + current_text);
// Choose the good name!
if(!current_name || (current_bname != getXIDNick(current_xid)))
current_name = current_bname;
// Create it!
newNotification(current_type, current_xid, [current_name, current_href, current_parent_href, current_item], current_text, current_id, inverse);
});
logThis(items.size() + ' social notification(s) got!', 3);
}
// Sends a social notification
function sendNotification(xid, type, href, text, parent) {
// Notification ID
var id = hex_md5(xid + text + getTimeStamp());
// IQ
var iq = new JSJaCIQ();
iq.setType('set');
iq.setTo(xid);
// ATOM content
var pubsub = iq.appendNode('pubsub', {'xmlns': NS_PUBSUB});
var publish = pubsub.appendChild(iq.buildNode('publish', {'node': NS_URN_INBOX, 'xmlns': NS_PUBSUB}));
var item = publish.appendChild(iq.buildNode('item', {'id': id, 'xmlns': NS_PUBSUB}));
var entry = item.appendChild(iq.buildNode('entry', {'xmlns': NS_ATOM}));
// Notification author (us)
var Source = entry.appendChild(iq.buildNode('source', {'xmlns': NS_ATOM}));
var author = Source.appendChild(iq.buildNode('author', {'xmlns': NS_ATOM}));
author.appendChild(iq.buildNode('name', {'xmlns': NS_ATOM}, getName()));
author.appendChild(iq.buildNode('uri', {'xmlns': NS_ATOM}, 'xmpp:' + getXID()));
// Notification content
entry.appendChild(iq.buildNode('published', {'xmlns': NS_ATOM}, getXMPPTime('utc')));
entry.appendChild(iq.buildNode('content', {'type': 'text', 'xmlns': NS_ATOM}, text));
entry.appendChild(iq.buildNode('link', {'rel': 'via', 'title': type, 'href': href, 'xmlns': NS_ATOM}));
// Any parent item?
if(parent && parent[0] && parent[1] && parent[2]) {
// Generate the parent XMPP URI
var parent_href = 'xmpp:' + parent[0] + '?;node=' + encodeURIComponent(parent[1]) + ';item=' + encodeURIComponent(parent[2]);
entry.appendChild(iq.buildNode('link', {'rel': 'related', 'href': parent_href, 'xmlns': NS_ATOM}));
}
con.send(iq);
logThis('Sending a social notification to ' + xid + ' (type: ' + type + ')...');
}
// Removes a social notification
function removeNotification(id) {
var iq = new JSJaCIQ();
iq.setType('set');
var pubsub = iq.appendNode('pubsub', {'xmlns': NS_PUBSUB});
var retract = pubsub.appendChild(iq.buildNode('retract', {'node': NS_URN_INBOX, 'xmlns': NS_PUBSUB}));
retract.appendChild(iq.buildNode('item', {'id': id, 'xmlns': NS_PUBSUB}));
con.send(iq);
}
// Purge the social notifications
function purgeNotifications() {
var iq = new JSJaCIQ();
iq.setType('set');
var pubsub = iq.appendNode('pubsub', {'xmlns': NS_PUBSUB_OWNER});
pubsub.appendChild(iq.buildNode('purge', {'node': NS_URN_INBOX, 'xmlns': NS_PUBSUB_OWNER}));
con.send(iq);
return false;
}
// Adapt the notifications bubble max-height
function adaptNotifications() {
// Process the new height
var max_height = $('#right-content').height() - 22;
// New height too small
if(max_height < 250)
max_height = 250;
// Apply the new height
$('.notifications-content .tools-content-subitem').css('max-height', max_height);
}
// Plugin launcher
function launchNotifications() {
// Adapt the notifications height
adaptNotifications();
}
// Window resize event handler
$(window).resize(adaptNotifications);

184
jappixmini/jappix/js/oob.js Normal file
View file

@ -0,0 +1,184 @@
/*
Jappix - An open social platform
These are the Out of Band Data JS scripts for Jappix
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 27/08/11
*/
// Sends an OOB request to someone
function sendOOB(to, type, url, desc) {
// IQ stanza?
if(type == 'iq') {
// Get some values
var id = hex_md5(genID() + to + url + desc);
to = getHighestResource(to);
// IQs cannot be sent to offline users
if(!to)
return;
// Register the ID
setDB('send/url', id, url);
setDB('send/desc', id, desc);
var aIQ = new JSJaCIQ();
aIQ.setTo(fullXID(to));
aIQ.setType('set');
aIQ.setID(id);
// Append the query content
var aQuery = aIQ.setQuery(NS_IQOOB);
aQuery.appendChild(aIQ.buildNode('url', {'xmlns': NS_IQOOB}, url));
aQuery.appendChild(aIQ.buildNode('desc', {'xmlns': NS_IQOOB}, desc));
con.send(aIQ);
}
// Message stanza?
else {
var aMsg = new JSJaCMessage();
aMsg.setTo(bareXID(to));
// Append the content
aMsg.setBody(desc);
var aX = aMsg.appendNode('x', {'xmlns': NS_XOOB});
aX.appendChild(aMsg.buildNode('url', {'xmlns': NS_XOOB}, url));
con.send(aMsg);
}
logThis('Sent OOB request to: ' + to + ' (' + desc + ')');
}
// Handles an OOB request
function handleOOB(from, id, type, node) {
var xid = url = desc = '';
// IQ stanza?
if(type == 'iq') {
xid = fullXID(from);
url = $(node).find('url').text();
desc = $(node).find('desc').text();
}
// Message stanza?
else {
xid = bareXID(from);
url = $(node).find('url').text();
desc = $(node).find('body').text();
}
// No desc?
if(!desc)
desc = url;
// Open a new notification
if(type && xid && url && desc)
newNotification('send', xid, [xid, url, type, id, node], desc, hex_md5(xid + url + desc + id));
}
// Replies to an OOB request
function replyOOB(to, id, choice, type, node) {
// Not IQ type?
if(type != 'iq')
return;
// New IQ
var aIQ = new JSJaCIQ();
aIQ.setTo(to);
aIQ.setID(id);
// OOB request accepted
if(choice == 'accept') {
aIQ.setType('result');
logThis('Accepted file request from: ' + to, 3);
}
// OOB request rejected
else {
aIQ.setType('error');
// Append stanza content
for(var i = 0; i < node.childNodes.length; i++)
aIQ.getNode().appendChild(node.childNodes.item(i).cloneNode(true));
// Append error content
var aError = aIQ.appendNode('error', {'xmlns': NS_CLIENT, 'code': '406', 'type': 'modify'});
aError.appendChild(aIQ.buildNode('not-acceptable', {'xmlns': NS_STANZAS}));
logThis('Rejected file request from: ' + to, 3);
}
con.send(aIQ);
}
// Wait event for OOB upload
function waitUploadOOB() {
// Append the wait icon
$('#page-engine .chat-tools-file:not(.mini) .tooltip-subitem *').hide();
$('#page-engine .chat-tools-file:not(.mini) .tooltip-subitem').append('<div class="wait wait-medium"></div>');
// Lock the bubble
$('#page-engine .chat-tools-file:not(.mini)').addClass('mini');
}
// Success event for OOB upload
function handleUploadOOB(responseXML) {
// Data selector
var dData = $(responseXML).find('jappix');
// Get the values
var fID = dData.find('id').text();
var fURL = dData.find('url').text();
var fDesc = dData.find('desc').text();
// Get the OOB values
var oob_has;
// No ID provided?
if(!fID)
oob_has = ':has(.wait)';
else
oob_has = ':has(#oob-upload input[value=' + fID + '])';
var xid = $('#page-engine .page-engine-chan' + oob_has).attr('data-xid');
var oob_type = $('#page-engine .chat-tools-file' + oob_has).attr('data-oob');
// Reset the file send tool
$('#page-engine .chat-tools-file' + oob_has).removeClass('mini');
$('#page-engine .bubble-file' + oob_has).remove();
// Not available?
if($('#page-engine .chat-tools-file' + oob_has).is(':hidden') && (oob_type == 'iq')) {
openThisError(4);
// Remove the file we sent
if(fURL)
$.get(fURL + '&action=remove');
}
// Everything okay?
else if(fURL && fDesc && !dData.find('error').size()) {
// Send the OOB request
sendOOB(xid, oob_type, fURL, fDesc);
// Notify the sender
newNotification('send_pending', xid, [xid, fURL, oob_type, '', ''], fDesc, hex_md5(fURL + fDesc + fID));
logThis('File request sent.', 3);
}
// Upload error?
else {
openThisError(4);
logThis('Error while sending the file: ' + dData.find('error').text(), 1);
}
}

View file

@ -0,0 +1,643 @@
/*
Jappix - An open social platform
These are the options JS scripts for Jappix
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 17/07/11
*/
// Opens the options popup
function optionsOpen() {
// Popup HTML content
var html =
'<div class="top">' + _e("Edit options") + '</div>' +
'<div class="tab">' +
'<a href="#" class="tab-active" data-key="1">' + _e("General") + '</a>' +
'<a href="#" class="pubsub-hidable" data-key="2">' + _e("Channel") + '</a>' +
'<a href="#" data-key="3">' + _e("Account") + '</a>' +
'</div>' +
'<div class="content">' +
'<div id="conf1" class="lap-active one-lap forms">' +
'<fieldset class="privacy">' +
'<legend>' + _e("Privacy") + '</legend>' +
'<label for="geolocation" class="pep-hidable">' + _e("Geolocation") + '</label>' +
'<input id="geolocation" type="checkbox" class="pep-hidable" />' +
'<label for="archiving" class="archives-hidable pref">' + _e("Message archiving") + '</label>' +
'<input id="archiving" type="checkbox" class="archives-hidable pref" />' +
'</fieldset>' +
'<fieldset>' +
'<legend>' + _e("Application") + '</legend>' +
'<label for="sounds">' + _e("Sounds") + '</label>' +
'<input id="sounds" type="checkbox" />' +
'<label for="showall">' + _e("Show all friends") + '</label>' +
'<input id="showall" type="checkbox" />' +
'<label for="integratemedias">' + _e("Media integration") + '</label>' +
'<input id="integratemedias" type="checkbox" />' +
'<label class="xmpplinks-hidable">' + _e("XMPP links") + '</label>' +
'<a href="#" class="linked xmpp-links xmpplinks-hidable">' + _e("Open XMPP links with Jappix") + '</a>' +
'</fieldset>' +
'</div>' +
'<div id="conf2" class="one-lap forms">' +
'<fieldset>' +
'<legend>' + _e("Channel") + '</legend>' +
'<label>' + _e("Empty") + '</label>' +
'<a href="#" class="linked empty-channel">' + _e("Empty channel") + '</a>' +
'<label>' + _e("Persistent") + '</label>' +
'<input id="persistent" type="checkbox" />' +
'<label>' + _e("Maximum notices") + '</label>' +
'<select id="maxnotices">' +
'<option value="1">1</option>' +
'<option value="100">100</option>' +
'<option value="1000">1000</option>' +
'<option value="10000">10000</option>' +
'<option value="100000">100000</option>' +
'<option value="1000000">1000000</option>' +
'</select>' +
'</fieldset>' +
'<div class="sub-ask sub-ask-empty sub-ask-element">' +
'<div class="sub-ask-top">' +
'<div class="sub-ask-title">' + _e("Empty channel") + '</div>' +
'<a href="#" class="sub-ask-close">X</a>' +
'</div>' +
'<div class="sub-ask-content">' +
'<label>' + _e("Password") + '</label>' +
'<input type="password" class="purge-microblog check-empty" required="" />' +
'</div>' +
'<a href="#" class="sub-ask-bottom">' + _e("Empty") + ' &raquo;</a>' +
'</div>' +
'</div>' +
'<div id="conf3" class="one-lap forms">' +
'<fieldset>' +
'<legend>' + _e("Account") + '</legend>' +
'<label>' + _e("Password") + '</label>' +
'<a href="#" class="linked change-password">' + _e("Change password") + '</a>' +
'<label>' + _e("Delete") + '</label>' +
'<a href="#" class="linked delete-account">' + _e("Delete account") + '</a>' +
'</fieldset>' +
'<div class="sub-ask sub-ask-pass sub-ask-element">' +
'<div class="sub-ask-top">' +
'<div class="sub-ask-title">' + _e("Change password") + '</div>' +
'<a href="#" class="sub-ask-close">X</a>' +
'</div>' +
'<div class="sub-ask-content">' +
'<label>' + _e("Old") + '</label>' +
'<input type="password" class="password-change old" required="" />' +
'<label>' + _e("New (2 times)") + '</label>' +
'<input type="password" class="password-change new1" required="" />' +
'<input type="password" class="password-change new2" required="" />' +
'</div>' +
'<a href="#" class="sub-ask-bottom">' + _e("Continue") + ' &raquo;</a>' +
'</div>' +
'<div class="sub-ask sub-ask-delete sub-ask-element">' +
'<div class="sub-ask-top">' +
'<div class="sub-ask-title">' + _e("Delete account") + '</div>' +
'<a href="#" class="sub-ask-close">X</a>' +
'</div>' +
'<div class="sub-ask-content">' +
'<label>' + _e("Password") + '</label>' +
'<input type="password" class="delete-account check-password" required="" />' +
'</div>' +
'<a href="#" class="sub-ask-bottom">' + _e("Delete") + ' &raquo;</a>' +
'</div>' +
'</div>' +
'</div>' +
'<div class="bottom">' +
'<div class="wait wait-medium"></div>' +
'<a href="#" class="finish save">' + _e("Save") + '</a>' +
'<a href="#" class="finish cancel">' + _e("Cancel") + '</a>' +
'</div>';
// Create the popup
createPopup('options', html);
// Apply the features
applyFeatures('options');
// Associate the events
launchOptions();
return false;
}
// Closes the options popup
function closeOptions() {
// Destroy the popup
destroyPopup('options');
return false;
}
// Checks whether the options are loaded or not
function loadedOptions() {
if($('.options-hidable').is(':visible'))
return true;
return false;
}
// Switches between the options tabs
function switchOptions(id) {
$('#options .one-lap').hide();
$('#options #conf' + id).show();
$('#options .tab a').removeClass('tab-active');
$('#options .tab a[data-key=' + id + ']').addClass('tab-active');
return false;
}
// Manages the options wait item
function waitOptions(id) {
var sOptions = $('#options .content');
// Remove the current item class
sOptions.removeClass(id);
// Hide the waiting items if all was received
if(!sOptions.hasClass('microblog') && !sOptions.hasClass('archives')) {
$('#options .wait').hide();
$('#options .finish:first').removeClass('disabled');
}
}
// Sends the options to the XMPP server
function storeOptions() {
// Get the values
var sounds = getDB('options', 'sounds');
var geolocation = getDB('options', 'geolocation');
var showall = getDB('options', 'roster-showall');
var integratemedias = getDB('options', 'integratemedias');
var status = getDB('options', 'presence-status');
// Create an array to be looped
var oType = new Array('sounds', 'geolocation', 'roster-showall', 'integratemedias', 'presence-status');
var oContent = new Array(sounds, geolocation, showall, integratemedias, status);
// New IQ
var iq = new JSJaCIQ();
iq.setType('set');
var query = iq.setQuery(NS_PRIVATE);
var storage = query.appendChild(iq.buildNode('storage', {'xmlns': NS_OPTIONS}));
// Loop the array
for(i in oType)
storage.appendChild(iq.buildNode('option', {'type': oType[i], 'xmlns': NS_OPTIONS}, oContent[i]));
con.send(iq, handleStoreOptions);
logThis('Storing options...', 3);
}
// Handles the option storing
function handleStoreOptions(iq) {
if(!iq || (iq.getType() != 'result'))
logThis('Options not stored.', 2);
else
logThis('Options stored.', 3);
}
// Saves the user options
function saveOptions() {
// We apply the sounds
var sounds = '0';
if($('#sounds').filter(':checked').size())
sounds = '1';
setDB('options', 'sounds', sounds);
// We apply the geolocation
if($('#geolocation').filter(':checked').size()) {
setDB('options', 'geolocation', '1');
// We geolocate the user on the go
geolocate();
}
else {
setDB('options', 'geolocation', '0');
// We delete the geolocation informations
sendPosition();
removeDB('geolocation', 'now');
}
// We apply the roster show all
if($('#showall').filter(':checked').size()) {
setDB('options', 'roster-showall', '1');
showAllBuddies('options');
}
else {
setDB('options', 'roster-showall', '0');
showOnlineBuddies('options');
}
// We apply the media integration
var integratemedias = '0';
if($('#integratemedias').filter(':checked').size())
integratemedias = '1';
setDB('options', 'integratemedias', integratemedias);
// We apply the message archiving
if(enabledArchives('pref')) {
var aEnabled = false;
if($('#archiving').filter(':checked').size())
aEnabled = true;
configArchives(aEnabled);
}
// We apply the microblog configuration
var persist = '0';
var maximum = $('#maxnotices').val();
if($('#persistent').filter(':checked').size())
persist = '1';
if(enabledPEP() && enabledPubSub())
setupMicroblog('', NS_URN_MBLOG, persist, maximum, '', '', false);
// We send the options to the database
storeOptions();
// Close the options
closeOptions();
return false;
}
// Handles the password changing
function handlePwdChange(iq) {
// Remove the general wait item
removeGeneralWait();
// If no errors
if(!handleErrorReply(iq)) {
clearLastSession();
quit();
openThisInfo(1);
logThis('Password changed.', 3);
}
else
logThis('Password not changed.', 2);
}
// Sends the new account password
function sendNewPassword() {
/* REF: http://xmpp.org/extensions/xep-0077.html#usecases-changepw */
var password0 = $('#options .old').val();
var password1 = $('#options .new1').val();
var password2 = $('#options .new2').val();
if ((password1 == password2) && (password0 == getPassword())) {
// We show the waiting image
showGeneralWait();
// We send the IQ
var iq = new JSJaCIQ();
iq.setTo(getServer());
iq.setType('set');
var iqQuery = iq.setQuery(NS_REGISTER);
iqQuery.appendChild(iq.buildNode('username', {'xmlns': NS_REGISTER}, con.username));
iqQuery.appendChild(iq.buildNode('password', {'xmlns': NS_REGISTER}, password1));
con.send(iq, handlePwdChange);
logThis('Password change sent.', 3);
}
else {
$('.sub-ask-pass input').each(function() {
var select = $(this);
if(!select.val())
$(document).oneTime(10, function() {
select.addClass('please-complete').focus();
});
else
select.removeClass('please-complete');
});
if(password0 != getPassword())
$(document).oneTime(10, function() {
$('#options .old').addClass('please-complete').focus();
});
if(password1 != password2)
$(document).oneTime(10, function() {
$('#options .new1, #options .new2').addClass('please-complete').focus();
});
}
return false;
}
// Handles the account deletion request
function handleAccDeletion(iq) {
// Remove the general wait item
removeGeneralWait();
// If no errors
if(!handleErrorReply(iq)) {
clearLastSession();
destroyTalkPage();
openThisInfo(2);
logout();
logThis('Account deleted.', 3);
}
else
logThis('Account not deleted.', 2);
}
// Purge the user's microblog items
function purgeMyMicroblog() {
/* REF: http://xmpp.org/extensions/xep-0060.html#owner-purge */
var password = $('#options .check-empty').val();
if(password == getPassword()) {
// Send the IQ to remove the item (and get eventual error callback)
var iq = new JSJaCIQ();
iq.setType('set');
var pubsub = iq.appendNode('pubsub', {'xmlns': NS_PUBSUB_OWNER});
pubsub.appendChild(iq.buildNode('purge', {'node': NS_URN_MBLOG, 'xmlns': NS_PUBSUB_OWNER}));
con.send(iq, handleMicroblogPurge);
// Hide the tool
$('#options .sub-ask').hide();
logThis('Microblog purge sent.', 3);
}
else {
var selector = $('#options .check-empty');
if(password != getPassword())
$(document).oneTime(10, function() {
selector.addClass('please-complete').focus();
});
else
selector.removeClass('please-complete');
}
return false;
}
// Handles the microblog purge
function handleMicroblogPurge(iq) {
// If no errors
if(!handleErrorReply(iq)) {
// Remove the microblog items
$('.one-update.update_' + hex_md5(getXID())).remove();
logThis('Microblog purged.', 3);
}
else
logThis('Microblog not purged.', 2);
}
// Deletes the user's account
function deleteMyAccount() {
/* REF: http://xmpp.org/extensions/xep-0077.html#usecases-cancel */
var password = $('#options .check-password').val();
if(password == getPassword()) {
// We show the waiting image
showGeneralWait();
// We send the IQ
var iq = new JSJaCIQ();
iq.setType('set');
var iqQuery = iq.setQuery(NS_REGISTER);
iqQuery.appendChild(iq.buildNode('remove', {'xmlns': NS_REGISTER}));
con.send(iq, handleAccDeletion);
logThis('Delete account sent.', 3);
}
else {
var selector = $('#options .check-password');
if(password != getPassword())
$(document).oneTime(10, function() {
selector.addClass('please-complete').focus();
});
else
selector.removeClass('please-complete');
}
return false;
}
// Loads the user options
function loadOptions() {
// Process the good stuffs, depending of the server features
var enabled_archives_pref = enabledArchives('pref');
var enabled_pubsub = enabledPubSub();
var enabled_pep = enabledPEP();
var sWait = $('#options .content');
// Show the waiting items if necessary
if(enabled_archives_pref || (enabled_pep && enabled_pubsub)) {
$('#options .wait').show();
$('#options .finish:first').addClass('disabled');
}
// We get the archiving configuration
if(enabled_archives_pref) {
sWait.addClass('archives');
getConfigArchives();
}
// We get the microblog configuration
if(enabled_pubsub && enabled_pep) {
sWait.addClass('microblog');
getConfigMicroblog();
}
// We show the "privacy" form if something is visible into it
if(enabled_archives_pref || enabled_pep)
$('#options fieldset.privacy').show();
// We get the values of the forms for the sounds
if(getDB('options', 'sounds') == '0')
$('#sounds').attr('checked', false);
else
$('#sounds').attr('checked', true);
// We get the values of the forms for the geolocation
if(getDB('options', 'geolocation') == '1')
$('#geolocation').attr('checked', true);
else
$('#geolocation').attr('checked', false);
// We get the values of the forms for the roster show all
if(getDB('options', 'roster-showall') == '1')
$('#showall').attr('checked', true);
else
$('#showall').attr('checked', false);
// We get the values of the forms for the integratemedias
if(getDB('options', 'integratemedias') == '0')
$('#integratemedias').attr('checked', false);
else
$('#integratemedias').attr('checked', true);
}
// Plugin launcher
function launchOptions() {
// Click events
$('#options .tab a').click(function() {
// Yet active?
if($(this).hasClass('tab-active'))
return false;
// Switch to the good tab
var key = parseInt($(this).attr('data-key'));
return switchOptions(key);
});
$('#options .linked').click(function() {
$('#options .sub-ask').hide();
});
$('#options .xmpp-links').click(function() {
xmppLinksHandler();
return false;
});
$('#options .empty-channel').click(function() {
var selector = '#options .sub-ask-empty';
$(selector).show();
$(document).oneTime(10, function() {
$(selector + ' input').focus();
});
return false;
});
$('#options .change-password').click(function() {
var selector = '#options .sub-ask-pass';
$(selector).show();
$(document).oneTime(10, function() {
$(selector + ' input:first').focus();
});
return false;
});
$('#options .delete-account').click(function() {
var selector = '#options .sub-ask-delete';
$(selector).show();
$(document).oneTime(10, function() {
$(selector + ' input').focus();
});
return false;
});
$('#options .sub-ask-pass .sub-ask-bottom').click(function() {
return sendNewPassword();
});
$('#options .sub-ask-empty .sub-ask-bottom').click(function() {
return purgeMyMicroblog();
});
$('#options .sub-ask-delete .sub-ask-bottom').click(function() {
return deleteMyAccount();
});
$('#options .sub-ask-close').click(function() {
$('#options .sub-ask').hide();
return false;
});
$('#options .bottom .finish').click(function() {
if($(this).is('.save') && !$(this).hasClass('disabled'))
return saveOptions();
if($(this).is('.cancel'))
return closeOptions();
return false;
});
// The keyup events
$('#options .sub-ask input').keyup(function(e) {
if(e.keyCode == 13) {
// Microblog purge
if($(this).is('.purge-microblog'))
return purgeMyMicroblog();
// Password change
else if($(this).is('.password-change'))
return sendNewPassword();
// Account deletion
else if($(this).is('.delete-account'))
return deleteMyAccount();
}
});
// Load the options
loadOptions();
}

827
jappixmini/jappix/js/pep.js Normal file
View file

@ -0,0 +1,827 @@
/*
Jappix - An open social platform
These are the PEP JS scripts for Jappix
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 26/08/11
*/
// Stores the PEP items
function storePEP(xid, type, value1, value2, value3, value4) {
// Handle the correct values
if(!value1)
value1 = '';
if(!value2)
value2 = '';
if(!value3)
value3 = '';
if(!value4)
value4 = '';
// If one value
if(value1 || value2 || value3 || value4) {
// Define the XML variable
var xml = '<pep type="' + type + '">';
// Generate the correct XML
if(type == 'tune')
xml += '<artist>' + value1.htmlEnc() + '</artist><title>' + value2.htmlEnc() + '</title><album>' + value3.htmlEnc() + '</album><uri>' + value4.htmlEnc() + '</uri>';
else if(type == 'geoloc')
xml += '<lat>' + value1.htmlEnc() + '</lat><lon>' + value2.htmlEnc() + '</lon><human>' + value3.htmlEnc() + '</human>';
else
xml += '<value>' + value1.htmlEnc() + '</value><text>' + value2.htmlEnc() + '</text>';
// End the XML node
xml += '</pep>';
// Update the input with the new value
setDB('pep-' + type, xid, xml);
}
else
removeDB('pep-' + type, xid);
// Display the PEP event
displayPEP(xid, type);
}
// Displays a PEP item
function displayPEP(xid, type) {
// Read the target input for values
var value = $(XMLFromString(getDB('pep-' + type, xid)));
var dText;
var aLink = ''
// If the PEP element exists
if(type) {
// Get the user hash
var hash = hex_md5(xid);
// Initialize
var fText, fValue;
var dText = '';
// Parse the XML for mood and activity
if((type == 'mood') || (type == 'activity')) {
if(value) {
var pepValue = value.find('value').text();
var pepText = value.find('text').text();
// No value?
if(!pepValue)
pepValue = 'none';
// Apply the good values
if(type == 'mood')
fValue = moodIcon(pepValue);
else if(type == 'activity')
fValue = activityIcon(pepValue);
if(!pepText)
fText = _e("unknown");
else
fText = pepText;
}
else {
if(type == 'mood')
fValue = moodIcon('undefined');
else if(type == 'activity')
fValue = activityIcon('exercising');
fText = _e("unknown");
}
dText = fText;
fText = fText.htmlEnc();
}
else if(type == 'tune') {
fValue = 'tune-note';
if(value) {
// Parse the tune XML
var tArtist = value.find('artist').text();
var tTitle = value.find('title').text();
var tAlbum = value.find('album').text();
var tURI = value.find('uri').text();
var fArtist, fTitle, fAlbum, fURI;
// Apply the good values
if(!tArtist && !tAlbum && !tTitle) {
fText = _e("unknown");
dText = fText;
}
else {
// URI element
if(!tURI)
fURI = 'http://grooveshark.com/search?q=' + encodeURIComponent(tArtist + ' ' + tTitle + ' ' + tAlbum);
else
fURI = tURI;
// Artist element
if(!tArtist)
fArtist = _e("unknown");
else
fArtist = tArtist;
// Title element
if(!tTitle)
fTitle = _e("unknown");
else
fTitle = tTitle;
// Album element
if(!tAlbum)
fAlbum = _e("unknown");
else
fAlbum = tAlbum;
// Generate the link to the title
aLink = ' href="' + fURI + '" target="_blank"';
// Generate the text to be displayed
dText = fArtist + ' - ' + fTitle + ' (' + fAlbum + ')';
fText = '<a' + aLink + '>' + dText + '</a>';
}
}
else {
fText = _e("unknown");
dText = fText;
}
}
else if(type == 'geoloc') {
fValue = 'location-world';
if(value) {
// Parse the geoloc XML
var tLat = value.find('lat').text();
var tLon = value.find('lon').text();
var tHuman = value.find('human').text();
var tReal = tHuman;
// No human location?
if(!tHuman)
tHuman = _e("See his/her position on the globe");
// Generate the text to be displayed
if(tLat && tLon) {
aLink = ' href="http://maps.google.com/?q=' + encodeQuotes(tLat) + ',' + encodeQuotes(tLon) + '" target="_blank"';
fText = '<a' + aLink + '>' + tHuman.htmlEnc() + '</a>';
if(tReal)
dText = tReal;
else
dText = tLat + '; ' + tLon;
}
else {
fText = _e("unknown");
dText = fText;
}
}
else {
fText = _e("unknown");
dText = fText;
}
}
// Apply the text to the buddy infos
var this_buddy = '#buddy-list .buddy[data-xid=' + escape(xid) + ']';
if(exists(this_buddy))
$(this_buddy + ' .bi-' + type).replaceWith('<p class="bi-' + type + ' talk-images ' + fValue + '" title="' + encodeQuotes(dText) + '">' + fText + '</p>');
// Apply the text to the buddy chat
if(exists('#' + hash)) {
// Selector
var bc_pep = $('#' + hash + ' .bc-pep');
// We remove the old PEP item
bc_pep.find('a.bi-' + type).remove();
// If the new PEP item is not null, create a new one
if(fText != _e("unknown"))
bc_pep.prepend(
'<a' + aLink + ' class="bi-' + type + ' talk-images ' + fValue + '" title="' + encodeQuotes(dText) + '"></a>'
);
// Process the new status position
adaptChatPresence(hash);
}
// If this is the PEP values of the logged in user
if(xid == getXID()) {
// Change the icon/value of the target element
if((type == 'mood') || (type == 'activity')) {
// Change the input value
var dVal = '';
var dAttr = pepValue;
// Must apply default values?
if(pepValue == 'none') {
if(type == 'mood')
dAttr = 'happy';
else
dAttr = 'exercising';
}
// No text?
if(dText != _e("unknown"))
dVal = dText;
// Store this user event in our database
setDB(type + '-value', 1, dAttr);
setDB(type + '-text', 1, dVal);
// Apply this PEP event
$('#my-infos .f-' + type + ' a.picker').attr('data-value', dAttr);
$('#my-infos .f-' + type + ' input').val(dVal);
$('#my-infos .f-' + type + ' input').placeholder();
}
else if((type == 'tune') || (type == 'geoloc')) {
// Reset the values
$('#my-infos .f-others a.' + type).remove();
// Not empty?
if(dText != _e("unknown")) {
// Specific stuffs
var href, title, icon_class;
if(type == 'tune') {
href = fURI;
title = dText;
icon_class = 'tune-note';
}
else {
href = 'http://maps.google.com/?q=' + encodeQuotes(tLat) + ',' + encodeQuotes(tLon);
title = _e("Where are you?") + ' (' + dText + ')';
icon_class = 'location-world';
}
// Must create the container?
if(!exists('#my-infos .f-others'))
$('#my-infos .content').append('<div class="element f-others"></div>');
// Create the element
$('#my-infos .f-others').prepend(
'<a class="icon ' + type + '" href="' + encodeQuotes(href) + '" target="_blank" title="' + encodeQuotes(title) + '">' +
'<span class="talk-images ' + icon_class + '"></span>' +
'</a>'
);
}
// Empty?
else if(!exists('#my-infos .f-others a.icon'))
$('#my-infos .f-others').remove();
// Process the buddy-list height again
adaptRoster();
}
}
}
}
// Changes the mood icon
function moodIcon(value) {
// The main var
var icon;
// Switch the values
switch(value) {
case 'angry':
case 'cranky':
case 'hot':
case 'invincible':
case 'mean':
case 'restless':
case 'serious':
case 'strong':
icon = 'mood-one';
break;
case 'contemplative':
case 'happy':
case 'playful':
icon = 'mood-two';
break;
case 'aroused':
case 'envious':
case 'excited':
case 'interested':
case 'lucky':
case 'proud':
case 'relieved':
case 'satisfied':
case 'shy':
icon = 'mood-three';
break;
case 'calm':
case 'cautious':
case 'contented':
case 'creative':
case 'humbled':
case 'lonely':
case 'undefined':
case 'none':
icon = 'mood-four';
break;
case 'afraid':
case 'amazed':
case 'confused':
case 'dismayed':
case 'hungry':
case 'in_awe':
case 'indignant':
case 'jealous':
case 'lost':
case 'offended':
case 'outraged':
case 'shocked':
case 'surprised':
case 'embarrassed':
case 'impressed':
icon = 'mood-five';
break;
case 'crazy':
case 'distracted':
case 'neutral':
case 'relaxed':
case 'thirsty':
icon = 'mood-six';
break;
case 'amorous':
case 'curious':
case 'in_love':
case 'nervous':
case 'sarcastic':
icon = 'mood-eight';
break;
case 'brave':
case 'confident':
case 'hopeful':
case 'grateful':
case 'spontaneous':
case 'thankful':
icon = 'mood-nine';
break;
default:
icon = 'mood-seven';
break;
}
// Return the good icon name
return icon;
}
// Changes the activity icon
function activityIcon(value) {
// The main var
var icon;
// Switch the values
switch(value) {
case 'doing_chores':
icon = 'activity-doing_chores';
break;
case 'drinking':
icon = 'activity-drinking';
break;
case 'eating':
icon = 'activity-eating';
break;
case 'grooming':
icon = 'activity-grooming';
break;
case 'having_appointment':
icon = 'activity-having_appointment';
break;
case 'inactive':
icon = 'activity-inactive';
break;
case 'relaxing':
icon = 'activity-relaxing';
break;
case 'talking':
icon = 'activity-talking';
break;
case 'traveling':
icon = 'activity-traveling';
break;
case 'working':
icon = 'activity-working';
break;
default:
icon = 'activity-exercising';
break;
}
// Return the good icon name
return icon;
}
// Sends the user's mood
function sendMood(value, text) {
/* REF: http://xmpp.org/extensions/xep-0107.html */
// We propagate the mood on the xmpp network
var iq = new JSJaCIQ();
iq.setType('set');
// We create the XML document
var pubsub = iq.appendNode('pubsub', {'xmlns': NS_PUBSUB});
var publish = pubsub.appendChild(iq.buildNode('publish', {'node': NS_MOOD, 'xmlns': NS_PUBSUB}));
var item = publish.appendChild(iq.buildNode('item', {'xmlns': NS_PUBSUB}));
var mood = item.appendChild(iq.buildNode('mood', {'xmlns': NS_MOOD}));
if(value != 'none') {
mood.appendChild(iq.buildNode(value, {'xmlns': NS_MOOD}));
mood.appendChild(iq.buildNode('text', {'xmlns': NS_MOOD}, text));
}
// And finally we send the mood that is set
con.send(iq);
logThis('New mood sent: ' + value + ' (' + text + ')', 3);
}
// Sends the user's activity
function sendActivity(main, sub, text) {
// We propagate the mood on the xmpp network
var iq = new JSJaCIQ();
iq.setType('set');
// We create the XML document
var pubsub = iq.appendNode('pubsub', {'xmlns': NS_PUBSUB});
var publish = pubsub.appendChild(iq.buildNode('publish', {'node': NS_ACTIVITY, 'xmlns': NS_PUBSUB}));
var item = publish.appendChild(iq.buildNode('item', {'xmlns': NS_PUBSUB}));
var activity = item.appendChild(iq.buildNode('activity', {'xmlns': NS_ACTIVITY}));
if(main != 'none') {
var mainType = activity.appendChild(iq.buildNode(main, {'xmlns': NS_ACTIVITY}));
// Child nodes
if(sub)
mainType.appendChild(iq.buildNode(sub, {'xmlns': NS_ACTIVITY}));
if(text)
activity.appendChild(iq.buildNode('text', {'xmlns': NS_ACTIVITY}, text));
}
// And finally we send the mood that is set
con.send(iq);
logThis('New activity sent: ' + main + ' (' + text + ')', 3);
}
// Sends the user's geographic position
function sendPosition(vLat, vLon, vAlt, vCountry, vCountrycode, vRegion, vPostalcode, vLocality, vStreet, vBuilding, vText, vURI) {
/* REF: http://xmpp.org/extensions/xep-0080.html */
// We propagate the position on pubsub
var iq = new JSJaCIQ();
iq.setType('set');
// We create the XML document
var pubsub = iq.appendNode('pubsub', {'xmlns': NS_PUBSUB});
var publish = pubsub.appendChild(iq.buildNode('publish', {'node': NS_GEOLOC, 'xmlns': NS_PUBSUB}));
var item = publish.appendChild(iq.buildNode('item', {'xmlns': NS_PUBSUB}));
var geoloc = item.appendChild(iq.buildNode('geoloc', {'xmlns': NS_GEOLOC}));
// Create two position arrays
var pos_names = ['lat', 'lon', 'alt', 'country', 'countrycode', 'region', 'postalcode', 'locality', 'street', 'building', 'text', 'uri', 'timestamp'];
var pos_values = [ vLat, vLon, vAlt, vCountry, vCountrycode, vRegion, vPostalcode, vLocality, vStreet, vBuilding, vText, vURI, getXMPPTime('utc')];
for(var i = 0; i < pos_names.length; i++) {
if(pos_names[i] && pos_values[i])
geoloc.appendChild(iq.buildNode(pos_names[i], {'xmlns': NS_GEOLOC}, pos_values[i]));
}
// And finally we send the XML
con.send(iq);
// For logger
if(vLat && vLon)
logThis('Geolocated.', 3);
else
logThis('Not geolocated.', 2);
}
// Parses the user's geographic position
function parsePosition(data) {
var result = $(data).find('result:first');
// Get latitude and longitude
var lat = result.find('geometry:first location:first lat').text();
var lng = result.find('geometry:first location:first lng').text();
var array = [
lat,
lng,
result.find('address_component:has(type:contains("country")):first long_name').text(),
result.find('address_component:has(type:contains("country")):first short_name').text(),
result.find('address_component:has(type:contains("administrative_area_level_1")):first long_name').text(),
result.find('address_component:has(type:contains("postal_code")):first long_name').text(),
result.find('address_component:has(type:contains("locality")):first long_name').text(),
result.find('address_component:has(type:contains("route")):first long_name').text(),
result.find('address_component:has(type:contains("street_number")):first long_name').text(),
result.find('formatted_address:first').text(),
'http://maps.google.com/?q=' + encodeQuotes(lat) + ',' + encodeQuotes(lng)
];
return array;
}
// Converts a position into an human-readable one
function humanPosition(tLocality, tRegion, tCountry) {
var tHuman = '';
// Any locality?
if(tLocality) {
tHuman += tLocality;
if(tRegion)
tHuman += ', ' + tRegion;
if(tCountry)
tHuman += ', ' + tCountry;
}
// Any region?
else if(tRegion) {
tHuman += tRegion;
if(tCountry)
tHuman += ', ' + tCountry;
}
// Any country?
else if(tCountry)
tHuman += tCountry;
return tHuman;
}
// Gets the user's geographic position
function getPosition(position) {
// Convert integers to strings
var vLat = '' + position.coords.latitude;
var vLon = '' + position.coords.longitude;
var vAlt = '' + position.coords.altitude;
// Get full position (from Google Maps API)
$.get('./php/geolocation.php', {latitude: vLat, longitude: vLon, language: XML_LANG}, function(data) {
// Parse data!
var results = parsePosition(data);
// Handled!
sendPosition(
vLat,
vLon,
vAlt,
results[2],
results[3],
results[4],
results[5],
results[6],
results[7],
results[8],
results[9],
results[10]
);
// Store data
setDB('geolocation', 'now', xmlToString(data));
logThis('Position details got from Google Maps API.');
});
logThis('Position got: latitude > ' + vLat + ' / longitude > ' + vLon + ' / altitude > ' + vAlt);
}
// Geolocates the user
function geolocate() {
// Don't fire it until options & features are not retrieved!
if(!getDB('options', 'geolocation') || (getDB('options', 'geolocation') == '0') || !enabledPEP())
return;
// We publish the user location if allowed
if(navigator.geolocation) {
// Wait a bit... (to fix a bug)
$('#my-infos').stopTime().oneTime('1s', function() {
navigator.geolocation.getCurrentPosition(getPosition);
});
logThis('Geolocating...', 3);
}
// Any error?
else
logThis('Not geolocated: browser does not support it.', 1);
}
// Displays all the supported PEP events for a given XID
function displayAllPEP(xid) {
displayPEP(xid, 'mood');
displayPEP(xid, 'activity');
displayPEP(xid, 'tune');
displayPEP(xid, 'geoloc');
}
// Plugin launcher
function launchPEP() {
// Apply empty values to the PEP database
setDB('mood-value', 1, '');
setDB('mood-text', 1, '');
setDB('activity-value', 1, '');
setDB('activity-text', 1, '');
// Click event for user mood
$('#my-infos .f-mood a.picker').click(function() {
// Initialize some vars
var path = '#my-infos .f-mood div.bubble';
var mood_id = ['crazy', 'excited', 'playful', 'happy', 'shocked', 'hot', 'sad', 'amorous', 'confident'];
var mood_lang = [_e("Crazy"), _e("Excited"), _e("Playful"), _e("Happy"), _e("Shocked"), _e("Hot"), _e("Sad"), _e("Amorous"), _e("Confident")];
var mood_val = $('#my-infos .f-mood a.picker').attr('data-value');
// Yet displayed?
var can_append = true;
if(exists(path))
can_append = false;
// Add this bubble!
showBubble(path);
if(!can_append)
return false;
// Generate the HTML code
var html = '<div class="bubble removable">';
for(i in mood_id) {
// Yet in use: no need to display it!
if(mood_id[i] == mood_val)
continue;
html += '<a href="#" class="talk-images" data-value="' + mood_id[i] + '" title="' + mood_lang[i] + '"></a>';
}
html += '</div>';
// Append the HTML code
$('#my-infos .f-mood').append(html);
// Click event
$(path + ' a').click(function() {
// Update the mood marker
$('#my-infos .f-mood a.picker').attr('data-value', $(this).attr('data-value'));
// Close the bubble
closeBubbles();
// Focus on the status input
$(document).oneTime(10, function() {
$('#mood-text').focus();
});
return false;
});
return false;
});
// Click event for user activity
$('#my-infos .f-activity a.picker').click(function() {
// Initialize some vars
var path = '#my-infos .f-activity div.bubble';
var activity_id = ['doing_chores', 'drinking', 'eating', 'exercising', 'grooming', 'having_appointment', 'inactive', 'relaxing', 'talking', 'traveling', 'working'];
var activity_lang = [_e("Chores"), _e("Drinking"), _e("Eating"), _e("Exercising"), _e("Grooming"), _e("Appointment"), _e("Inactive"), _e("Relaxing"), _e("Talking"), _e("Traveling"), _e("Working")];
var activity_val = $('#my-infos .f-activity a.picker').attr('data-value');
// Yet displayed?
var can_append = true;
if(exists(path))
can_append = false;
// Add this bubble!
showBubble(path);
if(!can_append)
return false;
// Generate the HTML code
var html = '<div class="bubble removable">';
for(i in activity_id) {
// Yet in use: no need to display it!
if(activity_id[i] == activity_val)
continue;
html += '<a href="#" class="talk-images" data-value="' + activity_id[i] + '" title="' + activity_lang[i] + '"></a>';
}
html += '</div>';
// Append the HTML code
$('#my-infos .f-activity').append(html);
// Click event
$(path + ' a').click(function() {
// Update the activity marker
$('#my-infos .f-activity a.picker').attr('data-value', $(this).attr('data-value'));
// Close the bubble
closeBubbles();
// Focus on the status input
$(document).oneTime(10, function() {
$('#activity-text').focus();
});
return false;
});
return false;
});
// Submit events for PEP inputs
$('#mood-text, #activity-text').placeholder()
.keyup(function(e) {
if(e.keyCode == 13) {
$(this).blur();
return false;
}
});
// Input blur handler
$('#mood-text').blur(function() {
// Read the parameters
var value = $('#my-infos .f-mood a.picker').attr('data-value');
var text = $(this).val();
// Must send the mood?
if((value != getDB('mood-value', 1)) || (text != getDB('mood-text', 1))) {
// Update the local stored values
setDB('mood-value', 1, value);
setDB('mood-text', 1, text);
// Send it!
sendMood(value, text);
}
})
// Input focus handler
.focus(function() {
closeBubbles();
});
// Input blur handler
$('#activity-text').blur(function() {
// Read the parameters
var value = $('#my-infos .f-activity a.picker').attr('data-value');
var text = $(this).val();
// Must send the activity?
if((value != getDB('activity-value', 1)) || (text != getDB('activity-text', 1))) {
// Update the local stored values
setDB('activity-value', 1, value);
setDB('activity-text', 1, text);
// Send it!
sendActivity(value, '', text);
}
})
// Input focus handler
.focus(function() {
closeBubbles();
});
}

View file

@ -0,0 +1,42 @@
/*
Jappix - An open social platform
These are the popup JS scripts for Jappix
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 26/04/11
*/
// Creates a popup code
function createPopup(id, content) {
// Popup exists?
if(exists('#' + id))
return false;
// Append the popup code
$('body').append(
'<div id="' + id + '" class="lock removable">' +
'<div class="popup">' +
content +
'</div>' +
'</div>'
);
return true;
}
// Destroys a popup code
function destroyPopup(id) {
// Stop the popup timers
$('#' + id + ' *').stopTime();
// Remove the popup
$('#' + id).remove();
// Manage input focus
inputFocus();
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,963 @@
/*
Jappix - An open social platform
These are the privacy JS scripts for Jappix
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 23/06/11
*/
// Opens the privacy popup
function openPrivacy() {
// Popup HTML content
var html =
'<div class="top">' + _e("Privacy") + '</div>' +
'<div class="content">' +
'<div class="privacy-head">' +
'<div class="list-left">' +
'<span>' + _e("Choose") + '</span>' +
'<select disabled=""></select>' +
'<a href="#" class="list-remove one-button talk-images" title="' + _e("Remove") + '"></a>' +
'</div>' +
'<div class="list-center"></div>' +
'<div class="list-right">' +
'<span>' + _e("Add") + '</span>' +
'<input type="text" placeholder="' + _e("List name") + '" />' +
'</div>' +
'</div>' +
'<div class="privacy-item">' +
'<span>' + _e("Item") + '</span>' +
'<select disabled=""></select>' +
'<a href="#" class="item-add one-button talk-images" title="' + _e("Add") + '"></a>' +
'<a href="#" class="item-remove one-button talk-images" title="' + _e("Remove") + '"></a>' +
'<a href="#" class="item-save one-button talk-images">' + _e("Save") + '</a>' +
'<div class="clear"></div>' +
'</div>' +
'<div class="privacy-form">' +
'<div class="privacy-first">' +
'<label><input type="radio" name="action" value="allow" disabled="" />' + _e("Allow") + '</label>' +
'<label><input type="radio" name="action" value="deny" disabled="" />' + _e("Deny") + '</label>' +
'</div>' +
'<div class="privacy-second">' +
'<label><input type="radio" name="type" value="jid" disabled="" />' + _e("Address") + '</label>' +
'<input type="text" name="jid" disabled="" />' +
'<label><input type="radio" name="type" value="group" disabled="" />' + _e("Group") + '</label>' +
'<select name="group" disabled="">' + groupsToHtmlPrivacy() + '</select>' +
'<label><input type="radio" name="type" value="subscription" disabled="" />' + _e("Subscription") + '</label>' +
'<select name="subscription" disabled="">' +
'<option value="none">' + _e("None") + '</option>' +
'<option value="both">' + _e("Both") + '</option>' +
'<option value="from">' + _e("From") + '</option>' +
'<option value="to">' + _e("To") + '</option>' +
'</select>' +
'<label><input type="radio" name="type" value="everybody" disabled="" />' + _e("Everybody") + '</label>' +
'</div>' +
'<div class="privacy-third">' +
'<label><input type="checkbox" name="send-messages" disabled="" />' + _e("Send messages") + '</label>' +
'<label><input type="checkbox" name="send-queries" disabled="" />' + _e("Send queries") + '</label>' +
'<label><input type="checkbox" name="see-status" disabled="" />' + _e("See my status") + '</label>' +
'<label><input type="checkbox" name="send-status" disabled="" />' + _e("Send his/her status") + '</label>' +
'<label><input type="checkbox" name="everything" disabled="" />' + _e("Everything") + '</label>' +
'</div>' +
'<div class="clear"></div>' +
'</div>' +
'<div class="privacy-active">' +
'<label>' + _e("Order") + '<input type="text" name="order" value="1" disabled="" /></label>' +
'<div class="privacy-active-elements">' +
'<label><input type="checkbox" name="active" disabled="" />' + _e("Active for this session") + '</label>' +
'<label><input type="checkbox" name="default" disabled="" />' + _e("Always active") + '</label>' +
'</div>' +
'</div>' +
'</div>' +
'<div class="bottom">' +
'<div class="wait wait-medium"></div>' +
'<a href="#" class="finish">' + _e("Close") + '</a>' +
'</div>';
// Create the popup
createPopup('privacy', html);
// Associate the events
launchPrivacy();
// Display the available privacy lists
displayListsPrivacy();
// Get the first list items
displayItemsPrivacy();
return false;
}
// Quits the privacy popup
function closePrivacy() {
// Destroy the popup
destroyPopup('privacy');
return false;
}
// Sets the received state for privacy block list
function receivedPrivacy() {
// Store marker
setDB('privacy-marker', 'available', 'true');
// Show privacy elements
$('.privacy-hidable').show();
}
// Gets available privacy lists
function listPrivacy() {
// Build query
var iq = new JSJaCIQ();
iq.setType('get');
iq.setQuery(NS_PRIVACY);
con.send(iq, handleListPrivacy);
logThis('Getting available privacy list(s)...');
}
// Handles available privacy lists
function handleListPrivacy(iq) {
// Error?
if(iq.getType() == 'error')
return logThis('Privacy lists not supported!', 2);
// Get IQ query content
var iqQuery = iq.getQuery();
// Save the content
setDB('privacy-lists', 'available', xmlToString(iqQuery));
// Any block list?
if($(iqQuery).find('list[name=block]').size()) {
// Not the default one?
if(!$(iqQuery).find('default[name=block]').size())
changePrivacy('block', 'default');
else
setDB('privacy-marker', 'default', 'block');
// Not the active one?
if(!$(iqQuery).find('active[name=block]').size())
changePrivacy('block', 'active');
else
setDB('privacy-marker', 'active', 'block');
// Get the block list rules
getPrivacy('block');
}
// Apply the received marker here
else
receivedPrivacy();
logThis('Got available privacy list(s).', 3);
}
// Gets privacy lists
function getPrivacy(list) {
// Build query
var iq = new JSJaCIQ();
iq.setType('get');
// Privacy query
var iqQuery = iq.setQuery(NS_PRIVACY);
iqQuery.appendChild(iq.buildNode('list', {'xmlns': NS_PRIVACY, 'name': list}));
con.send(iq, handleGetPrivacy);
// Must show the wait item?
if(exists('#privacy'))
$('#privacy .wait').show();
logThis('Getting privacy list(s): ' + list);
}
// Handles privacy lists
function handleGetPrivacy(iq) {
// Apply a "received" marker
receivedPrivacy();
// Store the data for each list
$(iq.getQuery()).find('list').each(function() {
// Read list name
var list_name = $(this).attr('name');
// Store list content
setDB('privacy', list_name, xmlToString(this));
// Is this a block list?
if(list_name == 'block') {
// Reset buddies
$('#buddy-list .buddy').removeClass('blocked');
// XID types
$(this).find('item[action=deny][type=jid]').each(function() {
$('#buddy-list .buddy[data-xid=' + escape($(this).attr('value')) + ']').addClass('blocked');
});
// Group types
$(this).find('item[action=deny][type=group]').each(function() {
$('#buddy-list .group' + hex_md5($(this).attr('value')) + ' .buddy').addClass('blocked');
});
}
});
// Must display it to the popup?
if(exists('#privacy')) {
displayItemsPrivacy();
$('#privacy .wait').hide();
}
logThis('Got privacy list(s).', 3);
}
// Sets a privacy list
function setPrivacy(list, types, values, actions, orders, presence_in, presence_out, msg, iq_p) {
// Build query
var iq = new JSJaCIQ();
iq.setType('set');
// Privacy query
var iqQuery = iq.setQuery(NS_PRIVACY);
var iqList = iqQuery.appendChild(iq.buildNode('list', {'xmlns': NS_PRIVACY, 'name': list}));
// Build the item elements
if(types && types.length) {
for(var i = 0; i < types.length; i++) {
// Item element
var iqItem = iqList.appendChild(iq.buildNode('item', {'xmlns': NS_PRIVACY}));
// Item attributes
if(types[i])
iqItem.setAttribute('type', types[i]);
if(values[i])
iqItem.setAttribute('value', values[i]);
if(actions[i])
iqItem.setAttribute('action', actions[i]);
if(orders[i])
iqItem.setAttribute('order', orders[i]);
// Child elements
if(presence_in[i])
iqItem.appendChild(iq.buildNode('presence-in', {'xmlns': NS_PRIVACY}));
if(presence_out[i])
iqItem.appendChild(iq.buildNode('presence-out', {'xmlns': NS_PRIVACY}));
if(msg[i])
iqItem.appendChild(iq.buildNode('message', {'xmlns': NS_PRIVACY}));
if(iq_p[i])
iqItem.appendChild(iq.buildNode('iq', {'xmlns': NS_PRIVACY}));
}
}
con.send(iq);
logThis('Sending privacy list: ' + list);
}
// Push a privacy list item to a list
function pushPrivacy(list, type, value, action, order, presence_in, presence_out, msg, iq_p, hash, special_action) {
// Read the stored elements (to add them)
var stored = XMLFromString(getDB('privacy', list));
// Read the first value
var first_val = value[0];
// Must remove the given value?
if(special_action == 'remove') {
type = [];
value = [];
action = [];
order = [];
presence_in = [];
presence_out = [];
iq_p = [];
}
// Serialize them to an array
$(stored).find('item').each(function() {
// Attributes
var c_type = $(this).attr('type');
var c_value = $(this).attr('value');
var c_action = $(this).attr('action');
var c_order = $(this).attr('order');
// Generate hash
var c_hash = hex_md5(c_type + c_value + c_action + c_order);
// Do not push it twice!
if(((c_hash != hash) && (special_action != 'roster')) || ((first_val != c_value) && (special_action == 'roster'))) {
if(!c_type)
c_type = '';
if(!c_value)
c_value = '';
if(!c_action)
c_action = '';
if(!c_order)
c_order = '';
type.push(c_type);
value.push(c_value);
action.push(c_action);
order.push(c_order);
// Child elements
if($(this).find('presence-in').size())
presence_in.push(true);
else
presence_in.push(false);
if($(this).find('presence-out').size())
presence_out.push(true);
else
presence_out.push(false);
if($(this).find('message').size())
msg.push(true);
else
msg.push(false);
if($(this).find('iq').size())
iq_p.push(true);
else
iq_p.push(false);
}
});
// Send it!
setPrivacy(list, type, value, action, order, presence_in, presence_out, msg, iq_p);
}
// Change a privacy list status
function changePrivacy(list, status) {
// Yet sent?
if(getDB('privacy-marker', status) == list)
return;
// Write a marker
setDB('privacy-marker', status, list);
// Build query
var iq = new JSJaCIQ();
iq.setType('set');
// Privacy query
var iqQuery = iq.setQuery(NS_PRIVACY);
var iqStatus = iqQuery.appendChild(iq.buildNode(status, {'xmlns': NS_PRIVACY}));
// Can add a "name" attribute?
if(list)
iqStatus.setAttribute('name', list);
con.send(iq);
logThis('Changing privacy list status: ' + list + ' to: ' + status);
}
// Checks the privacy status (action) of a value
function statusPrivacy(list, value) {
return $(XMLFromString(getDB('privacy', list))).find('item[value=' + value + ']').attr('action');
}
// Converts the groups array into a <option /> string
function groupsToHtmlPrivacy() {
var groups = getAllGroups();
var html = '';
// Generate HTML
for(i in groups) {
html += '<option value="' + encodeQuotes(groups[i]) +'">' + groups[i].htmlEnc() + '</option>';
}
return html;
}
// Displays the privacy lists
function displayListsPrivacy() {
// Initialize
var code = '';
var select = $('#privacy .privacy-head .list-left select');
var data = XMLFromString(getDB('privacy-lists', 'available'));
// Parse the XML data!
$(data).find('list').each(function() {
var list_name = $(this).attr('name');
if(list_name)
code += '<option value="' + encodeQuotes(list_name) + '">' + list_name.htmlEnc() + '</option>';
});
// Apply HTML code
select.html(code);
// Not empty?
if(code)
select.removeAttr('disabled');
else
select.attr('disabled', true);
return true;
}
// Displays the privacy items for a list
function displayItemsPrivacy() {
// Reset the form
clearFormPrivacy();
disableFormPrivacy();
// Initialize
var code = '';
var select = $('#privacy .privacy-item select');
var list = $('#privacy .privacy-head .list-left select').val();
// Reset the item select
select.html('');
// No list?
if(!list)
return false;
// Reset the list status
$('#privacy .privacy-active input[type=checkbox]').removeAttr('checked');
// Display the list status
var status = ['active', 'default'];
for(s in status) {
if(getDB('privacy-marker', status[s]) == list)
$('#privacy .privacy-active input[name=' + status[s] + ']').attr('checked', true);
}
// Try to read the stored items
var items = XMLFromString(getDB('privacy', list));
// Must retrieve the data?
if(!items) {
select.attr('disabled', true);
return getPrivacy(list);
}
else
select.removeAttr('disabled');
// Parse the XML data!
$(items).find('item').each(function() {
// Read attributes
var item_type = $(this).attr('type');
var item_value = $(this).attr('value');
var item_action = $(this).attr('action');
var item_order = $(this).attr('order');
// Generate hash
var item_hash = hex_md5(item_type + item_value + item_action + item_order);
// Read sub-elements
var item_presencein = $(this).find('presence-in').size();
var item_presenceout = $(this).find('presence-out').size();
var item_message = $(this).find('message').size();
var item_iq = $(this).find('iq').size();
// Apply default values (if missing)
if(!item_type)
item_type = '';
if(!item_value)
item_value = '';
if(!item_action)
item_action = 'allow';
if(!item_order)
item_order = '1';
// Apply sub-elements values
if(item_presencein)
item_presencein = 'true';
else
item_presencein = 'false';
if(item_presenceout)
item_presenceout = 'true';
else
item_presenceout = 'false';
if(item_message)
item_message = 'true';
else
item_message = 'false';
if(item_iq)
item_iq = 'true';
else
item_iq = 'false';
// Generate item description
var desc = '';
var desc_arr = [item_type, item_value, item_action, item_order];
for(d in desc_arr) {
// Nothing to display?
if(!desc_arr[d])
continue;
if(desc)
desc += ' - ';
desc += desc_arr[d];
}
// Add the select option
code += '<option data-type="' + encodeQuotes(item_type) + '" data-value="' + encodeQuotes(item_value) + '" data-action="' + encodeQuotes(item_action) + '" data-order="' + encodeQuotes(item_order) + '" data-presence_in="' + encodeQuotes(item_presencein) + '" data-presence_out="' + encodeQuotes(item_presenceout) + '" data-message="' + encodeQuotes(item_message) + '" data-iq="' + encodeQuotes(item_iq) + '" data-hash="' + encodeQuotes(item_hash) + '">' +
desc +
'</option>';
});
// Append the code
select.append(code);
// Display the first item form
var first_item = select.find('option:first');
displayFormPrivacy(
first_item.attr('data-type'),
first_item.attr('data-value'),
first_item.attr('data-action'),
first_item.attr('data-order'),
first_item.attr('data-presence_in'),
first_item.attr('data-presence_out'),
first_item.attr('data-message'),
first_item.attr('data-iq')
);
return true;
}
// Displays the privacy form for an item
function displayFormPrivacy(type, value, action, order, presence_in, presence_out, message, iq) {
// Reset the form
clearFormPrivacy();
// Apply the action
$('#privacy .privacy-first input[name=action][value=' + action + ']').attr('checked', true);
// Apply the type & value
var privacy_second = '#privacy .privacy-second';
var privacy_type = privacy_second + ' input[name=type]';
var type_check, value_input;
switch(type) {
case 'jid':
type_check = privacy_type + '[value=jid]';
value_input = privacy_second + ' input[type=text][name=jid]';
break;
case 'group':
type_check = privacy_type + '[value=group]';
value_input = privacy_second + ' select[name=group]';
break;
case 'subscription':
type_check = privacy_type + '[value=subscription]';
value_input = privacy_second + ' select[name=subscription]';
break;
default:
type_check = privacy_type + '[value=everybody]';
break;
}
// Check the target
$(type_check).attr('checked', true);
// Can apply a value?
if(value_input)
$(value_input).val(value);
// Apply the things to do
var privacy_do = '#privacy .privacy-third input[type=checkbox]';
if(presence_in == 'true')
$(privacy_do + '[name=send-status]').attr('checked', true);
if(presence_out == 'true')
$(privacy_do + '[name=see-status]').attr('checked', true);
if(message == 'true')
$(privacy_do + '[name=send-messages]').attr('checked', true);
if(iq == 'true')
$(privacy_do + '[name=send-queries]').attr('checked', true);
if(!$(privacy_do).filter(':checked').size())
$(privacy_do + '[name=everything]').attr('checked', true);
// Apply the order
$('#privacy .privacy-active input[name=order]').val(order);
// Enable the forms
$('#privacy .privacy-form input, #privacy .privacy-form select, #privacy .privacy-active input').removeAttr('disabled');
}
// Clears the privacy list form
function clearFormPrivacy() {
// Uncheck checkboxes & radio inputs
$('#privacy .privacy-form input[type=checkbox], #privacy .privacy-form input[type=radio]').removeAttr('checked');
// Reset select
$('#privacy .privacy-form select option').removeAttr('selected');
$('#privacy .privacy-form select option:first').attr('selected', true);
// Reset text input
$('#privacy .privacy-form input[type=text]').val('');
// Reset order input
$('#privacy .privacy-active input[name=order]').val('1');
}
// Disables the privacy list form
function disableFormPrivacy() {
$('#privacy .privacy-form input, #privacy .privacy-form select, #privacy .privacy-active input').attr('disabled', true);
}
// Enables the privacy list form
function enableFormPrivacy(rank) {
$('#privacy .privacy-' + rank + ' input, #privacy .privacy-' + rank + ' select').removeAttr('disabled');
}
// Plugin launcher
function launchPrivacy() {
// Click events
$('#privacy .bottom .finish').click(closePrivacy);
// Placeholder events
$('#privacy input[placeholder]').placeholder();
// Form events
$('#privacy .privacy-head a.list-remove').click(function() {
// Get list name
var list = $('#privacy .privacy-head .list-left select').val();
// No value?
if(!list)
return false;
// Remove it from popup
$('#privacy .privacy-head .list-left select option[value=' + list + ']').remove();
// Nothing remaining?
if(!exists('#privacy .privacy-head .list-left select option'))
$('#privacy .privacy-head .list-left select option').attr('disabled', true);
// Empty the item select
$('#privacy .privacy-item select').attr('disabled', true).html('');
// Disable this list before removing it
var status = ['active', 'default'];
for(s in status) {
if(getDB('privacy-marker', status[s]) == list)
changePrivacy('', status[s]);
}
// Remove from server
setPrivacy(list);
// Reset the form
clearFormPrivacy();
disableFormPrivacy();
return false;
});
$('#privacy .privacy-head .list-right input').keyup(function(e) {
// Not enter?
if(e.keyCode != 13)
return;
// Get list name
var list = $('#privacy .privacy-head .list-right input').val();
var select = '#privacy .privacy-head .list-left select';
var existed = true;
// Create the new element
if(!exists(select + ' option[value=' + list + ']')) {
// Marker
existed = false;
// Create a new option
$(select).append('<option value="' + encodeQuotes(list) + '">' + list.htmlEnc() + '</option>');
// Reset the item select
$('#privacy .privacy-item select').attr('disabled', true).html('');
}
// Change the select value & enable it
$(select).val(list).removeAttr('disabled');
// Reset its value
$(this).val('');
// Reset the form
clearFormPrivacy();
disableFormPrivacy();
// Must reload the list items?
if(existed) {
displayItemsPrivacy();
$('#privacy .privacy-item select').removeAttr('disabled');
}
});
$('#privacy .privacy-head .list-left select').change(displayItemsPrivacy);
$('#privacy .privacy-item select').change(function() {
// Get the selected item
var item = $(this).find('option:selected');
// Display the data!
displayFormPrivacy(
item.attr('data-type'),
item.attr('data-value'),
item.attr('data-action'),
item.attr('data-order'),
item.attr('data-presence_in'),
item.attr('data-presence_out'),
item.attr('data-message'),
item.attr('data-iq')
);
});
$('#privacy .privacy-item a.item-add').click(function() {
// Cannot add anything?
if(!exists('#privacy .privacy-head .list-left select option:selected'))
return false;
// Disable item select
$('#privacy .privacy-item select').attr('disabled', true);
// Reset the form
clearFormPrivacy();
disableFormPrivacy();
// Enable first form item
enableFormPrivacy('first');
enableFormPrivacy('active');
return false;
});
$('#privacy .privacy-item a.item-remove').click(function() {
// Cannot add anything?
if(!exists('#privacy .privacy-head .list-left select option:selected'))
return false;
// Get values
var list = $('#privacy .privacy-head .list-left select').val();
var selected = $('#privacy .privacy-item select option:selected');
var item = selected.attr('data-value');
var hash = selected.attr('data-hash');
// Remove it from popup
$('#privacy .privacy-item select option:selected').remove();
// No more items in this list?
if(!exists('#privacy .privacy-item select option')) {
// Disable this select
$('#privacy .privacy-item select').attr('disabled', true);
// Remove the privacy list select item
$('#privacy .privacy-head .list-left select option[value=' + list + ']').remove();
// No more privacy lists?
if(!exists('#privacy .privacy-head .list-left select option'))
$('#privacy .privacy-head .list-left select').attr('disabled', true);
// Disable this list before removing it
var status = ['active', 'default'];
for(s in status) {
if(getDB('privacy-marker', status[s]) == list)
changePrivacy('', status[s]);
}
}
// Synchronize it with server
pushPrivacy(list, [], [item], [], [], [], [], [], [], hash, 'remove');
// Reset the form
clearFormPrivacy();
disableFormPrivacy();
return false;
});
$('#privacy .privacy-item a.item-save').click(function() {
// Canot push item?
if(exists('#privacy .privacy-form input:disabled'))
return false;
// Get the hash
var item_hash = '';
if(!$('#privacy .privacy-item select').is(':disabled'))
item_hash = $('#privacy .privacy-item select option:selected').attr('data-hash');
// Read the form
var privacy_second = '#privacy .privacy-second';
var item_list = $('#privacy .privacy-head .list-left select').val();
var item_action = $('#privacy .privacy-first input[name=action]').filter(':checked').val();
var item_type = $(privacy_second + ' input[name=type]').filter(':checked').val();
var item_order = $('#privacy .privacy-active input[name=order]').val();
var item_value = '';
// Switch the type to get the value
switch(item_type) {
case 'jid':
item_value = $(privacy_second + ' input[type=text][name=jid]').val();
break;
case 'group':
item_value = $(privacy_second + ' select[name=group]').val();
break;
case 'subscription':
item_value = $(privacy_second + ' select[name=subscription]').val();
break;
default:
item_type = '';
break;
}
// Get the selected things to do
var privacy_third_cb = '#privacy .privacy-third input[type=checkbox]';
var item_prin = false;
var item_prout = false;
var item_msg = false;
var item_iq = false;
// Individual select?
if(!$(privacy_third_cb + '[name=everything]').filter(':checked').size()) {
if($(privacy_third_cb + '[name=send-messages]').filter(':checked').size())
item_msg = true;
if($(privacy_third_cb + '[name=send-queries]').filter(':checked').size())
item_iq = true;
if($(privacy_third_cb + '[name=send-queries]').filter(':checked').size())
item_iq = true;
if($(privacy_third_cb + '[name=see-status]').filter(':checked').size())
item_prout = true;
if($(privacy_third_cb + '[name=send-status]').filter(':checked').size())
item_prin = true;
}
// Push item to the server!
pushPrivacy(
item_list,
[item_type],
[item_value],
[item_action],
[item_order],
[item_prin],
[item_prout],
[item_msg],
[item_iq],
item_hash
);
return false;
});
$('#privacy .privacy-first input').change(function() {
enableFormPrivacy('second');
});
$('#privacy .privacy-second input').change(function() {
enableFormPrivacy('third');
});
$('#privacy .privacy-third input[type=checkbox]').change(function() {
// Target
var target = '#privacy .privacy-third input[type=checkbox]';
// Must tick "everything" checkbox?
if(!$(target).filter(':checked').size())
$(target + '[name=everything]').attr('checked', true);
// Must untick the other checkboxes?
else if($(this).is('[name=everything]'))
$(target + ':not([name=everything])').removeAttr('checked');
// Must untick "everything" checkbox?
else
$(target + '[name=everything]').removeAttr('checked');
});
$('#privacy .privacy-active input[name=order]').keyup(function() {
// Get the value
var value = $(this).val();
// No value?
if(!value)
return;
// Not a number?
if(isNaN(value))
value = 1;
else
value = parseInt(value);
// Negative?
if(value < 0)
value = value * -1;
// Apply the filtered value
$(this).val(value);
})
.blur(function() {
// No value?
if(!$(this).val())
$(this).val('1');
});
$('#privacy .privacy-active .privacy-active-elements input').change(function() {
// Get the values
var list_name = $('#privacy .privacy-head .list-left select').val();
var state_name = $(this).attr('name');
// Cannot continue?
if(!list_name || !state_name)
return;
// Change the current list status
if($(this).filter(':checked').size())
changePrivacy(list_name, state_name);
else
changePrivacy('', state_name);
});
}

View file

@ -0,0 +1,94 @@
/*
Jappix - An open social platform
These are the receipts JS scripts for Jappix
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 26/12/10
*/
// Checks if we can send a receipt request
function receiptRequest(hash) {
// Entity have support for receipt?
if($('#' + hash + ' .message-area').attr('data-receipts') == 'true')
return true;
return false;
}
// Checks if there is a receipt request
function hasReceipt(packet) {
// Any receipt request?
if(packet.getChild('request', NS_URN_RECEIPTS))
return true;
return false;
}
// Checks if there is a received reply
function hasReceived(packet) {
// Any received reply?
if(packet.getChild('received', NS_URN_RECEIPTS))
return true;
return false;
}
// Sends a received notification
function sendReceived(type, to, id) {
var aMsg = new JSJaCMessage();
aMsg.setTo(to);
aMsg.setID(id);
// Any type?
if(type)
aMsg.setType(type);
// Append the received node
aMsg.appendNode('received', {'xmlns': NS_URN_RECEIPTS, 'id': id});
con.send(aMsg);
logThis('Sent received to: ' + to);
}
// Tells the message has been received
function messageReceived(hash, id) {
// Line selector
var path = $('#' + hash + ' .one-line[data-id=' + id + ']');
// Add a received marker
path.attr('data-received', 'true')
.removeAttr('data-lost');
// Group selector
var group = path.parent();
// Remove the group marker
if(!group.find('.one-line[data-lost]').size()) {
group.find('b.name').removeClass('talk-images')
.removeAttr('title');
}
return false;
}
// Checks if the message has been received
function checkReceived(hash, id) {
// Fire a check 10 seconds later
$('#' + hash + ' .one-line[data-id=' + id + ']').oneTime('10s', function() {
// Not received?
if($(this).attr('data-received') != 'true') {
// Add a "lost" marker
$(this).attr('data-lost', 'true');
// Add a warn on the buddy-name
$(this).parent().find('b.name').addClass('talk-images')
.attr('title', _e("Your friend seems not to have received your message(s)!"));
}
});
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,187 @@
/*
Jappix - An open social platform
These are the Roster Item Exchange JS script for Jappix
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 23/06/11
*/
// Opens the welcome tools
function openRosterX(data) {
// Popup HTML content
var html =
'<div class="top">' + _e("Suggested friends") + '</div>' +
'<div class="content">' +
'<div class="rosterx-head">' +
'<a href="#" class="uncheck">' + _e("Uncheck all") + '</a>' +
'<a href="#" class="check">' + _e("Check all") + '</a>' +
'</div>' +
'<div class="results"></div>' +
'</div>' +
'<div class="bottom">' +
'<a href="#" class="finish save">' + _e("Save") + '</a>' +
'<a href="#" class="finish cancel">' + _e("Cancel") + '</a>' +
'</div>';
// Create the popup
createPopup('rosterx', html);
// Associate the events
launchRosterX();
// Parse the data
parseRosterX(data);
logThis('Roster Item Exchange popup opened.');
}
// Closes the welcome tools
function closeRosterX() {
// Destroy the popup
destroyPopup('rosterx');
return false;
}
// Parses a rosterx query
function parseRosterX(data) {
// Main selector
var x = $(data).find('x[xmlns=' + NS_ROSTERX + ']:first');
// Parse data
x.find('item').each(function() {
// Generate group XML
var group = '';
$(this).find('group').each(function() {
group += '<group>' + $(this).text().htmlEnc() + '</group>';
});
if(group)
group = '<groups>' + group + '</groups>';
// Display it!
displayRosterX($(this).attr('jid'), $(this).attr('name'), group, $(this).attr('action'));
});
// Click to check/uncheck
$('#rosterx .oneresult').click(function(evt) {
// No need to apply when click on input
if($(evt.target).is('input[type=checkbox]'))
return;
// Input selector
var checkbox = $(this).find('input[type=checkbox]');
// Check or uncheck?
if(checkbox.filter(':checked').size())
checkbox.removeAttr('checked');
else
checkbox.attr('checked', true);
});
}
// Displays a rosterx item
function displayRosterX(xid, nick, group, action) {
// End if no XID
if(!xid)
return false;
// Set up a default action if no one
if(!action || (action != 'modify') || (action != 'delete'))
action = 'add';
// Override "undefined" for nickname
if(!nick)
nick = '';
// Display it
$('#rosterx .results').append(
'<div class="oneresult">' +
'<input type="checkbox" checked="" data-name="' + encodeQuotes(nick) + '" data-xid="' + encodeQuotes(xid) + '" data-action="' + encodeQuotes(action) + '" data-group="' + encodeQuotes(group) + '" />' +
'<span class="name">' + nick.htmlEnc() + '</span>' +
'<span class="xid">' + xid.htmlEnc() + '</span>' +
'<span class="action ' + action + ' talk-images"></span>' +
'</div>'
);
}
// Saves the rosterx settings
function saveRosterX() {
// Send the requests
$('#rosterx .results input[type=checkbox]').filter(':checked').each(function() {
// Read the attributes
var nick = $(this).attr('data-name');
var xid = $(this).attr('data-xid');
var action = $(this).attr('data-action');
var group = $(this).attr('data-group');
// Parse groups XML
if(group) {
var group_arr = []
$(group).find('group').each(function() {
group_arr.push($(this).text().revertHtmlEnc());
});
}
// Process the asked action
var roster_item = $('#buddy-list .' + hex_md5(xid));
switch(action) {
// Buddy add
case 'add':
if(!exists(roster_item)) {
sendSubscribe(xid, 'subscribe');
sendRoster(xid, '', nick, group_arr);
}
break;
// Buddy edit
case 'modify':
if(exists(roster_item))
sendRoster(xid, '', nick, group_arr);
break;
// Buddy delete
case 'delete':
if(exists(roster_item))
sendRoster(xid, 'remove');
break;
}
});
// Close the popup
closeRosterX();
}
// Plugin launcher
function launchRosterX() {
// Click events
$('#rosterx .bottom .finish').click(function() {
if($(this).is('.save'))
return saveRosterX();
if($(this).is('.cancel'))
return closeRosterX();
});
$('#rosterx .rosterx-head a').click(function() {
if($(this).is('.check'))
$('#rosterx .results input[type=checkbox]').attr('checked', true);
else if($(this).is('.uncheck'))
$('#rosterx .results input[type=checkbox]').removeAttr('checked');
return false;
});
}

View file

@ -0,0 +1,288 @@
/*
Jappix - An open social platform
These are the seach tools JS script for Jappix
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 19/03/11
*/
// Searches in the user's buddy list
function processBuddySearch(query) {
// No query submitted?
if(!query)
return;
// Wildcard (*) submitted
if(query == '*')
query = '';
// Replace forbidden characters in regex
query = escapeRegex(query);
// Create an empty array
var results = new Array();
// Search regex
var regex = new RegExp('((^)|( ))' + query, 'gi');
// Search in the roster
var buddies = getAllBuddies();
for(i in buddies) {
var xid = buddies[i];
var nick = getBuddyName(xid);
// Buddy match our search, and not yet in the array
if(nick.match(regex) && !existArrayValue(results, xid))
results.push(xid);
}
// Return the results array
return results;
}
// Resets the buddy search tool
function resetBuddySearch(destination) {
$(destination + ' ul').remove();
$(destination + ' input').removeClass('suggested');
}
// Add the clicked XID to the input
function addBuddySearch(destination, xid) {
// Remove the search tool
resetBuddySearch(destination);
// Define a selector
var input = $(destination + ' input');
var value = input.val();
// Get the old value (if there's another value)
var old = '';
if(value.match(/(^(.+)(,)(\s)?)(\w+)$/))
old = RegExp.$1;
// Add the XID to the "to" input and focus on it
$(document).oneTime(10, function() {
input.val(old + xid).focus();
});
return false;
}
// Creates the appropriate markup for the search results
function createBuddySearch(destination) {
// Reset the search engine
resetBuddySearch(destination);
// Get the entered value
var value = $(destination + ' input').val();
// Separation with a comma?
if(value.match(/^(.+)((,)(\s)?)(\w+)$/))
value = RegExp.$5;
// Get the result array
var entered = processBuddySearch(value);
// Display each result (if any)
if(entered && entered.length) {
// Set a special class to the search input
$(destination + ' input').addClass('suggested');
// Append each found buddy in the container
var regex = new RegExp('((^)|( ))' + value, 'gi');
// Initialize the code generation
var code = '<ul>';
for(b in entered) {
// Get some values from the XID
var current = getBuddyName(entered[b]).htmlEnc();
current = current.replace(regex, '<b>$&</b>');
// Add the current element to the global code
code += '<li onclick="return addBuddySearch(\'' + encodeOnclick(destination) + '\', \'' + encodeOnclick(entered[b]) + '\');" data-xid="' + encodeQuotes(entered[b]) + '">' + current + '</li>';
}
// Finish the code generation
code += '</ul>';
// Creates the code in the DOM
$(destination).append(code);
// Put the hover on the first element
$(destination + ' ul li:first').addClass('hovered');
// Hover event, to not to remove this onblur and loose the click event
$(destination + ' ul li').hover(function() {
$(destination + ' ul li').removeClass('hovered');
$(this).addClass('hovered');
// Add a marker for the blur event
$(destination + ' ul').attr('mouse-hover', 'true');
}, function() {
$(this).removeClass('hovered');
// Remove the mouse over marker
$(destination + ' ul').removeAttr('mouse-hover');
});
}
}
// Handles the keyboard arrows press when searching
function arrowsBuddySearch(e, destination) {
// Down arrow: 40
// Up arrown: 38
// Initialize
var code = e.keyCode;
// Not the key we want here
if((code != 40) && (code != 38))
return;
// Remove the eventual mouse hover marker
$(destination + ' ul').removeAttr('mouse-hover');
// Create the path & get its size
var path = destination + ' ul li';
var pSize = $(path).size();
// Define the i value
var i = 0;
// Switching yet launched
if(exists(path + '.hovered')) {
var index = $(path).attr('data-hovered');
if(index)
i = parseInt(index);
if(code == 40)
i++;
else
i--;
}
else if(code == 38)
i = pSize - 1;
// We must not override the maximum i limit
if(i >= pSize)
i = 0;
// We must not have negative i
else if(i < 0)
i = pSize - 1;
// Modify the list
$(path + '.hovered').removeClass('hovered');
$(path).eq(i).addClass('hovered');
// Store the i index
$(path).attr('data-hovered', i);
return false;
}
// Filters the buddies in the roster
var SEARCH_FILTERED = false;
function goFilterBuddySearch(vFilter) {
// Put a marker
SEARCH_FILTERED = true;
// Show the buddies that match the search string
var rFilter = processBuddySearch(vFilter);
// Hide all the buddies
$('#buddy-list .buddy').hide();
// Only show the buddies which match the search
for(i in rFilter) {
// Choose the correct selector for this search
if(!BLIST_ALL)
$('#buddy-list .buddy[data-xid=' + escape(rFilter[i]) + ']:not(.hidden-buddy)').show();
else
$('#buddy-list .buddy[data-xid=' + escape(rFilter[i]) + ']').show();
}
}
// Resets the buddy filtering in the roster
function resetFilterBuddySearch() {
// Remove the marker
SEARCH_FILTERED = false;
// Show all the buddies
$('#buddy-list .buddy').show();
// Only show available buddies
if(!BLIST_ALL)
$('#buddy-list .buddy.hidden-buddy').hide();
// Update the groups
updateGroups();
}
// Funnels the buddy filtering
function funnelFilterBuddySearch(keycode) {
// Get the input value
var input = $('#buddy-list .filter input');
var cancel = $('#buddy-list .filter a');
var value = input.val();
// Security: reset all the groups, empty or not, deployed or not
$('#buddy-list .one-group, #buddy-list .group-buddies').show();
$('#buddy-list .group span').text('-');
// Nothing is entered, or escape pressed
if(!value || (keycode == 27)) {
if(keycode == 27)
input.val('');
resetFilterBuddySearch();
cancel.hide();
}
// Process the filtering
else {
cancel.show();
goFilterBuddySearch(value);
}
// Update the groups
updateGroups();
}
// Searches for the nearest element (with a lower stamp than the current one)
function sortElementByStamp(stamp, element) {
var array = new Array();
var i = 0;
var nearest = 0;
// Add the stamp values to the array
$(element).each(function() {
var current_stamp = parseInt($(this).attr('data-stamp'));
// Push it!
array.push(current_stamp);
});
// Sort the array
array.sort();
// Get the nearest stamp value
while(stamp > array[i]) {
nearest = array[i];
i++;
}
return nearest;
}

View file

@ -0,0 +1,113 @@
/*
Jappix - An open social platform
These are the smileys JS scripts for Jappix
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 21/03/11
*/
// Generates the correct HTML code for an emoticon insertion tool
function emoteLink(smiley, image, hash) {
return '<a href="#" class="emoticon emoticon-' + image + ' smileys-images" data-smiley="' + smiley + '"></a>';
}
// Emoticon links arrays
function smileyLinks(hash) {
var links = '';
var sArray = new Array(
':-D',
']:->',
'8-)',
':-P',
':-)',
';-)',
':-$',
':-|',
':-/',
'=-O',
':-(',
':\'-(',
':-@',
':-!',
'({)',
'(})',
':3',
'(@)',
':-[',
':-{}',
'<3',
'</3',
'@}->--',
'(W)',
'(Y)',
'(N)',
'(I)',
'(C)',
'(D)',
'(B)',
'(Z)',
'(X)',
'(P)',
'(T)',
'(8)',
'(%)',
'(E)',
'(R)',
'(*)',
'(S)'
);
var cArray = new Array(
'biggrin',
'devil',
'coolglasses',
'tongue',
'smile',
'wink',
'blush',
'stare',
'frowning',
'oh',
'unhappy',
'cry',
'angry',
'puke',
'hugright',
'hugleft',
'lion',
'pussy',
'bat',
'kiss',
'heart',
'brheart',
'flower',
'brflower',
'thumbup',
'thumbdown',
'lamp',
'coffee',
'drink',
'beer',
'boy',
'girl',
'photo',
'phone',
'music',
'cuffs',
'mail',
'rainbow',
'star',
'moon'
);
for(i in sArray)
links += emoteLink(sArray[i], cArray[i], hash);
return links;
}

View file

@ -0,0 +1,134 @@
/*
Jappix - An open social platform
These are the storage JS scripts for Jappix
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 26/08/11
*/
// Gets the storage items of the user
function getStorage(type) {
/* REF: http://xmpp.org/extensions/xep-0049.html */
var iq = new JSJaCIQ();
iq.setType('get');
var iqQuery = iq.setQuery(NS_PRIVATE);
iqQuery.appendChild(iq.buildNode('storage', {'xmlns': type}));
con.send(iq, handleStorage);
}
// Handles the storage items
function handleStorage(iq) {
var handleXML = iq.getQuery();
var handleFrom = fullXID(getStanzaFrom(iq));
// Define some vars
var options = $(handleXML).find('storage[xmlns=' + NS_OPTIONS + ']');
var inbox = $(handleXML).find('storage[xmlns=' + NS_INBOX + ']');
var bookmarks = $(handleXML).find('storage[xmlns=' + NS_BOOKMARKS + ']');
var rosternotes = $(handleXML).find('storage[xmlns=' + NS_ROSTERNOTES + ']');
// No options and node not yet configured
if(options.size() && !options.find('option').size() && (iq.getType() != 'error'))
openWelcome();
// Parse the options xml
options.find('option').each(function() {
// We retrieve the informations
var type = $(this).attr('type');
var value = $(this).text();
// We display the storage
setDB('options', type, value);
// If this is the buddy list show status
if((type == 'roster-showall') && (value == '1'))
showAllBuddies('storage');
});
// Parse the inbox xml
inbox.find('message').each(function() {
storeInboxMessage(
$(this).attr('from'),
$(this).attr('subject'),
$(this).text(),
$(this).attr('status'),
$(this).attr('id'),
$(this).attr('date'),
[
$(this).attr('file_title'),
$(this).attr('file_href'),
$(this).attr('file_type'),
$(this).attr('file_length')
]
);
});
// Parse the bookmarks xml
bookmarks.find('conference').each(function() {
// We retrieve the informations
var xid = $(this).attr('jid');
var name = $(this).attr('name');
var autojoin = $(this).attr('autojoin');
var password = $(this).find('password').text();
var nick = $(this).find('nick').text();
// We display the storage
displayFavorites(xid, name, nick, autojoin, password);
// Join the chat if autojoin is enabled
if(autojoin == '1')
checkChatCreate(xid, 'groupchat', nick, password, name);
});
// Parse the roster notes xml
rosternotes.find('note').each(function() {
setDB('rosternotes', $(this).attr('jid'), $(this).text());
});
// Options received
if(options.size()) {
logThis('Options received.');
// Now, get the inbox
getStorage(NS_INBOX);
// Geolocate the user
geolocate();
$('.options-hidable').show();
}
// Inbox received
else if(inbox.size()) {
logThis('Inbox received.');
// Send the first presence!
firstPresence(getDB('checksum', 1));
// Check we have new messages (play a sound if any unread messages)
if(checkInboxMessages())
soundPlay(2);
$('.inbox-hidable').show();
}
// Bookmarks received
else if(bookmarks.size()) {
// Join the groupchats the admin defined (if any)
joinConfGroupchats();
logThis('Bookmarks received.');
}
// Roster notes received (for logger)
else if(rosternotes.size())
logThis('Roster notes received.');
}

View file

@ -0,0 +1,263 @@
/*
Jappix - An open social platform
These are the talkpage JS scripts for Jappix
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 06/05/11
*/
// Creates the talkpage events
function eventsTalkPage() {
// Launch all associated plugins
launchMicroblog();
launchRoster();
launchPresence();
launchPEP();
launchNotifications();
launchMusic();
}
// Creates the talkpage code
function createTalkPage() {
// Talkpage exists?
if(exists('#talk'))
return false;
// Anonymous detector
var anonymous = isAnonymous();
// Generate the HTML code
var html =
'<div id="talk" class="removable">' +
'<div id="top-content">' +
'<div class="tools tools-logo talk-images"></div>' +
'<div class="tools tools-all">';
if(!anonymous) html +=
'<a href="#" onclick="return openInbox();" class="inbox-hidable">' + _e("Messages") + '</a>' +
'<a href="#" onclick="return openVCard();">' + _e("Profile") + '</a>' +
'<a href="#" onclick="return optionsOpen();" class="options-hidable">' + _e("Options") + '</a>' +
'<a href="#" onclick="return normalQuit();">' + _e("Disconnect") + '</a>';
else html +=
'<a href="./">' + _e("Disconnect") + '</a>';
html +=
'</div>';
if(!anonymous && document.createElement('audio').canPlayType) html +=
'<div class="tools-all ibubble">' +
'<div class="tools music talk-images" onclick="return openMusic();"></div>' +
'<div class="music-content tools-content bubble hidable">' +
'<div class="tools-content-subarrow talk-images"></div>' +
'<div class="tools-content-subitem">' +
'<div class="player">' +
'<a href="#" class="stop talk-images" onclick="return actionMusic(\'stop\');"></a>' +
'</div>' +
'<div class="list">' +
'<p class="no-results">' + _e("No result!") + '</p>' +
'</div>' +
'<div class="search">' +
'<input type="text" />' +
'</div>' +
'</div>' +
'</div>' +
'</div>';
if(!anonymous) html +=
'<div class="tools-all ibubble">' +
'<div class="tools notifications talk-images" onclick="return showBubble(\'.notifications-content\');"></div>' +
'<div class="notifications-content tools-content bubble hidable">' +
'<div class="tools-content-subarrow talk-images"></div>' +
'<div class="tools-content-subitem">' +
'<a class="empty" href="#" onclick="return clearNotifications();">' + _e("Empty") + '</a>' +
'<p class="nothing">' + _e("No notifications.") + '</p>' +
'</div>' +
'</div>' +
'</div>';
html +=
'</div>' +
'<div id="main-content">' +
'<div id="left-content">';
if(!anonymous) html +=
'<div id="buddy-list">' +
'<div class="content"></div>' +
'<div class="filter">' +
'<input type="text" placeholder="' + _e("Filter") + '" />' +
'<a href="#">x</a>' +
'</div>' +
'<div class="foot ibubble">' +
'<div class="buddy-list-add buddy-list-icon">' +
'<a href="#" class="add talk-images" title="' + _e("Add a friend") + '"></a>' +
'</div>' +
'<div class="buddy-list-join buddy-list-icon">' +
'<a href="#" class="join talk-images" title="' + _e("Join a chat") + '"></a>' +
'</div>' +
'<div class="buddy-list-groupchat buddy-list-icon">' +
'<a href="#" class="groupchat talk-images" title="' + _e("Your groupchats") + '"></a>' +
'</div>' +
'<div class="buddy-list-more buddy-list-icon">' +
'<a href="#" class="more talk-images" title="' + _e("More stuff") + '"></a>' +
'</div>' +
'<div style="clear: both;"></div>' +
'</div>' +
'</div>';
html +=
'<div id="my-infos">' +
'<div class="content">' +
'<div class="element f-presence ibubble">' +
'<a href="#" class="icon picker disabled" data-value="available">' +
'<span class="talk-images"></span>' +
'</a>' +
'<input id="presence-status" type="text" placeholder="' + _e("Status") + '" disabled="" />' +
'</div>';
if(!anonymous) html +=
'<div class="element f-mood pep-hidable ibubble">' +
'<a href="#" class="icon picker" data-value="happy">' +
'<span class="talk-images"></span>' +
'</a>' +
'<input id="mood-text" type="text" placeholder="' + _e("Mood") + '" />' +
'</div>' +
'<div class="element f-activity pep-hidable ibubble">' +
'<a href="#" class="icon picker" data-value="exercising">' +
'<span class="talk-images activity-exercising"></span>' +
'</a>' +
'<input id="activity-text" type="text" placeholder="' + _e("Activity") + '" />' +
'</div>';
html +=
'</div>' +
'</div>' +
'</div>' +
'<div id="right-content">' +
'<div id="page-switch">' +
'<div class="chans">';
if(!anonymous) html +=
'<div class="channel switcher activechan" onclick="return switchChan(\'channel\');">' +
'<div class="icon talk-images"></div>' +
'<div class="name">' + _e("Channel") + '</div>' +
'</div>';
html +=
'</div>' +
'<div class="more ibubble">' +
'<div class="more-button talk-images" onclick="return loadChatSwitch();" title="' + _e("All tabs") + '"></div>' +
'</div>' +
'</div>' +
'<div id="page-engine">';
if(!anonymous) html +=
'<div id="channel" class="page-engine-chan" style="display: block;">' +
'<div class="top mixed ' + hex_md5(getXID()) + '">' +
'<div class="avatar-container">' +
'<img class="avatar" src="' + './img/others/default-avatar.png' + '" alt="" />' +
'</div>' +
'<div class="update">' +
'<p>' + _e("What\'s up with you?") + '</p>' +
'<div class="microblog-body">' +
'<input class="focusable" type="text" name="microblog_body" placeholder="' + _e("Type something you want to share with your friends...") + '" disabled="" />' +
'</div>' +
'<div class="one-microblog-icon ibubble">' +
'<a href="#" onclick="return showBubble(\'#attach\');" title="' + _e("Attach a file") + '" class="postit attach talk-images"></a>' +
'<form id="attach" class="bubble hidable" action="./php/file-share.php" method="post" enctype="multipart/form-data">' +
'<div class="attach-subarrow talk-images"></div>' +
'<div class="attach-subitem">' +
'<p class="attach-p">' + _e("Attach a file") + '</p>' +
generateFileShare() +
'</div>' +
'</form>' +
'</div>' +
'</div>' +
'</div>' +
'<div class="content mixed"></div>' +
'<div class="footer">' +
'<div class="sync talk-images">' + _e("You are synchronized with your network.") + '</div>' +
'<div class="unsync talk-images">' + _e("Cannot send anything: you can only receive notices!") + '</div>' +
'<div class="fetch wait-small">' + _e("Fetching the social channel...") + '</div>' +
'</div>' +
'</div>';
html +=
'</div>' +
'</div>' +
'</div>' +
'</div>';
// Create the HTML code
$('body').prepend(html);
// Adapt the buddy-list size
adaptRoster();
// Create JS events
eventsTalkPage();
// Start the auto idle functions
liveIdle();
return true;
}
// Destroys the talkpage code
function destroyTalkPage() {
// Reset our database
resetDB();
// Reset some vars
STANZA_ID = 1;
BLIST_ALL = false;
FIRST_PRESENCE_SENT = false;
SEARCH_FILTERED = false;
AVATAR_PENDING = [];
// Kill all timers, exept the board ones
$('*:not(#board .one-board)').stopTime();
// Kill the auto idle functions
dieIdle();
// We renitalise the html markup as its initiale look
$('.removable').remove();
pageTitle('home');
// Finally we show the homepage
$('#home').show();
}

View file

@ -0,0 +1,268 @@
/*
Jappix - An open social platform
These are the tooltip JS scripts for Jappix
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 27/08/11
*/
// Creates a tooltip code
function createTooltip(xid, hash, type) {
// Path to the element
var path = '#' + hash;
var path_tooltip = path + ' .chat-tools-' + type;
var path_bubble = path_tooltip + ' .bubble-' + type;
// Yet exists?
if(exists(path_bubble))
return false;
// Generates special tooltip HTML code
var title = '';
var content = '';
switch(type) {
// Smileys
case 'smileys':
title = _e("Smiley insertion");
content = smileyLinks(hash);
break;
// Style
case 'style':
title = _e("Change style");
content =
'<label class="bold"><input type="checkbox" class="bold" />' + _e("Text in bold") + '</label>' +
'<label class="italic"><input type="checkbox" class="italic" />' + _e("Text in italic") + '</label>' +
'<label class="underline"><input type="checkbox" class="underline" />' + _e("Underlined text") + '</label>' +
'<a href="#" class="color" style="background-color: #b10808; clear: both;" data-color="b10808"></a>' +
'<a href="#" class="color" style="background-color: #e5860c;" data-color="e5860c"></a>' +
'<a href="#" class="color" style="background-color: #f0f30e;" data-color="f0f30e"></a>' +
'<a href="#" class="color" style="background-color: #009a04;" data-color="009a04"></a>' +
'<a href="#" class="color" style="background-color: #0ba9a0;" data-color="0ba9a0"></a>' +
'<a href="#" class="color" style="background-color: #04228f;" data-color="04228f"></a>' +
'<a href="#" class="color" style="background-color: #9d0ab7;" data-color="9d0ab7"></a>' +
'<a href="#" class="color" style="background-color: #8a8a8a;" data-color="8a8a8a"></a>';
break;
// File send
case 'file':
title = _e("Send a file");
content = '<p style="margin-bottom: 8px;">' + _e("Once uploaded, your friend will be prompted to download the file you sent.") + '</p>';
content += '<form id="oob-upload" action="./php/send.php" method="post" enctype="multipart/form-data">' + generateFileShare() + '</form>';
break;
// Chat log
case 'save':
title = _e("Save chat");
content = '<p style="margin-bottom: 8px;">' + _e("Click on the following link to get the chat log, and wait. Then click again to get the file.") + '</p>';
// Possible to generate any log?
if($(path + ' .one-line').size())
content += '<a href="#" class="tooltip-actionlog">' + _e("Generate file!") + '</a>';
else
content += '<span class="tooltip-nolog">' + _e("This chat is empty!") + '</span>';
break;
}
// Generates general tooltip HTML code
var html =
'<div class="tooltip bubble-' + type + '">' +
'<div class="tooltip-subitem">' +
'<p class="tooltip-top">' + title + '</p>' +
content +
'</div>' +
'<div class="tooltip-subarrow talk-images"></div>' +
'</div>';
// Append the HTML code
$(path_tooltip).append(html);
// Special events
switch(type) {
// Smileys
case 'smileys':
// Apply click event on smiley links
$(path_tooltip + ' a.emoticon').click(function() {
return insertSmiley($(this).attr('data-smiley'), hash);
});
break;
// Style
case 'style':
// Paths to items
var message_area = path + ' .message-area';
var bubble_style = path_tooltip + ' .bubble-style ';
var style = bubble_style + 'input:checkbox';
var colors = bubble_style + 'a.color';
// Click event on color picker
$(colors).click(function() {
// The clicked color is yet selected
if($(this).hasClass('selected')) {
$(message_area).removeAttr('data-color');
$(this).removeClass('selected');
}
else {
$(message_area).attr('data-color', $(this).attr('data-color'));
$(colors).removeClass('selected');
$(this).addClass('selected');
}
return false;
});
// Change event on text style checkboxes
$(style).change(function() {
// Get current type
var style_data = 'data-' + $(this).attr('class');
// Checked checkbox?
if($(this).filter(':checked').size())
$(message_area).attr(style_data, true);
else
$(message_area).removeAttr(style_data);
});
// Update the textarea style when it is changed
$(style + ', ' + colors).click(function() {
var style = generateStyle(hash);
// Any style to apply?
if(style)
$(message_area).attr('style', style);
else
$(message_area).removeAttr('style');
// Focus again on the message textarea
$(document).oneTime(10, function() {
$(message_area).focus();
});
});
// Load current style
loadStyleSelector(hash);
break;
// File send
case 'file':
// File upload vars
var oob_upload_options = {
dataType: 'xml',
beforeSubmit: waitUploadOOB,
success: handleUploadOOB
};
// Upload form submit event
$(path_tooltip + ' #oob-upload').submit(function() {
if($(path_tooltip + ' #oob-upload input[type=file]').val())
$(this).ajaxSubmit(oob_upload_options);
return false;
});
// Upload input change event
$(path_tooltip + ' #oob-upload input[type=file]').change(function() {
if($(this).val())
$(path_tooltip + ' #oob-upload').ajaxSubmit(oob_upload_options);
return false;
});
// Input click event
$(path_tooltip + ' #oob-upload input[type=file], ' + path_tooltip + ' #oob-upload input[type=submit]').click(function() {
if(exists(path_tooltip + ' #oob-upload input[type=reset]'))
return;
// Lock the bubble
$(path_bubble).addClass('locked');
// Add a cancel button
$(this).after('<input type="reset" value="' + _e("Cancel") + '" />');
// Cancel button click event
$(path_tooltip + ' #oob-upload input[type=reset]').click(function() {
// Remove the bubble
$(path_bubble).removeClass('locked');
destroyTooltip(hash, 'file');
});
});
break;
// Chat log
case 'save':
// Chat log generation click event
$(path_tooltip + ' .tooltip-actionlog').click(function() {
// Replace it with a waiting notice
$(this).replaceWith('<span class="tooltip-waitlog">' + _e("Please wait...") + '</span>');
generateChatLog(xid, hash);
return false;
});
break;
}
return true;
}
// Destroys a tooltip code
function destroyTooltip(hash, type) {
$('#' + hash + ' .chat-tools-content:not(.mini) .bubble-' + type + ':not(.locked)').remove();
}
// Applies the page-engine tooltips hover event
function hoverTooltip(xid, hash, type) {
$('#' + hash + ' .chat-tools-' + type).hover(function() {
createTooltip(xid, hash, type);
}, function() {
destroyTooltip(hash, type)
});
}
// Applies the hoverTooltip function to the needed things
function tooltipIcons(xid, hash) {
// Hover events
hoverTooltip(xid, hash, 'smileys');
hoverTooltip(xid, hash, 'style');
hoverTooltip(xid, hash, 'file');
hoverTooltip(xid, hash, 'save');
// Click events
$('#' + hash + ' a.chat-tools-content, #' + hash + ' .chat-tools-content a').click(function() {
return false;
});
}
// Loads the style selector options
function loadStyleSelector(hash) {
// Define the vars
var path = '#' + hash;
var message_area = $(path + ' .message-area');
var bubble_style = path + ' .bubble-style';
// Apply the options to the style selector
$(bubble_style + ' input[type=checkbox]').each(function() {
// Current input enabled?
if(message_area.attr('data-' + $(this).attr('class')))
$(this).attr('checked', true);
});
// Apply message color
$(bubble_style + ' a.color[data-color=' + message_area.attr('data-color') + ']').addClass('selected');
}

View file

@ -0,0 +1,426 @@
/*
Jappix - An open social platform
These are the user-infos JS scripts for Jappix
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 27/03/11
*/
// Opens the user-infos popup
function openUserInfos(xid) {
// Can show shortcuts?
var shortcuts = '';
if(xid != getXID()) {
shortcuts = '<div class="shortcuts">' +
'<a href="#" class="message talk-images" title="' + _e("Send him/her a message") + '" onclick="closeUserInfos(); return composeInboxMessage(\'' + encodeOnclick(xid) + '\');"></a>' +
'<a href="#" class="chat talk-images" title="' + _e("Start a chat with him/her") + '" onclick="closeUserInfos(); return checkChatCreate(\'' + encodeOnclick(xid) + '\', \'chat\');"></a>' +
'<a href="#" class="command talk-images" title="' + _e("Command") + '" onclick="closeUserInfos(); return retrieveAdHoc(\'' + encodeOnclick(xid) + '\');"></a>' +
'</div>';
}
// Popup HTML content
var html =
'<div class="top">' + _e("User profile") + '</div>' +
'<div class="tab">' +
'<a href="#" class="tab-active" data-key="1">' + _e("General") + '</a>' +
'<a href="#" data-key="2">' + _e("Advanced") + '</a>' +
'<a href="#" data-key="3">' + _e("Comments") + '</a>' +
'</div>' +
'<div class="content">' +
'<div class="lap-active one-lap info1">' +
'<div class="main-infos">' +
'<div class="avatar-container">' +
'<img class="avatar" src="' + './img/others/default-avatar.png' + '" alt="" />' +
'</div>' +
'<h1 id="BUDDY-FN" class="reset-info">' + _e("unknown") + '</h1>' +
'<h2 class="buddy-xid" class="reset-info">' + _e("unknown") + '</h2>' +
'<h3 class="buddy-last" class="reset-info">' + _e("unknown") + '</h3>' +
shortcuts +
'</div>' +
'<div class="block-infos">' +
'<div class="one-line"><b>' + _e("Date of birth") + '</b><span id="BUDDY-BDAY" class="reset-info">' + _e("unknown") + '</span></div>' +
'<div class="one-line"><b>' + _e("E-mail") + '</b><span id="BUDDY-EMAIL-USERID" class="reset-info">' + _e("unknown") + '</span></div>' +
'<div class="one-line"><b>' + _e("Phone") + '</b><span id="BUDDY-TEL-NUMBER" class="reset-info">' + _e("unknown") + '</span></div>' +
'<div class="one-line"><b>' + _e("Website") + '</b><span id="BUDDY-URL" class="reset-info">' + _e("unknown") + '</span></div>' +
'</div>' +
'<div class="block-infos">' +
'<div class="one-line"><b>' + _e("Client") + '</b><span id="BUDDY-CLIENT" class="reset-info">' + _e("unknown") + '</span></div>' +
'<div class="one-line"><b>' + _e("System") + '</b><span id="BUDDY-SYSTEM" class="reset-info">' + _e("unknown") + '</span></div>' +
'<div class="one-line"><b>' + _e("Local time") + '</b><span id="BUDDY-TIME" class="reset-info">' + _e("unknown") + '</span></div>' +
'</div>' +
'</div>' +
'<div class="one-lap info2">' +
'<div class="block-infos">' +
'<div class="one-line"><b>' + _e("Street") + '</b><span id="BUDDY-ADR-STREET" class="reset-info">' + _e("unknown") + '</span></div>' +
'<div class="one-line"><b>' + _e("City") + '</b><span id="BUDDY-ADR-LOCALITY" class="reset-info">' + _e("unknown") + '</span></div>' +
'<div class="one-line"><b>' + _e("Postal code") + '</b><span id="BUDDY-ADR-PCODE" class="reset-info">' + _e("unknown") + '</span></div>' +
'<div class="one-line"><b>' + _e("Country") + '</b><span id="BUDDY-ADR-CTRY" class="reset-info">' + _e("unknown") + '</span></div>' +
'</div>' +
'<div class="block-infos">' +
'<div class="one-line"><b>' + _e("Biography") + '</b><span id="BUDDY-DESC" class="reset-info">' + _e("unknown") + '</span></div>' +
'</div>' +
'</div>' +
'<div class="one-lap info3">' +
'<textarea class="rosternotes" rows="8" cols="60"></textarea>' +
'</div>' +
'</div>' +
'<div class="bottom">' +
'<div class="wait wait-medium"></div>' +
'<a href="#" class="finish">' + _e("Close") + '</a>' +
'</div>';
// Create the popup
createPopup('userinfos', html);
// Associate the events
launchUserInfos();
// We retrieve the user's vcard
retrieveUserInfos(xid);
return false;
}
// Closes the user-infos popup
function closeUserInfos() {
// Send the buddy comments
sendBuddyComments();
// Destroy the popup
destroyPopup('userinfos');
return false;
}
// Gets the user-infos
function retrieveUserInfos(xid) {
// We setup the waiting indicator
markers = 'vcard last';
// We put the user's XID
$('#userinfos .buddy-xid').text(xid);
// We get the vCard
getVCard(xid, 'buddy');
// Get the highest resource for this XID
var cXID = getHighestResource(xid);
var pXID = xid;
// If the user is logged in
if(cXID) {
// Change the XID
pXID = cXID;
// We request the user's system infos
queryUserInfos(cXID, 'version')
// We request the user's local time
queryUserInfos(cXID, 'time')
// Add these to the markers
markers += ' version time';
}
// We request the user's last activity
queryUserInfos(pXID, 'last');
// Add the markers
$('#userinfos .content').addClass(markers);
// We request all the user's comments
displayBuddyComments(xid);
}
// Builds the asked user-infos query
function queryUserInfos(xid, mode) {
// Generate a session ID
var id = genID();
$('#userinfos').attr('data-' + mode, id);
// New IQ
var iq = new JSJaCIQ();
iq.setID(id);
iq.setType('get');
iq.setTo(xid);
// Last activity query
if(mode == 'last') {
iq.setQuery(NS_LAST);
con.send(iq, lastActivityUserInfos);
}
// Time query
else if(mode == 'time') {
iq.appendNode('time', {'xmlns': NS_URN_TIME});
con.send(iq, localTimeUserInfos);
}
// Version query
else if(mode == 'version') {
iq.setQuery(NS_VERSION);
con.send(iq, versionUserInfos);
}
}
// Checks if the waiting item can be hidden
function vCardBuddyInfos() {
$('#userinfos .content').removeClass('vcard');
wUserInfos();
}
// Displays the buddy comments
function displayBuddyComments(xid) {
// We get the value in the database
var value = getDB('rosternotes', xid);
// Display the value
if(value)
$('#userinfos .rosternotes').val(value);
}
// Displays the user's last activity result
function lastActivityUserInfos(iq) {
// Extract the request ID
var id = iq.getID();
var path = '#userinfos[data-last=' + id + ']';
// End if session does not exist
if(!exists(path))
return;
if(iq && (iq.getType() == 'result')) {
// Get the values
var from = fullXID(getStanzaFrom(iq));
var seconds = $(iq.getNode()).find('query').attr('seconds');
// Any seconds?
if(seconds != undefined) {
// Initialize the parsing
var last;
seconds = parseInt(seconds);
// Active user
if(seconds <= 60)
last = _e("User currently active");
// Inactive user
else {
// Parse the date
var date_now = new Date();
var time_now = date_now.getTime();
var date_last = new Date(date_now - (seconds * 1000));
var date = date_last.toLocaleString();
// Offline user
if(from.indexOf('/') == -1)
last = printf(_e("Last seen: %s"), date);
// Online user
else
last = printf(_e("Inactive since: %s"), date);
}
// Append this text
$('#userinfos .buddy-last').text(last);
}
logThis('Last activity received: ' + from);
}
$('#userinfos .content').removeClass('last');
wUserInfos();
}
// Displays the user's software version result
function versionUserInfos(iq) {
// Extract the request ID
var id = iq.getID();
var path = '#userinfos[data-version=' + id + ']';
// End if session does not exist
if(!exists(path))
return;
// Extract the reply data
if(iq && (iq.getType() == 'result')) {
// Get the values
var xml = iq.getQuery();
var name = $(xml).find('name').text();
var version = $(xml).find('version').text();
var os = $(xml).find('os').text();
// Put the values together
if(name && version)
name = name + ' ' + version;
// Display the values
if(name)
$(path + ' #BUDDY-CLIENT').text(name);
if(os)
$(path + ' #BUDDY-SYSTEM').text(os);
logThis('Software version received: ' + fullXID(getStanzaFrom(iq)));
}
$('#userinfos .content').removeClass('version');
wUserInfos();
}
// Displays the user's local time result
function localTimeUserInfos(iq) {
// Extract the request ID
var id = iq.getID();
var path = '#userinfos[data-time=' + id + ']';
// End if session does not exist
if(!exists(path))
return;
if(iq && (iq.getType() == 'result')) {
// Get the values
var xml = iq.getNode();
var tzo = $(xml).find('tzo').text();
var utc = $(xml).find('utc').text();
// Any UTC?
if(utc) {
// Add the TZO if there's no one
if(tzo && utc.match(/^(.+)Z$/))
utc = RegExp.$1 + tzo;
// Get the local date string
var local_string = Date.hrTime(utc);
// Then display it
$(path + ' #BUDDY-TIME').text(local_string);
}
logThis('Local time received: ' + fullXID(getStanzaFrom(iq)));
}
$('#userinfos .content').removeClass('time');
wUserInfos();
}
// Hides the waiting image if needed
function wUserInfos() {
var selector = $('#userinfos .content');
if(!selector.hasClass('vcard') && !selector.hasClass('last') && !selector.hasClass('version') && !selector.hasClass('time'))
$('#userinfos .wait').hide();
}
// Sends the buddy comments
function sendBuddyComments() {
// Update the current value
var value = $('#userinfos .rosternotes').val();
var xid = $('#userinfos .buddy-xid').text();
// Necessary to update?
var old_value = getDB('rosternotes', xid);
if((old_value == value) || (!old_value && !value))
return false;
// Update the database
setDB('rosternotes', xid, value);
// Send the new buddy storage values
var iq = new JSJaCIQ();
iq.setType('set');
var query = iq.setQuery(NS_PRIVATE);
var storage = query.appendChild(iq.buildNode('storage', {'xmlns': NS_ROSTERNOTES}));
// We regenerate the XML
for(var i = 0; i < sessionStorage.length; i++) {
// Get the pointer values
var current = sessionStorage.key(i);
// If the pointer is on a stored rosternote
if(explodeThis('_', current, 0) == 'rosternotes') {
var xid = explodeThis('_', current, 1);
var value = sessionStorage.getItem(current);
if(xid && value)
storage.appendChild(iq.buildNode('note', {'jid': xid, 'xmlns': NS_ROSTERNOTES}, value));
}
}
con.send(iq);
return false;
}
// Switches the user-infos tabs
function switchUInfos(id) {
$('#userinfos .content .one-lap').hide();
$('#userinfos .content .info' + id).show();
$('#userinfos .tab a').removeClass('tab-active');
$('#userinfos .tab a[data-key=' + id + ']').addClass('tab-active');
return false;
}
// Gets the user's informations when creating a new chat
function getUserInfos(hash, xid, nick, type) {
// This is a normal chat
if(type != 'private') {
// Display the buddy name
if(nick) {
$('#' + hash + ' .top .name .bc-name').text(nick);
$('#page-switch .' + hash + ' .name').text(nick);
}
// Get the buddy PEP informations
displayAllPEP(xid);
}
// Display the buddy presence
presenceFunnel(xid, hash);
}
// Plugin launcher
function launchUserInfos() {
// Click events
$('#userinfos .tab a').click(function() {
// Yet active?
if($(this).hasClass('tab-active'))
return false;
// Switch to the good tab
var key = parseInt($(this).attr('data-key'));
return switchUInfos(key);
});
$('#userinfos .bottom .finish').click(function() {
return closeUserInfos();
});
}

View file

@ -0,0 +1,437 @@
/*
Jappix - An open social platform
These are the utilities JS script for Jappix
-------------------------------------------------
License: AGPL
Authors: Vanaryon, olivierm
Last revision: 24/06/11
*/
// Checks if a function exists
function functionExists(func) {
if(typeof func == 'function')
return true;
return false;
}
// Returns whether using HTTPS or not
function isHTTPS() {
if(window.location.href && (window.location.href).match(/^https/i))
return true;
return false;
}
// Generates the good storage URL
function generateURL(url) {
// HTTPS not allowed
if((HTTPS_STORAGE != 'on') && url.match(/^https(.+)/))
url = 'http' + RegExp.$1;
return url;
}
// Disables an input if needed
function disableInput(value, condition) {
if(value == condition)
return ' disabled=""';
return '';
}
// Cuts a string
function cut(string, limit) {
return string.substr(0, limit);
}
// Truncates a string
function truncate(string, limit) {
// Must truncate the string
if(string.length > limit)
string = string.substr(0, limit) + '...';
return string;
}
// Removes the new lines
function noLines(string) {
return string.replace(/\n/g, ' ');
}
// Encodes a string for onclick attribute
function encodeOnclick(str) {
return (encodeQuotes(str)).replace(/'/g, '\\$&');
}
// Checks if we are in the anonymous mode
function isAnonymous() {
if(allowedAnonymous() && LINK_VARS['r'])
return true;
return false;
}
// Checks if this is a private chat user
function isPrivate(xid) {
if(exists('[data-xid=' + escape(xid) + '][data-type=groupchat]'))
return true;
return false;
}
// Checks if the user browser is obsolete
function isObsolete() {
// Get browser name & version
var browser_name = BrowserDetect.browser;
var browser_version = BrowserDetect.version;
// No DOM storage
if(!hasDB() || !hasPersistent())
return true;
// Obsolete IE
if((browser_name == 'Explorer') && (browser_version < 8))
return true;
// Obsolete Chrome
if((browser_name == 'Chrome') && (browser_version < 7))
return true;
// Obsolete Safari
if((browser_name == 'Safari') && (browser_version < 4))
return true;
// Obsolete Firefox
if((browser_name == 'Firefox') && (browser_version < 3.5))
return true;
// Obsolete Opera
if((browser_name == 'Opera') && (browser_version < 9))
return true;
return false;
}
// Gets a MUC user XID
function getMUCUserXID(room, nick) {
return $('div.chat[data-xid=' + escape(room) + '] div[data-nick=' + escape(nick) + ']').attr('data-xid');
}
// Gets a MUC user read XID
function getMUCUserRealXID(room, nick) {
return $('div.chat[data-xid=' + escape(room) + '] div[data-nick=' + escape(nick) + ']').attr('data-realxid');
}
// Gets the server of the user
function getServer() {
// Return the domain of the user
return con.domain;
}
// Gets the password of the user
function getPassword() {
// Return the password of the user
return con.pass;
}
// Quotes the nick of an user
function quoteMyNick(hash, nick) {
$(document).oneTime(10, function() {
$('#page-engine #' + hash + ' .message-area').val(nick + ', ').focus();
});
}
// Escapes a string for a regex usage
function escapeRegex(query) {
return query.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
}
// Converts a XML document to a string
function xmlToString(xmlData) {
try {
// For Mozilla, Firefox, Opera, etc.
if(window.XMLSerializer)
return (new XMLSerializer()).serializeToString(xmlData);
// For Internet Explorer
if(window.ActiveXObject)
return xmlData.xml;
return null;
}
catch(e) {
return null;
}
}
// Converts a string to a XML document
function XMLFromString(sXML) {
try {
// No data?
if(!sXML)
return '';
// Add the XML tag
if(!sXML.match(/^<\?xml/i))
sXML = '<?xml version="1.0"?>' + sXML;
// Parse it!
if(window.DOMParser)
return (new DOMParser()).parseFromString(sXML, 'text/xml');
if(window.ActiveXObject) {
var oXML = new ActiveXObject('Microsoft.XMLDOM');
oXML.loadXML(sXML);
return oXML;
}
}
catch(e) {
return '';
}
}
// Return the file category
function fileCategory(ext) {
var cat;
switch(ext) {
// Images
case 'jpg':
case 'jpeg':
case 'png':
case 'bmp':
case 'gif':
case 'tif':
case 'svg':
case 'psp':
case 'xcf':
cat = 'image';
break;
// Videos
case 'ogv':
case 'ogg':
case 'mkv':
case 'avi':
case 'mov':
case 'mp4':
case 'm4v':
case 'wmv':
case 'asf':
case 'mpg':
case 'mpeg':
case 'ogm':
case 'rmvb':
case 'rmv':
case 'qt':
case 'flv':
case 'ram':
case '3gp':
case 'avc':
cat = 'video';
break;
// Sounds
case 'oga':
case 'mka':
case 'flac':
case 'mp3':
case 'wav':
case 'm4a':
case 'wma':
case 'rmab':
case 'rma':
case 'bwf':
case 'aiff':
case 'caf':
case 'cda':
case 'atrac':
case 'vqf':
case 'au':
case 'aac':
case 'm3u':
case 'mid':
case 'mp2':
case 'snd':
case 'voc':
cat = 'audio';
break;
// Documents
case 'pdf':
case 'odt':
case 'ott':
case 'sxw':
case 'stw':
case 'ots':
case 'sxc':
case 'stc':
case 'sxi':
case 'sti':
case 'pot':
case 'odp':
case 'ods':
case 'doc':
case 'docx':
case 'docm':
case 'xls':
case 'xlsx':
case 'xlsm':
case 'xlt':
case 'ppt':
case 'pptx':
case 'pptm':
case 'pps':
case 'odg':
case 'otp':
case 'sxd':
case 'std':
case 'std':
case 'rtf':
case 'txt':
case 'htm':
case 'html':
case 'shtml':
case 'dhtml':
case 'mshtml':
cat = 'document';
break;
// Packages
case 'tgz':
case 'gz':
case 'tar':
case 'ar':
case 'cbz':
case 'jar':
case 'tar.7z':
case 'tar.bz2':
case 'tar.gz':
case 'tar.lzma':
case 'tar.xz':
case 'zip':
case 'xz':
case 'rar':
case 'bz':
case 'deb':
case 'rpm':
case '7z':
case 'ace':
case 'cab':
case 'arj':
case 'msi':
cat = 'package';
break;
// Others
default:
cat = 'other';
break;
}
return cat;
}
// Registers Jappix as the default XMPP links handler
function xmppLinksHandler() {
try {
navigator.registerProtocolHandler('xmpp', JAPPIX_LOCATION + '?x=%s', SERVICE_NAME);
return true;
}
catch(e) {
return false;
}
}
// Checks if a value exists in an array
function existArrayValue(array, value) {
try {
// Loop in the array
for(i in array) {
if(array[i] == value)
return true;
}
return false;
}
catch(e) {
return false;
}
}
// Removes a value from an array
function removeArrayValue(array, value) {
for(i in array) {
// It matches, remove it!
if(array[i] == value) {
array.splice(i, 1);
return true;
}
}
return false;
}
// Converts a string to an array
function stringToArray(string) {
var array = [];
// Any string to convert?
if(string) {
// More than one item
if(string.match(/,/gi)) {
var string_split = string.split(',');
for(i in string_split) {
if(string_split[i])
array.push(string_split[i]);
else
array.push('');
}
}
// Only one item
else
array.push(string);
}
return array;
}
// Get the index of an array value
function indexArrayValue(array, value) {
// Nothing?
if(!array || !array.length)
return 0;
// Read the index of the value
var index = 0;
for(var i = 0; i < array.length; i++) {
if(array[i] == value) {
index = i;
break;
}
}
return index;
}

View file

@ -0,0 +1,630 @@
/*
Jappix - An open social platform
These are the vCard JS scripts for Jappix
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 16/01/12
*/
// Opens the vCard popup
function openVCard() {
// Popup HTML content
var html =
'<div class="top">' + _e("Your profile") + '</div>' +
'<div class="tab">' +
'<a href="#" class="tab-active" data-key="1">' + _e("Identity") + '</a>' +
'<a href="#" data-key="2">' + _e("Profile image") + '</a>' +
'<a href="#" data-key="3">' + _e("Others") + '</a>' +
'</div>' +
'<div class="content">' +
'<div id="lap1" class="lap-active one-lap forms">' +
'<fieldset>' +
'<legend>' + _e("Personal") + '</legend>' +
'<label for="USER-FN">' + _e("Complete name") + '</label>' +
'<input type="text" id="USER-FN" class="vcard-item" />' +
'<label for="USER-NICKNAME">' + _e("Nickname") + '</label>' +
'<input type="text" id="USER-NICKNAME" class="vcard-item" />' +
'<label for="USER-N-GIVEN">' + _e("First name") + '</label>' +
'<input type="text" id="USER-N-GIVEN" class="vcard-item" />' +
'<label for="USER-N-FAMILY">' + _e("Last name") + '</label>' +
'<input type="text" id="USER-N-FAMILY" class="vcard-item" />' +
'<label for="USER-BDAY">' + _e("Date of birth") + '</label>' +
'<input type="text" id="USER-BDAY" class="vcard-item" />' +
'</fieldset>' +
'<fieldset>' +
'<legend>' + _e("Contact") + '</legend>' +
'<label for="USER-EMAIL-USERID">' + _e("E-mail") + '</label>' +
'<input type="text" id="USER-EMAIL-USERID" class="vcard-item" />' +
'<label for="USER-TEL-NUMBER">' + _e("Phone") + '</label>' +
'<input type="text" id="USER-TEL-NUMBER" class="vcard-item" />' +
'<label for="USER-URL">' + _e("Website") + '</label>' +
'<input type="text" id="USER-URL" class="vcard-item" />' +
'</fieldset>' +
'</div>' +
'<div id="lap2" class="one-lap forms">' +
'<fieldset>' +
'<legend>' + _e("New") + '</legend>' +
'<input type="hidden" id="USER-PHOTO-TYPE" class="vcard-item" />' +
'<input type="hidden" id="USER-PHOTO-BINVAL" class="vcard-item" />' +
'<form id="vcard-avatar" action="./php/avatar-upload.php" method="post" enctype="multipart/form-data">' +
generateFileShare() +
'</form>' +
'</fieldset>' +
'<fieldset>' +
'<legend>' + _e("Current") + '</legend>' +
'<div class="avatar-container"></div>' +
'<a href="#" class="one-button avatar-delete talk-images">' + _e("Delete") + '</a>' +
'<div class="no-avatar">' + _e("What a pity! You have no profile image defined in your identity card!") + '</div>' +
'</fieldset>' +
'<div class="avatar-wait avatar-info">' + _e("Please wait while your avatar is uploaded...") + '</div>' +
'<div class="avatar-ok avatar-info">' + _e("Here it is! A new beautiful profile image!") + '</div>' +
'<div class="avatar-error avatar-info">' + _e("The image file is not supported or has a bad size.") + '</div>' +
'</div>' +
'<div id="lap3" class="one-lap forms">' +
'<fieldset>' +
'<legend>' + _e("Address") + '</legend>' +
'<label for="USER-ADR-STREET">' + _e("Street") + '</label>' +
'<input type="text" id="USER-ADR-STREET" class="vcard-item" />' +
'<label for="USER-ADR-LOCALITY">' + _e("City") + '</label>' +
'<input type="text" id="USER-ADR-LOCALITY" class="vcard-item" />' +
'<label for="USER-ADR-PCODE">' + _e("Postal code") + '</label>' +
'<input type="text" id="USER-ADR-PCODE" class="vcard-item" />' +
'<label for="USER-ADR-CTRY">' + _e("Country") + '</label>' +
'<input type="text" id="USER-ADR-CTRY" class="vcard-item" />' +
'</fieldset>' +
'<fieldset>' +
'<legend>' + _e("Biography") + '</legend>' +
'<textarea id="USER-DESC" rows="8" cols="60" class="vcard-item"></textarea>' +
'</fieldset>' +
'</div>' +
'<div class="infos">' +
'<p class="infos-title">' + _e("Important notice") + '</p>' +
'<p>' + _e("Be careful of the information you write into your profile, because it could be accessed by everyone (even someone you don't want to).") + '</p>' +
'<p>' + _e("Not everything is private on XMPP; this is one of those things, your public profile (vCard).") + '</p>' +
'<p>' + printf(_e("It is strongly recommended to upload a profile image (%s maximum), like a picture of yourself, because that makes you easily recognizable by your friends."), JAPPIX_MAX_UPLOAD) + '</p>' +
'<p><a href="https://me.jappix.com/new" target="_blank">' + _e("Enable my public profile") + ' »</a></p>' +
'</div>' +
'</div>' +
'<div class="bottom">' +
'<div class="wait wait-medium"></div>' +
'<a href="#" class="finish save disabled">' + _e("Save") + '</a>' +
'<a href="#" class="finish cancel">' + _e("Cancel") + '</a>' +
'</div>';
// Create the popup
createPopup('vcard', html);
// Associate the events
launchVCard();
// We get the VCard informations
getVCard(getXID(), 'user');
return false;
}
// Closes the vCard popup
function closeVCard() {
// Destroy the popup
destroyPopup('vcard');
// Create the welcome end popup?
if(END_WELCOME)
openMe();
return false;
}
// Switches the vCard popup tabs
function switchVCard(id) {
$('#vcard .one-lap').removeClass('lap-active');
$('#vcard #lap' + id).addClass('lap-active');
$('#vcard .tab a').removeClass('tab-active');
$('#vcard .tab a[data-key=' + id + ']').addClass('tab-active');
return false;
}
// Waits for the avatar upload reply
function waitAvatarUpload() {
// Reset the avatar info
$('#vcard .avatar-info').hide().stopTime();
// Show the wait info
$('#vcard .avatar-wait').show();
}
// Handles the avatar upload reply
function handleAvatarUpload(responseXML) {
// Data selector
var dData = $(responseXML).find('jappix');
// Not current upload session?
if(parseInt(dData.attr('id')) != parseInt($('#vcard-avatar input[name=id]').val()))
return;
// Reset the avatar info
$('#vcard .avatar-info').hide().stopTime();
// Process the returned data
if(!dData.find('error').size()) {
// Read the values
var aType = dData.find('type').text();
var aBinval = dData.find('binval').text();
// We remove everything that isn't useful right here
$('#vcard .no-avatar').hide();
$('#vcard .avatar').remove();
// We display the delete button
$('#vcard .avatar-delete').show();
// We tell the user it's okay
$('#vcard .avatar-ok').show();
// Timer
$('#vcard .avatar-info').oneTime('10s', function() {
$(this).hide();
});
// We put the base64 values in a hidden input to be sent
$('#USER-PHOTO-TYPE').val(aType);
$('#USER-PHOTO-BINVAL').val(aBinval);
// We display the avatar !
$('#vcard .avatar-container').replaceWith('<div class="avatar-container"><img class="avatar" src="data:' + aType + ';base64,' + aBinval + '" alt="" /></div>');
}
// Any error?
else {
$('#vcard .avatar-error').show();
// Timer
$('#vcard .avatar-info').oneTime('10s', function() {
$(this).hide();
});
logThis('Error while uploading the avatar: ' + dData.find('error').text(), 1);
}
}
// Deletes the encoded avatar of an user
function deleteAvatar() {
// We remove the avatar displayed elements
$('#vcard .avatar-info').stopTime();
$('#vcard .avatar-info, #vcard .avatar-wait, #vcard .avatar-error, #vcard .avatar-ok, #vcard .avatar-delete').hide();
$('#vcard .avatar').remove();
// We reset the input value
$('#USER-PHOTO-TYPE, #USER-PHOTO-BINVAL').val('');
// We show the avatar-uploading request
$('#vcard .no-avatar').show();
return false;
}
// Creates a special vCard input
function createInputVCard(id, type) {
// Generate the new ID
id = 'USER-' + id;
// Can append the content
if((type == 'user') && !exists('#vcard #' + id))
$('#vcard .content').append('<input id="' + id + '" class="vcard-item" type="hidden" />');
}
// Gets the vCard of a XID
function getVCard(to, type) {
// Generate a special ID
var id = genID();
// New IQ
var iq = new JSJaCIQ();
iq.setID(id);
iq.setType('get');
iq.appendNode('vCard', {'xmlns': NS_VCARD});
// Send the IQ to the good user
if(type == 'user') {
// Show the wait icon
$('#vcard .wait').show();
// Apply the session ID
$('#vcard').attr('data-vcard', id);
// Send the IQ
con.send(iq, handeUVCard);
}
else {
// Show the wait icon
$('#userinfos .wait').show();
// Apply the session ID
$('#userinfos').attr('data-vcard', id);
// Send the IQ
iq.setTo(to);
con.send(iq, handeBVCard);
}
}
// Handles the current connected user's vCard
function handeUVCard(iq) {
handleVCard(iq, 'user');
}
// Handles an external buddy vCard
function handeBVCard(iq) {
handleVCard(iq, 'buddy');
}
// Handles a vCard stanza
function handleVCard(iq, type) {
// Extract the data
var iqID = iq.getID();
var iqFrom = fullXID(getStanzaFrom(iq));
var iqNode = iq.getNode();
// Define some paths
var path_vCard = '#vcard[data-vcard=' + iqID + ']';
var path_userInfos = '#userinfos[data-vcard=' + iqID + ']';
// End if the session does not exist
if(((type == 'user') && !exists(path_vCard)) || ((type == 'buddy') && !exists(path_userInfos)))
return;
// We retrieve main values
var values_yet = [];
$(iqNode).find('vCard').children().each(function() {
// Read the current parent node name
var tokenname = (this).nodeName.toUpperCase();
// Node with a parent
if($(this).children().size()) {
$(this).children().each(function() {
// Get the node values
var currentID = tokenname + '-' + (this).nodeName.toUpperCase();
var currentText = $(this).text();
// Not yet added?
if(!existArrayValue(values_yet, currentID)) {
// Create an input if it does not exist
createInputVCard(values_yet, type);
// Userinfos viewer popup
if((type == 'buddy') && currentText) {
if(currentID == 'EMAIL-USERID')
$(path_userInfos + ' #BUDDY-' + currentID).html('<a href="mailto:' + currentText.htmlEnc() + '" target="_blank">' + currentText.htmlEnc() + '</a>');
else
$(path_userInfos + ' #BUDDY-' + currentID).text(currentText.htmlEnc());
}
// Profile editor popup
else if(type == 'user')
$(path_vCard + ' #USER-' + currentID).val(currentText);
// Avoid duplicating the value
values_yet.push(currentID);
}
});
}
// Node without any parent
else {
// Get the node values
var currentText = $(this).text();
// Not yet added?
if(!existArrayValue(values_yet, tokenname)) {
// Create an input if it does not exist
createInputVCard(tokenname, type);
// Userinfos viewer popup
if((type == 'buddy') && currentText) {
// URL modification
if(tokenname == 'URL') {
// No http:// or https:// prefix, we should add it
if(!currentText.match(/^https?:\/\/(.+)/))
currentText = 'http://' + currentText;
currentText = '<a href="' + currentText + '" target="_blank">' + currentText.htmlEnc() + '</a>';
}
// Description modification
else if(tokenname == 'DESC')
currentText = filterThisMessage(currentText, getBuddyName(iqFrom).htmlEnc(), true);
// Other stuffs
else
currentText = currentText.htmlEnc();
$(path_userInfos + ' #BUDDY-' + tokenname).html(currentText);
}
// Profile editor popup
else if(type == 'user')
$(path_vCard + ' #USER-' + tokenname).val(currentText);
// Avoid duplicating the value
values_yet.push(tokenname);
}
}
});
// Update the stored avatar
if(type == 'buddy') {
// Get the avatar XML
var xml = getPersistent('avatar', iqFrom);
// If there were no stored avatar previously
if($(XMLFromString(xml)).find('type').text() == 'none') {
xml = xml.replace(/<forced>false<\/forced>/gi, '<forced>true</forced>');
setPersistent('avatar', iqFrom, xml);
}
// Handle the user avatar
handleAvatar(iq);
}
// The avatar values targets
var aBinval, aType, aContainer;
if(type == 'user') {
aBinval = $('#USER-PHOTO-BINVAL').val();
aType = $('#USER-PHOTO-TYPE').val();
aContainer = path_vCard + ' .avatar-container';
}
else {
aBinval = $(iqNode).find('BINVAL:first').text();
aType = $(iqNode).find('TYPE:first').text();
aContainer = path_userInfos + ' .avatar-container';
}
// We display the avatar if retrieved
if(aBinval) {
// No type?
if(!aType)
aType = 'image/png';
if(type == 'user') {
// We move all the things that we don't need in that case
$(path_vCard + ' .no-avatar').hide();
$(path_vCard + ' .avatar-delete').show();
$(path_vCard + ' .avatar').remove();
}
// We display the avatar we have just received
$(aContainer).replaceWith('<div class="avatar-container"><img class="avatar" src="data:' + aType + ';base64,' + aBinval + '" alt="" /></div>');
}
else if(type == 'buddy')
$(aContainer).replaceWith('<div class="avatar-container"><img class="avatar" src="' + './img/others/default-avatar.png' + '" alt="" /></div>');
// Do someting depending of the type
if(type == 'user') {
$(path_vCard + ' .wait').hide();
$(path_vCard + ' .finish:first').removeClass('disabled');
}
else
vCardBuddyInfos();
logThis('vCard received: ' + iqFrom);
}
// Sends the vCard of the user
function sendVCard() {
// Initialize the IQ
var iq = new JSJaCIQ();
iq.setType('set');
var vCard = iq.appendNode('vCard', {'xmlns': NS_VCARD});
// We send the identity part of the form
$('#vcard .vcard-item').each(function() {
var itemID = $(this).attr('id').replace(/^USER-(.+)/, '$1');
var itemVal = $(this).val();
if(itemVal && itemID) {
if(itemID.indexOf('-') != -1) {
var tagname = explodeThis('-', itemID, 0);
var aNode;
if(vCard.getElementsByTagName(tagname).length > 0)
aNode = vCard.getElementsByTagName(tagname).item(0);
else
aNode = vCard.appendChild(iq.buildNode(tagname, {'xmlns': NS_VCARD}));
aNode.appendChild(iq.buildNode(explodeThis('-', itemID, 1), {'xmlns': NS_VCARD}, itemVal));
}
else
vCard.appendChild(iq.buildNode(itemID, {'xmlns': NS_VCARD}, itemVal));
}
});
// Send the IQ
con.send(iq);
// Send the user nickname & avatar over PEP
if(enabledPEP()) {
// Read values
var user_nick = $('#USER-NICKNAME').val();
var photo_bin = $('#USER-PHOTO-BINVAL').val();
var photo_type = $('#USER-PHOTO-TYPE').val();
var photo_data = Base64.decode(photo_bin) || '';
var photo_bytes = photo_data.length || '';
var photo_id = hex_sha1(photo_data) || '';
// Values array
var read = [
user_nick,
photo_bin,
[photo_type, photo_id, photo_bytes]
];
// Nodes array
var node = [
NS_NICK,
NS_URN_ADATA,
NS_URN_AMETA
];
// Generate the XML
for(i in read) {
var iq = new JSJaCIQ();
iq.setType('set');
var pubsub = iq.appendNode('pubsub', {'xmlns': NS_PUBSUB});
var publish = pubsub.appendChild(iq.buildNode('publish', {'node': node[i], 'xmlns': NS_PUBSUB}));
if((i == 0) && read[0]) {
var item = publish.appendChild(iq.buildNode('item', {'xmlns': NS_PUBSUB}));
// Nickname element
item.appendChild(iq.buildNode('nick', {'xmlns': NS_NICK}, read[i]));
}
else if(((i == 1) || (i == 2)) && read[1]) {
var item = publish.appendChild(iq.buildNode('item', {'xmlns': NS_PUBSUB}));
// Apply the SHA-1 hash
if(photo_id)
item.setAttribute('id', photo_id);
// Avatar data node
if(i == 1)
item.appendChild(iq.buildNode('data', {'xmlns': NS_URN_ADATA}, read[i]));
// Avatar metadata node
else {
var metadata = item.appendChild(iq.buildNode('metadata', {'xmlns': NS_URN_AMETA}));
if(read[i]) {
var meta_info = metadata.appendChild(iq.buildNode('info', {'xmlns': NS_URN_AMETA}));
if(read[i][0])
meta_info.setAttribute('type', read[i][0]);
if(read[i][1])
meta_info.setAttribute('id', read[i][1]);
if(read[i][2])
meta_info.setAttribute('bytes', read[i][2]);
}
}
}
con.send(iq);
}
}
// Close the vCard stuffs
closeVCard();
// Get our new avatar
getAvatar(getXID(), 'force', 'true', 'forget');
logThis('vCard sent.');
return false;
}
// Plugin launcher
function launchVCard() {
// Focus on the first input
$(document).oneTime(10, function() {
$('#vcard input:first').focus();
});
// Keyboard events
$('#vcard input[type=text]').keyup(function(e) {
// Enter pressed: send the vCard
if((e.keyCode == 13) && !$('#vcard .finish.save').hasClass('disabled'))
return sendVCard();
});
// Click events
$('#vcard .tab a').click(function() {
// Yet active?
if($(this).hasClass('tab-active'))
return false;
// Switch to the good tab
var key = parseInt($(this).attr('data-key'));
return switchVCard(key);
});
$('#vcard .avatar-delete').click(function() {
return deleteAvatar();
});
$('#vcard .bottom .finish').click(function() {
if($(this).is('.cancel'))
return closeVCard();
if($(this).is('.save') && !$(this).hasClass('disabled'))
return sendVCard();
return false;
});
// Avatar upload vars
var avatar_options = {
dataType: 'xml',
beforeSubmit: waitAvatarUpload,
success: handleAvatarUpload
};
// Avatar upload form submit event
$('#vcard-avatar').submit(function() {
if($('#vcard .wait').is(':hidden') && $('#vcard .avatar-info.avatar-wait').is(':hidden') && $('#vcard-avatar input[type=file]').val())
$(this).ajaxSubmit(avatar_options);
return false;
});
// Avatar upload input change event
$('#vcard-avatar input[type=file]').change(function() {
if($('#vcard .wait').is(':hidden') && $('#vcard .avatar-info.avatar-wait').is(':hidden') && $(this).val())
$('#vcard-avatar').ajaxSubmit(avatar_options);
return false;
});
}

View file

@ -0,0 +1,299 @@
/*
Jappix - An open social platform
These are the welcome tool functions for Jappix
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 16/01/12
*/
// Opens the welcome tools
function openWelcome() {
// Share message
var share_msg = printf(_e("Using Jappix, an open social platform. I am %s!"), getXID());
// Popup HTML content
var html =
'<div class="top">' + _e("Welcome!") + '</div>' +
'<div class="tab">' +
'<a href="#" class="tab-active" data-step="1">' + _e("Options") + '</a>' +
'<a href="#" class="tab-missing" data-step="2">' + _e("Friends") + '</a>' +
'<a href="#" class="tab-missing" data-step="3">' + _e("Share") + '</a>' +
'</div>' +
'<div class="content">' +
'<div class="lap-active one-lap welcome1">' +
'<div class="infos">' +
'<p class="infos-title">' + _e("Welcome on Jappix, your own social cloud!") + '</p>' +
'<p>' + _e("Before you start using it, you will have to change some settings, search for friends and complete your profile.") + '</p>' +
'</div>' +
'<a href="#" class="box enabled" title="' + _e("Click to disable") + '">' +
'<span class="option">' + _e("Sounds") + '</span>' +
'<span class="description">' + _e("Enable notification sounds") + '</span>' +
'<span class="image sound talk-images"></span>' +
'<span class="tick talk-images"></span>' +
'</a>' +
'<a href="#" class="box enabled pep-hidable" title="' + _e("Click to disable") + '">' +
'<span class="option">' + _e("Geolocation") + '</span>' +
'<span class="description">' + _e("Share your position on the globe") + '</span>' +
'<span class="image geolocation talk-images"></span>' +
'<span class="tick talk-images"></span>' +
'</a>' +
'<a href="#" class="box xmpplinks-hidable" title="' + _e("Click to enable") + '">' +
'<span class="option">' + _e("XMPP links") + '</span>' +
'<span class="description">' + _e("Open XMPP links with Jappix") + '</span>' +
'<span class="image xmpp talk-images"></span>' +
'<span class="tick talk-images"></span>' +
'</a>' +
'<a href="#" class="box enabled archives-hidable pref" title="' + _e("Click to enable") + '">' +
'<span class="option">' + _e("Message archiving") + '</span>' +
'<span class="description">' + _e("Store a history of your chats") + '</span>' +
'<span class="image archives talk-images"></span>' +
'<span class="tick talk-images"></span>' +
'</a>' +
'<a href="#" class="box" title="' + _e("Click to enable") + '">' +
'<span class="option">' + _e("Offline friends") + '</span>' +
'<span class="description">' + _e("Don\'t hide offline friends") + '</span>' +
'<span class="image offline talk-images"></span>' +
'<span class="tick talk-images"></span>' +
'</a>' +
'</div>' +
'<div class="one-lap welcome2">' +
'<div class="infos">' +
'<p class="infos-title">' + _e("Friends") + '</p>' +
'<p>' + _e("Use this tool to find your friends on the server you are using right now, or add them later.") + '</p>' +
'</div>' +
'<div class="results welcome-results"></div>' +
'</div>' +
'<div class="one-lap welcome3">' +
'<div class="infos">' +
'<p class="infos-title">' + _e("Share") + '</p>' +
'<p>' + _e("Great work! Now, you can share Jappix with your friends!") + '</p>' +
'<p>' + _e("When you will press the save button, the profile editor will be opened. Happy socializing!") + '</p>' +
'</div>' +
'<a class="box share first" href="http://www.facebook.com/sharer/sharer.php?u=' + encodeQuotes(generateURL(JAPPIX_LOCATION)) + '" target="_blank">' +
'<span class="logo facebook welcome-images"></span>' +
'<span class="name">Facebook</span>' +
'<span class="description">' + printf(_e("Share Jappix on %s"), 'Facebook') + '</span>' +
'<span class="go talk-images"></span>' +
'</a>' +
'<a class="box share" href="http://twitter.com/intent/tweet?text=' + encodeQuotes(share_msg) + '&amp;url=' + encodeQuotes(generateURL(JAPPIX_LOCATION)) + '" target="_blank">' +
'<span class="logo twitter welcome-images"></span>' +
'<span class="name">Twitter</span>' +
'<span class="description">' + printf(_e("Share Jappix on %s"), 'Twitter') + '</span>' +
'<span class="go talk-images"></span>' +
'</a>' +
'<a class="box share" href="http://www.google.com/buzz/post?message=' + encodeQuotes(share_msg) + '&amp;url=' + encodeQuotes(generateURL(JAPPIX_LOCATION)) + '" target="_blank">' +
'<span class="logo buzz welcome-images"></span>' +
'<span class="name">Google Buzz</span>' +
'<span class="description">' + printf(_e("Share Jappix on %s"), 'Google Buzz') + '</span>' +
'<span class="go talk-images"></span>' +
'</a>' +
'<a class="box share" href="http://identi.ca/index.php?action=newnotice&amp;status_textarea=' + encodeQuotes(share_msg) + ' ' + encodeQuotes(generateURL(JAPPIX_LOCATION)) + '" target="_blank">' +
'<span class="logo identica welcome-images"></span>' +
'<span class="name">Identi.ca</span>' +
'<span class="description">' + printf(_e("Share Jappix on %s"), 'Identi.ca') + '</span>' +
'<span class="go talk-images"></span>' +
'</a>' +
'</div>' +
'</div>' +
'<div class="bottom">' +
'<div class="wait wait-medium"></div>' +
'<a href="#" class="finish next">' + _e("Next") + ' »</a>' +
'<a href="#" class="finish save">' + _e("Save") + '</a>' +
'</div>';
// Create the popup
createPopup('welcome', html);
// Apply the features
applyFeatures('welcome');
// Associate the events
launchWelcome();
logThis('Welcome assistant opened.');
}
// Closes the welcome tools
function closeWelcome() {
// Destroy the popup
destroyPopup('welcome');
return false;
}
// Switches the welcome tabs
function switchWelcome(id) {
// Path to
var welcome = '#welcome ';
var content = welcome + '.content .';
var tab = welcome + '.tab ';
var wait = $(welcome + '.wait');
$(content + 'one-lap').hide();
$(content + 'welcome' + id).show();
$(tab + 'a').removeClass('tab-active');
$(tab + 'a[data-step=' + id + ']').addClass('tab-active').removeClass('tab-missing');
// Update the "save" button if all is okay
if(!exists(tab + '.tab-missing')) {
var finish = welcome + '.finish.';
$(finish + 'save').show();
$(finish + 'next').hide();
}
// If this is ID 2: vJUD search
if(id == 2) {
wait.show();
dataForm(HOST_VJUD, 'search', '', '', 'welcome');
}
else
wait.hide();
return false;
}
// Sends the welcome options
function sendWelcome(array) {
// Sends the options
var iq = new JSJaCIQ();
iq.setType('set');
var query = iq.setQuery(NS_PRIVATE);
var storage = query.appendChild(iq.buildNode('storage', {'xmlns': NS_OPTIONS}));
// Value array
var tags = new Array('sounds', 'geolocation', '', '', 'roster-showall');
// Build the XML with the array
for(i in array) {
var value = array[i];
var tag = tags[i];
if((i != 2) && (i != 3) && tag && value) {
storage.appendChild(iq.buildNode('option', {'type': tag, 'xmlns': NS_OPTIONS}, value));
setDB('options', tag, value);
}
}
con.send(iq);
// If geolocation is enabled
if(array[1] == '1')
geolocate();
}
// Saves the welcome options
var END_WELCOME = false;
function saveWelcome() {
// Get the new options
var array = new Array();
$('#welcome a.box').each(function() {
var current = '0';
if($(this).hasClass('enabled'))
current = '1';
array.push(current);
});
// If XMPP links is enabled
if(array[2] == '1')
xmppLinksHandler();
// If offline buddies showing is enabled
if(array[4] == '1')
showAllBuddies('welcome');
// If archiving is supported by the server
if(enabledArchives('pref')) {
var aEnabled = false;
// If archiving is enabled
if(array[3] == '1')
aEnabled = true;
// Send the archives configuration
configArchives(aEnabled);
}
// Send the new options
sendWelcome(array);
// Close the welcome tool
closeWelcome();
// Open the profile editor
openVCard();
END_WELCOME = true;
return false;
}
// Goes to the next welcome step
function nextWelcome() {
// Check the next step to go to
var next = 1;
var missing = '#welcome .tab a.tab-missing';
if(exists(missing))
next = parseInt($(missing + ':first').attr('data-step'));
// Switch to the next step
switchWelcome(next);
return false;
}
// Plugin launcher
function launchWelcome() {
// Click events
$('#welcome .tab a').click(function() {
// Switch to the good tab
var key = parseInt($(this).attr('data-step'));
return switchWelcome(key);
});
$('#welcome a.box:not(.share)').click(function() {
if($(this).hasClass('enabled'))
$(this).removeClass('enabled').attr('title', _e("Click to enable"));
else
$(this).addClass('enabled').attr('title', _e("Click to disable"));
return false;
});
$('#welcome .bottom .finish').click(function() {
if($(this).is('.next'))
return nextWelcome();
if($(this).is('.save'))
return saveWelcome();
return false;
});
}

View file

@ -0,0 +1,78 @@
/*
Jappix - An open social platform
These are the XMPP links handling JS scripts for Jappix
-------------------------------------------------
License: AGPL
Author: Vanaryon
Last revision: 08/05/11
*/
// Does an action with the provided XMPP link
function xmppLink(link) {
/* REF: http://xmpp.org/registrar/querytypes.html */
// Remove the "xmpp:" string
link = explodeThis(':', link, 1);
// The XMPP URI has no "?"
if(link.indexOf('?') == -1)
checkChatCreate(link, 'chat');
// Parse the URI
else {
var xid = explodeThis('?', link, 0);
var action = explodeThis('?', link, 1);
switch(action) {
// Groupchat
case 'join':
checkChatCreate(xid, 'groupchat');
break;
// Profile
case 'vcard':
openUserInfos(xid);
break;
// Subscription
case 'subscribe':
addThisContact(xid);
break;
// Unsubscription
case 'unsubscribe':
sendRoster(xid, 'remove');
break;
// Private chat
default:
checkChatCreate(xid, 'chat');
break;
}
}
return false;
}
// Gets the links vars (get parameters in URL)
var LINK_VARS = (function() {
var vars = [], hash;
var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
for(var i = 0; i < hashes.length; i++) {
var hash = hashes[i].split('=');
vars.push(hash[0]);
vars[hash[0]] = decodeURIComponent(hash[1]);
}
return vars;
})();