/* 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; } // Addon 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; }); }