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

Merge pull request #11 from mbugeia/master

Update to Jappix 1.1.2 and some improvement
This commit is contained in:
titoko 2014-12-11 14:26:53 +01:00
commit bf2b92b31f
729 changed files with 72292 additions and 193908 deletions

8
README.markdown Normal file
View file

@ -0,0 +1,8 @@
Jappix for Yunohost
============
[Yunohost project](https://yunohost.org/)
Official website: <https://jappix.org/>
Jappix v1.1.2

View file

@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8" ?>
<jappix xmlns="jappix:conf:main">
<name>YunoJappix</name>
<name>CHANGENAME</name>
<desc>a free social network</desc>
<owner_name></owner_name>
<owner_website></owner_website>
<legal></legal>
<language>CHANGELANG</language>
<resource>YunoJappix</resource>
<resource>CHANGENAME</resource>
<lock>on</lock>
<anonymous>off</anonymous>
<http_auth>on</http_auth>
@ -18,6 +18,7 @@
<https_storage>off</https_storage>
<https_force>off</https_force>
<compression>off</compression>
<caching>on</caching>
<analytics_track>off</analytics_track>
<analytics_url></analytics_url>
<analytics_id></analytics_id>

View file

@ -5,6 +5,7 @@
"en": "A free social network",
"fr": "Un réseau social libre"
},
"licence": "AGPL v3",
"developer": {
"name": "titoko",
"email": "titoko@titoko.fr",
@ -16,27 +17,38 @@
{
"name": "domain",
"ask": {
"en": "Choose a domain for Jappix"
"en": "Choose a domain for Jappix",
"fr": "Choisissez un domaine pour Jappix"
},
"example": "domain.org"
},
{
"name": "path",
"ask": {
"en": "Choose a path for Jappix"
"en": "Choose a path for Jappix",
"fr": "Choisissez un chemin pour Jappix"
},
"example": "/jappix",
"default": "/jappix"
},
{
"name": "name",
"ask": {
"en": "Choose a name for Jappix",
"fr": "Choisissez un nom pour Jappix"
},
"example": "YunoJappix",
"default": "YunoJappix"
},
{
"name": "language",
"ask": {
"en": "Choose the language of the Jappix",
"fr": "Choissisez la langue du Jappix"
},
"example": "en",
"default": "en"
}
"en": "Choose the language of the Jappix",
"fr": "Choissisez la langue du Jappix"
},
"choices" : ["en", "fr", "es"],
"default" : "en"
}
]
}
}

15
scripts/backup Normal file
View file

@ -0,0 +1,15 @@
#!/bin/bash
app=jappix
# The parameter $1 is the backup directory location
# which will be compressed afterward
backup_dir=$1/apps/$app
mkdir -p $backup_dir
# Backup sources & data
sudo cp -a /var/www/$app/. $backup_dir/sources
# Copy Nginx and YunoHost parameters to make the script "standalone"
sudo cp -a /etc/yunohost/apps/$app/. $backup_dir/yunohost
domain=$(sudo yunohost app setting $app domain)
sudo cp -a /etc/nginx/conf.d/$domain.d/$app.conf $backup_dir/nginx.conf

View file

@ -3,7 +3,8 @@
# Retrieve arguments
domain=$1
path=$2
language=$3
name=$3
language=$4
# Check domain/path availability
sudo yunohost app checkurl $domain$path -a jappix
@ -15,10 +16,10 @@ fi
path=${path%/}
# Copy files to the right place
final_path=/var/www/jappix
sudo mkdir -p $final_path
sudo cp -r ../source/* $final_path
sudo cp ../conf/*.xml $final_path/store/conf/
final_path=/var/www/jappix
sudo mkdir -p $final_path
sudo cp -r ../source/* $final_path
sudo cp ../conf/*.xml $final_path/store/conf/
# Set permissions to jappix directory
sudo chown -R www-data: $final_path
@ -27,7 +28,7 @@ sudo chown -R www-data: $final_path
sudo sed -i "s@PATHTOCHANGE2@$path@g" ../conf/nginx.conf
if [ -z "$path" ]; then
path="/"
path="/"
fi
sudo ls $final_path/i18n/$language > /dev/null 2>&1
@ -36,6 +37,7 @@ then
language="en"
fi
sudo yunohost app setting jappix name -v $name
sudo yunohost app setting jappix language -v $language
sudo sed -i "s@PATHTOCHANGE@$path@g" ../conf/nginx.conf
@ -45,6 +47,7 @@ sudo sed -i "s@PATHTOCHANGE@$path@g" $final_path/store/conf/main.xml
sudo sed -i "s@PATHTOCHANGE@$path@g" $final_path/store/conf/hosts.xml
sudo sed -i "s@DOMAINTOCHANGE@$domain@g" $final_path/store/conf/main.xml
sudo sed -i "s@CHANGELANG@$language@g" $final_path/store/conf/main.xml
sudo sed -i "s@CHANGENAME@$name@g" $final_path/store/conf/main.xml
sudo sed -i "s@DOMAINTOCHANGE@$domain@g" $final_path/store/conf/hosts.xml
# Reload Nginx and regenerate SSOwat conf

View file

@ -3,3 +3,6 @@ domain=$(sudo yunohost app setting jappix domain)
sudo rm -rf /var/www/jappix
sudo rm -f /etc/nginx/conf.d/$domain.d/jappix.conf
sudo service nginx reload
sudo yunohost app ssowatconf

16
scripts/restore Normal file
View file

@ -0,0 +1,16 @@
#!/bin/bash
app=jappix
# The parameter $1 is the uncompressed restore directory location
backup_dir=$1/apps/$app
# Restore sources & data
sudo cp -a $backup_dir/sources/. /var/www/$app
# Restore Nginx and YunoHost parameters
sudo cp -a $backup_dir/yunohost/. /etc/yunohost/apps/$app
domain=$(sudo yunohost app setting $app domain)
sudo cp -a $backup_dir/nginx.conf /etc/nginx/conf.d/$domain.d/$app.conf
# Restart webserver
sudo service nginx reload

View file

@ -3,8 +3,13 @@
# Retrieve arguments
domain=$(sudo yunohost app setting jappix domain)
path=$(sudo yunohost app setting jappix path)
name=$(sudo yunohost app setting jappix name)
language=$(sudo yunohost app setting jappix language)
if [[ "$name" = "" ]];
then
name="YunoJappix"
fi
if [[ "$language" = "" ]];
then
language="en"
@ -37,6 +42,7 @@ sudo sed -i "s@PATHTOCHANGE@$path@g" $final_path/store/conf/main.xml
sudo sed -i "s@PATHTOCHANGE@$path@g" $final_path/store/conf/hosts.xml
sudo sed -i "s@DOMAINTOCHANGE@$domain@g" $final_path/store/conf/main.xml
sudo sed -i "s@CHANGELANG@$language@g" $final_path/store/conf/main.xml
sudo sed -i "s@CHANGENAME@$name@g" $final_path/store/conf/main.xml
sudo sed -i "s@DOMAINTOCHANGE@$domain@g" $final_path/store/conf/hosts.xml
# Reload Nginx and regenerate SSOwat conf

View file

@ -4,6 +4,71 @@ Jappix Changelog
Here's the log of what has changed over the Jappix releases.
Primo, v1.1.2 (October 2014)
----------------------------
* XEP-0353: Jingle Message Initiation @valeriansaliou
* Fixes Jingle calls in Chrome 38+ @valeriansaliou
Primo, v1.1.1 (September 2014)
------------------------------
* Ignore empty XHTML-IM messages @eijebong, @valeriansaliou
* Fix a bug with message markers @valeriansaliou
Primo, v1.1.0 (June 2014)
-------------------------
* XEP-0272: Multiparty Jingle (Muji) @valeriansaliou
* Prevent client crash on huge messages @valeriansaliou
* Beautified client code (JavaScript) @valeriansaliou
* Fix unavailable MUC rooms @emamirazavi
One, v1.0.7 (May 2014)
----------------------
* Fix BackLinks design @valeriansaliou
* Sort Jappix Mobile contacts alphabetically @valeriansaliou
* Display offline contacts in Jappix Mini @valeriansaliou
One, v1.0.6 (May 2014)
----------------------
* XEP-0308: Last Message Correction @valeriansaliou
* XEP-0333: Chat Markers @valeriansaliou
* XEP-0319: Last User Interaction into Presence @valeriansaliou
* XEP-0224: Attention @valeriansaliou
* XEP-0152: Reachability Addresses @valeriansaliou
* XEP-0334: Message Processing Hints @valeriansaliou
* Fix gateway contacts management @valeriansaliou
* Fix sounds in Jappix Mini @aryo, @valeriansaliou
One, v1.0.5 (May 2014)
----------------------
* Fix MUC bookmark shortcut button @valeriansaliou
* Fix HTML5 notifications in Firefox 22+ @valeriansaliou
* Fix server commands tool @valeriansaliou
* New translations added (Uzbek), and a few ones updated @nurkamol, @valeriansaliou
One, v1.0.4 (May 2014)
----------------------
* Fix update tool (on some environments) @valeriansaliou
* Fix MUC room join @maranda, @valeriansaliou
* Fix special chars in JIDs for Jappix Mini @dunger, @valeriansaliou
* Fix WebSocket session termination in JSJaC @sstrigler
* Enhance backend security (verify SSL certificates) @valeriansaliou
* Add assets client cache option @valeriansaliou
* Add SSO support to Jappix Mobile @valeriansaliou
One, v1.0.3 (March 2014)
------------------------

View file

@ -11,56 +11,76 @@ Here are listed the XMPP Protocol Extensions that Jappix supports, as well as th
* RFC-6122: Extensible Messaging and Presence Protocol (XMPP): Address Format
# XMPP Extensions
# XMPP Extensions (Standardized)
* XEP-0045: Multi-User Chat *v1.25*
* XEP-0004: Data Forms *v2.9*
* XEP-0012: Last Activity *v2.0*
* XEP-0016: Privacy Lists *v1.6*
* XEP-0030: Service Discovery *v2.4*
* XEP-0045: Multi-User Chat *v1.25*
* XEP-0049: Private XML Storage *v1.2*
* XEP-0050: Ad-Hoc Commands *v1.2*
* XEP-0054: vcard-temp *v1.2*
* XEP-0055: Jabber Search *v1.3*
* XEP-0060: Publish-Subscribe *v1.13*
* XEP-0124: Bidirectional-streams Over Synchronous HTTP (BOSH) *v1.10*
* XEP-0115: Entity Capabilities *v1.5*
* XEP-0066: Out of Band Data *v1.5*
* XEP-0071: XHTML-IM *v1.5*
* XEP-0072: SOAP Over XMPP *v1.0*
* XEP-0077: In-Band Registration *v2.4*
* XEP-0080: User Location *v1.7*
* XEP-0084: User Avatar *v1.1*
* XEP-0085: Chat State Notifications *v2.1*
* XEP-0092: Software Version *v1.1*
* XEP-0107: User Mood *v1.2*
* XEP-0108: User Activity *v1.3*
* XEP-0115: Entity Capabilities *v1.5*
* XEP-0118: User Tune *v1.2*
* XEP-0080: User Location *v1.7*
* XEP-0172: User Nickname *v1.1*
* XEP-0084: User Avatar *v1.1*
* XEP-0277: Microblogging over XMPP *v0.6*
* XEP-xxxx: Notification Inbox *v0.1*
* Alternate URL: http://xmpp.org/extensions/inbox/notification-inbox.html
* XEP-0203: Delayed Delivery *v2.0*
* XEP-0124: Bidirectional-streams Over Synchronous HTTP (BOSH) *v1.10*
* XEP-0144: Roster Item Exchange *v1.0*
* XEP-0072: SOAP Over XMPP *v1.0*
* XEP-0085: Chat State Notifications *v2.1*
* XEP-0071: XHTML-IM *v1.5*
* XEP-0313: Message Archive Management *v0.3*
* Alternate URL: https://demo.frenchtouch.pro/valerian.saliou/xmpp/extensions/xep-0313.html
* XEP-0012: Last Activity *v2.0*
* XEP-0049: Private XML Storage *v1.2*
* XEP-0077: In-Band Registration *v2.4*
* XEP-0055: Jabber Search *v1.3*
* XEP-0050: Ad-Hoc Commands *v1.2*
* XEP-0092: Software Version *v1.1*
* XEP-0004: Data Forms *v2.9*
* XEP-0054: vcard-temp *v1.2*
* XEP-0202: Entity Time *v2.0*
* XEP-0199: XMPP Ping *v2.0*
* XEP-0184: Message Delivery Receipts *v1.2*
* XEP-0016: Privacy Lists *v1.6*
* XEP-0066: Out of Band Data *v1.5*
* XEP-0280: Message Carbons *v0.9*
* XEP-0292: vCard4 Over XMPP *v0.10*
* XEP-0152: Reachability Addresses *v1.0*
* XEP-0166: Jingle *v1.1*
* XEP-0167: Jingle RTP Sessions *v1.1*
* XEP-0172: User Nickname *v1.1*
* XEP-0176: Jingle ICE-UDP Transport Method *v1.0*
* XEP-0177: Jingle Raw UDP Transport Method *v1.1*
* XEP-0184: Message Delivery Receipts *v1.2*
* XEP-0199: XMPP Ping *v2.0*
* XEP-0202: Entity Time *v2.0*
* XEP-0203: Delayed Delivery *v2.0*
* XEP-0224: Attention *v1.0*
* XEP-0215: External Service Discovery *v0.5*
* XEP-0249: Direct MUC Invitations *v1.2*
* XEP-0262: Use of ZRTP in Jingle RTP Sessions *v1.0*
* XEP-0266: Codecs for Jingle Audio *v1.0*
* XEP-0269: Jingle Early Media *v0.1*
* XEP-0277: Microblogging over XMPP *v0.6*
* XEP-0278: Jingle Relay Nodes *v0.2*
* XEP-0280: Message Carbons *v0.9*
* XEP-0292: vCard4 Over XMPP *v0.10*
* XEP-0293: Jingle RTP Feedback Negotiation *v0.1*
* XEP-0294: Jingle RTP Header Extensions Negotiation *v0.1*
* XEP-0299: Codecs for Jingle Video *v0.1*
* XEP-0308: Last Message Correction *v1.0*
* XEP-0319: Last User Interaction in Presence *v0.2*
* XEP-0320: Use of DTLS-SRTP in Jingle Sessions *v0.2*
* XEP-0333: Chat Markers *v0.2*
* XEP-0334: Message Processing Hints *v0.1*
* XEP-0338: Jingle Grouping Framework *v0.1*
* XEP-0339: Source-Specific Media Attributes in Jingle *v0.1*
* XEP-0353: Jingle Message Initiation *v0.1*
# XMPP Extensions (Updated)
* XEP-0272: Multiparty Jingle (Muji) *v0.2*
* Alternate URL: https://demo.hakuma.holdings/valerian.saliou/xmpp/extensions/xep-0272.html
* XEP-0313: Message Archive Management *v0.3*
* Alternate URL: https://demo.hakuma.holdings/valerian.saliou/xmpp/extensions/xep-0313.html
# XMPP Extensions (Proposed)
* XEP-xxxx: Notification Inbox *v0.1*
* Alternate URL: http://xmpp.org/extensions/inbox/notification-inbox.html
# Others

View file

@ -6,7 +6,7 @@ Jappix is a fresh new open social platform which enables you to create your own
You can build your own Jappix installation for your own requirements: if you want to use it as a personal social client, you can download it and put it on your webserver. It's easy, fast and free.
[![build status](https://ci.frenchtouch.pro/projects/7/status.png?ref=master)](https://ci.frenchtouch.pro/projects/7?ref=master)
[![build status](https://ci.hakuma.holdings/projects/7/status.png?ref=master)](https://ci.hakuma.holdings/projects/7?ref=master)
License
@ -32,9 +32,9 @@ Start translating on https://www.transifex.com/projects/p/jappix/ (new translato
Links
-----
* Jappix project website: http://jappix.org/
* Jappix project website: https://jappix.org/
* Jappix project dev panel: https://github.com/jappix/jappix
* Jappix nodes list: http://jappix.net/
* Jappix nodes list: https://jappix.net/
* Jappix main service: https://jappix.com/
* Jappix commercial support: https://jappix.pro/
@ -45,7 +45,7 @@ Mirrors
In case a master service is down (GitHub for Git access or Jappix.org for project download), here is a list of available mirrors:
* Project website mirror: https://project.jappix.com/
* Development repository mirror: https://code.frenchtouch.pro/jappix/jappix
* Development repository mirror: https://code.hakuma.holdings/jappix/jappix
MUC Links

View file

@ -1 +1 @@
One [1.0.3]
Primo [1.1.2]

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8" ?>
<jappix xmlns="jappix:file:get">
<css>fonts.css~main.css~images.css~board.css~home.css~others.css~tools.css~roster.css~myinfos.css~pageengine.css~channel.css~pageswitch.css~smileys.css~popup.css~vcard.css~options.css~favorites.css~discovery.css~directory.css~adhoc.css~privacy.css~inbox.css~mucadmin.css~integratebox.css~userinfos.css~search.css~welcome.css~me.css~rosterx.css~jingle.css</css>
<js>origin.js~jxhr.js~datejs.js~jquery.js~jquery.ui.js~jquery.json.js~jquery.form.js~jquery.timers.js~jquery.placeholder.js~jquery.textrange.js~base64.js~jsjac.js~jsjac.jingle.js~system.js~constants.js~datastore.js~browser-detect.js~home.js~talk.js~popup.js~audio.js~board.js~bubble.js~chat.js~groupchat.js~smileys.js~oob.js~avatar.js~mucadmin.js~connection.js~dataform.js~discovery.js~directory.js~adhoc.js~privacy.js~errors.js~name.js~favorites.js~features.js~interface.js~xmpplinks.js~iq.js~message.js~chatstate.js~receipts.js~tooltip.js~filter.js~links.js~inbox.js~microblog.js~music.js~notification.js~httpreply.js~options.js~integratebox.js~pubsub.js~pep.js~presence.js~roster.js~jingle.js~storage.js~console.js~common.js~utilities.js~date.js~caps.js~vcard.js~userinfos.js~search.js~autocompletion.js~welcome.js~me.js~rosterx.js~mam.js~carbons.js</js>
<css>fonts.css~main.css~images.css~board.css~home.css~others.css~tools.css~roster.css~myinfos.css~pageengine.css~channel.css~pageswitch.css~smileys.css~popup.css~vcard.css~options.css~favorites.css~discovery.css~directory.css~adhoc.css~privacy.css~inbox.css~mucadmin.css~integratebox.css~userinfos.css~search.css~welcome.css~me.css~rosterx.css~call.css~jingle.css~muji.css</css>
<js>origin.js~jxhr.js~datejs.js~jquery.js~jquery.ui.js~jquery.json.js~jquery.form.js~jquery.timers.js~jquery.placeholder.js~jquery.textrange.js~jquery.scrollto.js~base64.js~jsjac.js~jsjac.jingle.js~system.js~constants.js~datastore.js~browser-detect.js~home.js~talk.js~popup.js~audio.js~board.js~bubble.js~chat.js~groupchat.js~smileys.js~oob.js~avatar.js~mucadmin.js~connection.js~dataform.js~discovery.js~directory.js~adhoc.js~privacy.js~errors.js~name.js~favorites.js~features.js~interface.js~xmpplinks.js~iq.js~message.js~chatstate.js~receipts.js~tooltip.js~filter.js~links.js~inbox.js~microblog.js~music.js~notification.js~httpreply.js~options.js~integratebox.js~pubsub.js~pep.js~presence.js~roster.js~call.js~jingle.js~muji.js~storage.js~console.js~common.js~utilities.js~date.js~caps.js~vcard.js~userinfos.js~search.js~autocompletion.js~welcome.js~me.js~rosterx.js~mam.js~carbons.js~correction.js~markers.js~attention.js</js>
</jappix>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View file

@ -29,24 +29,24 @@ var AdHoc = (function () {
try {
// Popup HTML content
var html =
'<div class="top">' + Common._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">' + Common._e("Close") + '</a>' +
var html =
'<div class="top">' + Common._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">' + Common._e("Close") + '</a>' +
'</div>';
// Create the popup
Popup.create('adhoc', html);
// Associate the events
self.launch();
} catch(e) {
@ -88,16 +88,16 @@ var AdHoc = (function () {
try {
// Open the popup
self.open();
// Add a XID marker
$('#adhoc .adhoc-head').html('<b>' + Name.getBuddy(xid).htmlEnc() + '</b> (' + xid.htmlEnc() + ')');
// Get the highest entity resource
var highest = Presence.highestPriority(xid);
if(highest)
xid = highest;
// Start a new adhoc command
DataForm.go(xid, 'command', '', '', 'adhoc');
} catch(e) {
@ -120,10 +120,10 @@ var AdHoc = (function () {
try {
// Open the popup
self.open();
// Add a XID marker
$('#adhoc .adhoc-head').html('<b>' + server.htmlEnc() + '</b>');
// Start a new adhoc command
DataForm.go(server, 'command', '', '', 'adhoc');
} catch(e) {
@ -142,9 +142,7 @@ var AdHoc = (function () {
try {
// Click event
$('#adhoc .bottom .finish').click(
self.close()
);
$('#adhoc .bottom .finish').click(self.close);
} catch(e) {
Console.error('AdHoc.launch', e);
}

View file

@ -20,6 +20,28 @@ var Anonymous = (function () {
var self = {};
/**
* Registers connection handlers
* @private
* @param {object} con
* @return {undefined}
*/
self._registerHandlers = function(con) {
try {
con.registerHandler('message', Message.handle);
con.registerHandler('presence', Presence.handle);
con.registerHandler('iq', IQ.handle);
con.registerHandler('onconnect', self.connected);
con.registerHandler('onerror', Errors.handle);
con.registerHandler('ondisconnect', self.disconnected);
} catch(e) {
Console.error('Anonymous._registerHandlers', e);
}
};
/**
* Connected to an anonymous session
* @public
@ -29,40 +51,40 @@ var Anonymous = (function () {
try {
Console.info('Jappix (anonymous) is now connected.');
// Connected marker
Connection.connected = true;
Connection.current_session = true;
Connection.reconnect_try = 0;
Connection.reconnect_timer = 0;
// Not resumed?
if(!Connection.resume) {
// Create the app
Talk.create();
// Send our first presence
Presence.sendFirst('');
// Set last activity stamp
DateUtils.last_activity = DateUtils.getTimeStamp();
// Create the new groupchat
Chat.checkCreate(Common.generateXID(ANONYMOUS_ROOM, 'groupchat'), 'groupchat');
// Remove some nasty elements for the anonymous mode
$('.tools-mucadmin, .tools-add').remove();
}
// Resumed
else {
// Send again our presence
Presence.sendActions();
// Change the title
Interface.updateTitle();
}
// Remove the waiting icon
Interface.removeGeneralWait();
} catch(e) {
@ -107,21 +129,16 @@ var Anonymous = (function () {
// Check BOSH origin
BOSH_SAME_ORIGIN = Origin.isSame(httpbase);
// We create the new http-binding connection
con = new JSJaCHttpBindingConnection({
httpbase: httpbase
});
}
// And we handle everything that happen
con.registerHandler('message', Message.handle);
con.registerHandler('presence', Presence.handle);
con.registerHandler('iq', IQ.handle);
con.registerHandler('onconnect', self.connected);
con.registerHandler('onerror', Errors.handle);
con.registerHandler('ondisconnect', self.disconnected);
self._registerHandlers(con);
// We set the anonymous connection parameters
oArgs = {};
oArgs.domain = server;
@ -129,10 +146,10 @@ var Anonymous = (function () {
oArgs.resource = JAPPIX_RESOURCE + ' Anonymous (' + (new Date()).getTime() + ')';
oArgs.secure = true;
oArgs.xmllang = XML_LANG;
// We connect !
con.connect(oArgs);
// Change the page title
Interface.title('wait');
} catch(e) {
@ -140,7 +157,7 @@ var Anonymous = (function () {
// Reset Jappix
self.disconnected();
// Open an unknown error
Board.openThisError(2);
} finally {
@ -160,16 +177,19 @@ var Anonymous = (function () {
try {
$(document).ready(function() {
Console.info('Anonymous mode detected, connecting...');
// We add the login wait div
Interface.showGeneralWait();
// Get the vars
if(XMPPLinks.links_var.r)
if(XMPPLinks.links_var.r) {
ANONYMOUS_ROOM = XMPPLinks.links_var.r;
if(XMPPLinks.links_var.n)
}
if(XMPPLinks.links_var.n) {
ANONYMOUS_NICK = XMPPLinks.links_var.n;
}
// Fire the login action
self.login(HOST_ANONYMOUS);
});

View file

@ -0,0 +1,216 @@
/*
Jappix - An open social platform
Implementation of XEP-0224: Attention
-------------------------------------------------
License: AGPL
Author: Valérian Saliou
*/
// Bundle
var Attention = (function () {
/**
* Alias of this
* @private
*/
var self = {};
/**
* Displays attention message
* @private
* @param {string} xid
* @param {string} body
* @return {undefined}
*/
self._display = function(xid, body, mode) {
try {
var name = Name.getBuddy(xid).htmlEnc();
var hash = hex_md5(xid);
// Compute some variables
var message = Common._e(Common.printf("You requested %s's attention to the conversation", name));
if(mode == 'him') {
message = Common._e(Common.printf("%s requested your attention to the conversation", name));
}
if(body) {
message += ' (' + body + ')';
}
// Display notification
Message.display(
'chat',
xid,
hash,
name,
message,
DateUtils.getCompleteTime(),
DateUtils.getTimeStamp(),
'system-message',
true,
undefined,
mode
);
// Add a marker to displayed message
$('#' + hash + ' .content .one-line.system-message:last').addClass('attention-notice');
} catch(e) {
Console.error('Attention._display', e);
}
};
/**
* Sends attention stanza
* @private
* @param {string} xid
* @param {string} body
* @return {object}
*/
self._stanza = function(xid, body) {
try {
var message = new JSJaCMessage();
message.setType('headline');
message.setTo(xid);
if(body) {
message.setBody(body);
}
// Attention node
message.appendNode('attention', {
'xmlns': NS_URN_ATTENTION
});
con.send(message);
return message;
} catch(e) {
Console.error('Attention._stanza', e);
}
};
/**
* Returns whether last attention message exists or not
* @private
* @param {string} xid
* @return {boolean}
*/
self._lastExists = function(xid, mode) {
var last_exists = false;
try {
var line_sel = $('#' + hex_md5(xid) + ' .content .one-line[data-mode="' + mode + '"]:last');
last_exists = line_sel.is('.system-message.attention-notice') ? true : false;
} catch(e) {
Console.error('Attention._lastExists', e);
} finally {
return last_exists;
}
};
/**
* Return whether entity supports attention notifications
* @public
* @param {string} xid
* @return {boolean}
*/
self.hasSupport = function(xid) {
var has_support = false;
try {
has_support = true ? $('#' + hex_md5(xid)).attr('data-attention') == 'true' : false;
} catch(e) {
Console.error('Attention.hasSupport', e);
} finally {
return has_support;
}
};
/**
* Send an attention message
* @public
* @param {string} xid
* @param {string} body
* @return {undefined}
*/
self.send = function(xid, body) {
try {
var mode = 'me';
// Don't send attention message twice
if(self._lastExists(xid, mode) === false) {
// Send message stanza
self._stanza(xid, body);
// Display attention notification
self._display(xid, body, mode);
} else {
Console.debug('Attention.send', 'Not sending attention message to: ' + xid + ' because already sent.');
}
} catch(e) {
Console.error('Attention.send', e);
}
};
/**
* Receive an attention notification
* @public
* @param {string} xid
* @return {undefined}
*/
self.receive = function(xid, body) {
try {
var mode = 'him';
var hash = hex_md5(xid);
// Don't receive attention message twice
if((self._lastExists(xid, mode) === false) && Common.exists('#' + hash)) {
// Display attention notification
self._display(xid, body, mode);
// Show a notification
Interface.messageNotify(hash, 'personal');
Audio.play('catch-attention');
Board.quick(
xid,
'chat',
Common._e("Attention to conversation requested."),
Name.getBuddy(xid)
);
}
} catch(e) {
Console.error('Attention.receive', e);
}
};
/**
* Return class scope
*/
return self;
})();

View file

@ -29,7 +29,7 @@ var Audio = (function () {
* @private
* @return {boolean}
*/
self._is_supported = function() {
self._isSupported = function() {
is_supported = true;
@ -38,7 +38,7 @@ var Audio = (function () {
is_supported = false;
}
} catch(e) {
Console.error('Audio._is_supported', e);
Console.error('Audio._isSupported', e);
} finally {
return is_supported;
}
@ -46,6 +46,57 @@ var Audio = (function () {
};
/**
* Append audio DOM code
* @private
* @return {undefined}
*/
self._appendDOM = function() {
try {
// If the audio elements aren't yet in the DOM
if(!Common.exists('#audio')) {
$('body').append(
'<div id="audio">' +
'<audio id="new-chat" preload="auto" data-duration="2">' +
'<source src="' + './sounds/new-chat.mp3' + '" />' +
'<source src="' + './sounds/new-chat.oga' + '" />' +
'</audio>' +
'<audio id="receive-message" preload="auto" data-duration="2">' +
'<source src="' + './sounds/receive-message.mp3' + '" />' +
'<source src="' + './sounds/receive-message.oga' + '" />' +
'</audio>' +
'<audio id="notification" preload="auto" data-duration="2">' +
'<source src="' + './sounds/notification.mp3' + '" />' +
'<source src="' + './sounds/notification.oga' + '" />' +
'</audio>' +
'<audio id="catch-attention" preload="auto" data-duration="3">' +
'<source src="' + './sounds/catch-attention.mp3' + '" />' +
'<source src="' + './sounds/catch-attention.oga' + '" />' +
'</audio>' +
'<audio id="incoming-call" preload="auto" data-duration="7">' +
'<source src="' + './sounds/incoming-call.mp3' + '" />' +
'<source src="' + './sounds/incoming-call.oga' + '" />' +
'</audio>' +
'<audio id="outgoing-call" preload="auto" data-duration="30">' +
'<source src="' + './sounds/outgoing-call.mp3' + '" />' +
'<source src="' + './sounds/outgoing-call.oga' + '" />' +
'</audio>' +
'</div>'
);
}
} catch(e) {
Console.error('Audio._appendDOM', e);
}
};
/**
* Plays the given sound ID
* @public
@ -58,44 +109,14 @@ var Audio = (function () {
repeat = (typeof repeat === 'boolean') ? repeat : false;
// Not supported?
if(!self._is_supported()) {
if(!self._isSupported()) {
return false;
}
// If the sounds are enabled
if(DataStore.getDB(Connection.desktop_hash, 'options', 'sounds') === '1') {
// If the audio elements aren't yet in the DOM
if(!Common.exists('#audio')) {
$('body').append(
'<div id="audio">' +
'<audio id="new-chat" preload="auto" data-duration="2">' +
'<source src="' + './sounds/new-chat.mp3' + '" />' +
'<source src="' + './sounds/new-chat.oga' + '" />' +
'</audio>' +
'<audio id="receive-message" preload="auto" data-duration="2">' +
'<source src="' + './sounds/receive-message.mp3' + '" />' +
'<source src="' + './sounds/receive-message.oga' + '" />' +
'</audio>' +
'<audio id="notification" preload="auto" data-duration="2">' +
'<source src="' + './sounds/notification.mp3' + '" />' +
'<source src="' + './sounds/notification.oga' + '" />' +
'</audio>' +
'<audio id="incoming-call" preload="auto" data-duration="7">' +
'<source src="' + './sounds/incoming-call.mp3' + '" />' +
'<source src="' + './sounds/incoming-call.oga' + '" />' +
'</audio>' +
'<audio id="outgoing-call" preload="auto" data-duration="30">' +
'<source src="' + './sounds/outgoing-call.mp3' + '" />' +
'<source src="' + './sounds/outgoing-call.oga' + '" />' +
'</audio>' +
'</div>'
);
}
self._appendDOM();
// We play the target sound
var audio_raw_sel = $('#audio audio').filter('#' + name);
var audio_sel = audio_raw_sel[0];
@ -112,7 +133,7 @@ var Audio = (function () {
var duration = parseInt((audio_raw_sel.attr('data-duration') || 0), 10);
self._timeout_stop = false;
audio_raw_sel.oneTime((duration + 's'), function() {
if(!self._timeout_stop) {
self.play(name, repeat);
@ -146,10 +167,10 @@ var Audio = (function () {
try {
// Not supported?
if(!self._is_supported()) {
if(!self._isSupported()) {
return false;
}
self._timeout_stop = true;
// Check the audio container exists before doing anything...
@ -159,7 +180,7 @@ var Audio = (function () {
if(audio_parent_sel.size()) {
audio_raw_sel.stopTime();
if(audio_sel) {
if(!audio_sel.paused) {
audio_sel.pause();

View file

@ -32,14 +32,17 @@ var Autocompletion = (function () {
try {
// Put the two strings into lower case
var sA = a[0].toLowerCase();
var sB = b[0].toLowerCase();
var sort_a = a[0].toLowerCase();
var sort_b = b[0].toLowerCase();
// Process the sort
if(sA > sB)
if(sort_a > sort_b) {
return 1;
if(sA < sB)
}
if(sort_a < sort_b) {
return -1;
}
} catch(e) {
Console.error('Autocompletion.caseInsensitiveSort', e);
}
@ -49,40 +52,51 @@ var Autocompletion = (function () {
/**
* Split a query into its subqueries ready to be used in autocompletion
* The function return an array containing two others : the first with subqueries
* and the second with remaining parts
* For example, if query is "A B C", the subqueries are ["C", "B C", "A B C"] and
* the remaining parts are ["A B ", "A ", ""]
* @public
* @param {string} query
* @return {Array}
* @return {object}
*/
self.getSubQueries = function(query) {
var subqueries = [];
var remnants = [];
var result = [];
var queryLastCharPos = query.length - 1;
var spaceCounter = 0;
for (var i=queryLastCharPos; i>=0; i--) {
// Search from the end of the query
var iChar = query.charAt(i);
if (spaceCounter === 0 && iChar.search(/\s/) === 0) {
// the first "local" space was found
// add the subquery and its remnant to results
subqueries.push(query.slice(i+1));
remnants.push(query.slice(0, i+1));
spaceCounter++;
} else {
spaceCounter = 0;
try {
var subqueries = [];
var remnants = [];
var query_last_char_pos = query.length - 1;
var space_counter = 0;
var cur_char;
for(var i = query_last_char_pos; i >= 0; i--) {
// Search from the end of the query
cur_char = query.charAt(i);
if(space_counter === 0 && cur_char.search(/\s/) === 0) {
// The first "local" space was found
// Add the subquery and its remnant to results
subqueries.push(query.slice(i+1));
remnants.push(query.slice(0, i+1));
space_counter++;
} else {
space_counter = 0;
}
}
}
if (spaceCounter === 0) {
// If the first char of the query is not a space, add the full query to results
subqueries.push(query);
remnants.push("");
if(space_counter === 0) {
// If the first char of the query is not a space, add the full query to results
subqueries.push(query);
remnants.push('');
}
result = [subqueries, remnants];
} catch(e) {
Console.error('Autocompletion.getSubQueries', e);
} finally {
return result;
}
return [subqueries, remnants];
};
@ -102,25 +116,37 @@ var Autocompletion = (function () {
try {
// Replace forbidden characters in regex
query = Common.escapeRegex(query);
// Build an array of regex to use
var queryRegExp = [];
for (i = 0; i<query.length; i++) {
if (query[i] !== null) {
queryRegExp.push(new RegExp('(^)' + query[i], 'gi'));
var query_reg_exp = [];
for(i = 0; i < query.length; i++) {
if(query[i] !== null) {
query_reg_exp.push(
new RegExp('(^)' + query[i], 'gi')
);
}
}
// Search in the roster
var nick, regex;
$('#' + id + ' .user').each(function() {
var nick = $(this).find('.name').text();
for (i = 0; i<queryRegExp.length; i++) {
var regex = queryRegExp[i];
nick = $(this).find('.name').text();
for(i = 0; i < query_reg_exp.length; i++) {
regex = query_reg_exp[i];
if(nick.match(regex)) {
results.push([nick, i]);
}
}
});
// Sort the array
results = results.sort(self.caseInsensitiveSort);
results = results.sort(
self.caseInsensitiveSort
);
} catch(e) {
Console.error('Autocompletion.process', e);
} finally {
@ -139,7 +165,8 @@ var Autocompletion = (function () {
self.reset = function(hash) {
try {
$('#' + hash + ' .message-area').removeAttr('data-autocompletion-pointer').removeAttr('data-autocompletion-query');
$('#' + hash + ' .message-area').removeAttr('data-autocompletion-pointer')
.removeAttr('data-autocompletion-query');
} catch(e) {
Console.error('Autocompletion.reset', e);
}
@ -157,59 +184,62 @@ var Autocompletion = (function () {
try {
// Initialize
var vSelector = $('#' + hash + ' .message-area');
var value = vSelector.val();
var message_area_sel = $('#' + hash + ' .message-area');
var value = message_area_sel.val();
if(!value) {
self.reset(hash);
}
var query = vSelector.attr('data-autocompletion-query');
var query = message_area_sel.attr('data-autocompletion-query');
if(query === undefined) {
// The autocompletion has not been yet launched
query = self.getSubQueries(value);
vSelector.attr('data-autocompletion-query', JSON.stringify(query));
message_area_sel.attr('data-autocompletion-query', JSON.stringify(query));
} else {
// The autocompletion has already stored a query
query = JSON.parse(query);
}
// Get the pointer
var pointer = vSelector.attr('data-autocompletion-pointer');
var i = 0;
if(pointer)
i = parseInt(pointer);
var pointer = message_area_sel.attr('data-autocompletion-pointer');
var i = pointer ? parseInt(pointer, 10) : 0;
// We get the nickname
var nickResult = self.process(query[0], hash)[i];
var nick_result = self.process(query[0], hash)[i];
var nick;
if (nickResult !== undefined) {
nick = nickResult[0];
if(nick_result !== undefined) {
nick = nick_result[0];
}
// Shit, this is my nick!
if((nick !== undefined) && (nick.toLowerCase() == Name.getMUCNick(hash).toLowerCase())) {
// Increment
i++;
// Get the next nick
nickResult = self.process(query[0], hash)[i];
if (nickResult !== undefined) {
nick = nickResult[0];
nick_result = self.process(query[0], hash)[i];
if (nick_result !== undefined) {
nick = nick_result[0];
}
}
// We quote the nick
if((nickResult !== undefined) && (nick !== undefined)) {
if((nick_result !== undefined) && (nick !== undefined)) {
// Increment
i++;
var message = query[1][nickResult[1]];
Utils.quoteMyNick(hash, nick, message);
Utils.quoteMyNick(
hash,
nick,
query[1][nick_result[1]]
);
// Put a pointer
vSelector.attr('data-autocompletion-pointer', i);
message_area_sel.attr('data-autocompletion-pointer', i);
}
} catch(e) {
Console.error('Autocompletion.create', e);

View file

@ -39,30 +39,32 @@ var Avatar = (function () {
try {
// No need to get the avatar, another process is yet running
if(Utils.existArrayValue(self.pending, xid))
if(Utils.existArrayValue(self.pending, xid)) {
return false;
}
// Initialize: XML data is in one SQL entry, because some browser are sloooow with SQL requests
var xml = Common.XMLFromString(
DataStore.getPersistent('global', 'avatar', xid)
);
var forced = false;
// Retrieving forced?
if($(xml).find('forced').text() == 'true')
if($(xml).find('forced').text() == 'true') {
forced = true;
}
// No avatar in presence
if(!photo && !forced && enabled == 'true') {
// Pending marker
self.pending.push(xid);
// Reset the avatar
self.reset(xid, hex_md5(xid));
Console.warn('No avatar for: ' + xid);
}
// Try to catch the avatar
else {
// Define some stuffs
@ -72,38 +74,39 @@ var Avatar = (function () {
var updated = false;
// Process the checksum of the avatar
if(checksum == photo || photo == 'forget' || forced)
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
self.pending.push(xid);
// Display the cache avatar
self.display(xid, hex_md5(xid), type, binval);
Console.info('Read avatar from cache: ' + xid);
}
// Else if the request has not yet been fired, we get it
else if((!updated || mode == 'force' || photo == 'forget') && enabled != 'false') {
// Pending marker
self.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, self.handle);
Console.info('Get avatar from server: ' + xid);
}
}
return true;
} catch(e) {
Console.error('Avatar.get', e);
@ -124,90 +127,94 @@ var Avatar = (function () {
// Extract the XML values
var handleXML = iq.getNode();
var handleFrom = Common.fullXID(Common.getStanzaFrom(iq));
// Is this me? Remove the resource!
if(Common.bareXID(handleFrom) == Common.getXID()) {
handleFrom = Common.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 == Common.getXID()) {
oChecksum = DataStore.getDB(Connection.desktop_hash, 'checksum', 1);
// Avoid the "null" value
if(!oChecksum)
if(!oChecksum) {
oChecksum = '';
}
}
// vCard not empty?
if(find.size()) {
// We get our profile details
if(handleFrom == Common.getXID()) {
// Get the names
var names = Name.generateBuddy(iq);
var phone_number = find.find('TEL:has(NUMBER):first NUMBER:first').text();
// Write the values to the database
DataStore.setDB(Connection.desktop_hash, 'profile', 'name', names[0]);
DataStore.setDB(Connection.desktop_hash, 'profile', 'nick', names[1]);
DataStore.setDB(Connection.desktop_hash, 'profile', 'phone', phone_number);
}
// 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)
if(!aType) {
aType = 'image/png';
// Process the checksum
else
} else {
aChecksum = hex_sha1(Base64.decode(aBinval));
}
}
// We display the user avatar
self.display(handleFrom, hash, aType, aBinval);
// Store the avatar
DataStore.setPersistent('global', 'avatar', handleFrom, '<avatar><type>' + aType + '</type><binval>' + aBinval + '</binval><checksum>' + aChecksum + '</checksum><forced>false</forced></avatar>');
Console.info('Avatar retrieved from server: ' + handleFrom);
}
// vCard is empty
else {
self.reset(handleFrom);
}
// We got a new checksum for us?
if(((oChecksum !== null) && (oChecksum != aChecksum)) || !Presence.first_sent) {
// Define a proper checksum
var pChecksum = aChecksum;
if(pChecksum == 'none')
if(pChecksum == 'none') {
pChecksum = '';
}
// Update our temp. checksum
DataStore.setDB(Connection.desktop_hash, 'checksum', 1, pChecksum);
// Send the stanza
if(!Presence.first_sent)
if(!Presence.first_sent) {
Storage.get(NS_OPTIONS);
else if(DataStore.hasPersistent())
} else if(DataStore.hasPersistent()) {
Presence.sendActions(pChecksum);
}
}
} catch(e) {
Console.error('Avatar.handle', e);
@ -228,7 +235,7 @@ var Avatar = (function () {
try {
// Store the empty avatar
DataStore.setPersistent('global', 'avatar', xid, '<avatar><type>none</type><binval>none</binval><checksum>none</checksum><forced>false</forced></avatar>');
// Display the empty avatar
self.display(xid, hash, 'none', 'none');
} catch(e) {
@ -253,18 +260,19 @@ var Avatar = (function () {
// Initialize the vars
var container = hash + ' .avatar-container';
var code = '<img class="avatar" src="';
// If the avatar exists
if((type != 'none') && (binval != 'none'))
if((type != 'none') && (binval != 'none')) {
code += 'data:' + type + ';base64,' + binval;
else
} else {
code += './images/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
Utils.removeArrayValue(self.pending, xid);
} catch(e) {

View file

@ -17,12 +17,12 @@ var Base64 = (function () {
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);
@ -33,14 +33,14 @@ var Base64 = (function () {
} 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.
@ -50,22 +50,22 @@ var Base64 = (function () {
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);
}
@ -73,7 +73,7 @@ var Base64 = (function () {
output = output + String.fromCharCode(chr3);
}
} while (i < input.length);
return output;
}
};

View file

@ -20,6 +20,137 @@ var Board = (function () {
var self = {};
/* Contants */
self.NOTIFICATION = (window.Notification || window.mozNotification || window.webkitNotification);
/**
* Generate board info message
* @private
* @param {string} id
* @return {string}
*/
self._generateBoardInfo = function(id) {
var text = null;
try {
switch(id) {
// Password change
case 1:
text = Common._e("Your password has been changed, now you can connect to your account with your new login data.");
break;
// Account deletion
case 2:
text = Common._e("Your XMPP account has been removed, bye!");
break;
// Account logout
case 3:
text = Common._e("You have been logged out of your XMPP account, have a nice day!");
break;
// Groupchat join
case 4:
text = Common._e("The room you tried to join doesn't seem to exist.");
break;
// Groupchat removal
case 5:
text = Common._e("The groupchat has been removed.");
break;
// Non-existant groupchat user
case 6:
text = Common._e("The user that you want to reach is not present in the room.");
break;
}
} catch(e) {
Console.error('Board._generateBoardInfo', e);
} finally {
return text;
}
};
/**
* Generate board error message
* @private
* @param {string} id
* @return {string}
*/
self._generateBoardError = function(id) {
var text = null;
try {
switch(id) {
// Custom error
case 1:
text = '<b>' + Common._e("Error") + '</b> &raquo; <span></span>';
break;
// Network error
case 2:
text = Common._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 = Common._e("The element list on this server could not be obtained!");
break;
// Attaching error
case 4:
text = Common.printf(Common._e("An error occured while uploading your file: maybe it is too big (%s maximum) or forbidden!"), JAPPIX_MAX_UPLOAD);
break;
}
} catch(e) {
Console.error('Board._generateBoardError', e);
} finally {
return text;
}
};
/**
* Attaches board events
* @private
* @param {object} board_sel
* @return {undefined}
*/
self._attachEvents = function(board_sel) {
try {
board_sel.click(function() {
self.closeThis(this);
});
board_sel.oneTime('5s', function() {
self.closeThis(this);
});
board_sel.slideDown();
} catch(e) {
Console.error('Board._attachEvents', e);
}
};
/**
* Creates a board panel
* @public
@ -32,97 +163,29 @@ var Board = (function () {
try {
// Text var
var text = '';
// Info
if(type == 'info') {
switch(id) {
// Password change
case 1:
text = Common._e("Your password has been changed, now you can connect to your account with your new login data.");
break;
// Account deletion
case 2:
text = Common._e("Your XMPP account has been removed, bye!");
break;
// Account logout
case 3:
text = Common._e("You have been logged out of your XMPP account, have a nice day!");
break;
// Groupchat join
case 4:
text = Common._e("The room you tried to join doesn't seem to exist.");
break;
// Groupchat removal
case 5:
text = Common._e("The groupchat has been removed.");
break;
// Non-existant groupchat user
case 6:
text = Common._e("The user that you want to reach is not present in the room.");
break;
}
text = self._generateBoardInfo(id);
} else {
text = self._generateBoardError(id);
}
// Error
else {
switch(id) {
// Custom error
case 1:
text = '<b>' + Common._e("Error") + '</b> &raquo; <span></span>';
break;
// Network error
case 2:
text = Common._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 = Common._e("The element list on this server could not be obtained!");
break;
// Attaching error
case 4:
text = Common.printf(Common._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)
if(!text) {
return false;
}
// Append the content
$('#board').append('<div class="one-board ' + type + '" data-id="' + id + '">' + text + '</div>');
$('#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() {
self.closeThis(this);
})
.oneTime('5s', function() {
self.closeThis(this);
})
.slideDown();
self._attachEvents(
$('#board .one-board.' + type + '[data-id="' + id + '"]')
);
return true;
} catch(e) {
Console.error('Board.create', e);
@ -158,7 +221,7 @@ var Board = (function () {
try {
// In a first, we destroy other boards
self.destroy();
// Then we display the board
self.create(type, id);
} catch(e) {
@ -235,99 +298,74 @@ var Board = (function () {
try {
// Cannot process?
if(Common.isFocused() || !content || !(window.webkitNotifications || window.Notification)) {
if(Common.isFocused() || !content || !self.NOTIFICATION) {
return;
}
// Default icon?
if(!icon) {
icon = './images/others/default-avatar.png';
// Avatar icon?
if(xid) {
var avatar_xml = Common.XMLFromString(
DataStore.getPersistent('global', 'avatar', xid)
);
var avatar_type = $(avatar_xml).find('type').text() || 'image/png';
var avatar_binval = $(avatar_xml).find('binval').text();
if(avatar_binval && avatar_type)
if(avatar_binval && avatar_type) {
icon = 'data:' + avatar_type + ';base64,' + avatar_binval;
}
}
}
// Default title?
if(!title) {
title = Common._e("New event!");
}
// Click callback
var cb_click_fn = function() {
// Create notification
var notification = new self.NOTIFICATION(title, {
dir: 'auto',
lang: '',
body: content,
tag: type,
icon: icon
});
// Click event
notification.onclick = function() {
// Click action?
switch(type) {
case 'chat':
Interface.switchChan(hex_md5(xid));
break;
case 'groupchat':
Interface.switchChan(hex_md5(Common.bareXID(xid)));
break;
default:
break;
}
// Focus on msg-me
window.focus();
// Remove notification
this.cancel();
this.close();
};
// Check for notification permission
try {
if(Notification.permission == 'granted' || Notification.permission === undefined) {
var notification = new Notification(title, {
dir: 'auto',
lang: '',
body: content,
tag: type,
icon: icon
});
notification.onclick = cb_click_fn;
// Show event
notification.onshow = function() {
setTimeout(function() {
notification.close();
}, 10000);
};
setTimeout(function() {
notification.close();
}, 10000);
if(notification.permission == 'granted') {
return notification;
}
}
} catch(_e) {
if(window.webkitNotifications.checkPermission() === 0) {
// Create notification
var notification = window.webkitNotifications.createNotification(icon, title, content);
// Auto-hide after a while
notification.ondisplay = function(event) {
setTimeout(function() {
event.currentTarget.cancel();
}, 10000);
};
// Click event
notification.onclick = cb_click_fn;
// Show notification
notification.show();
return notification;
}
}
return null;
return notification;
} catch(e) {
Console.error('Board.quick', e);
}
@ -343,21 +381,7 @@ var Board = (function () {
self.quickPermission = function() {
try {
try {
// W3C Notification API (still a draft!)
if(Notification.permission !== 'granted') {
// Ask for permission
Notification.requestPermission();
}
} catch (_e) {
// WebKit Notification API (fallback)
if(!window.webkitNotifications || (window.webkitNotifications.checkPermission() === 0)) {
return;
}
// Ask for permission
window.webkitNotifications.requestPermission();
}
self.NOTIFICATION.requestPermission();
} catch(e) {
Console.error('Board.quickPermission', e);
}
@ -376,8 +400,9 @@ var Board = (function () {
// Fires quickPermission() on document click
$(document).click(function() {
// Ask for permission to use quick boards
if((typeof con != 'undefined') && con.connected())
if((typeof con != 'undefined') && con.connected()) {
self.quickPermission();
}
});
} catch(e) {
Console.error('Board.launch', e);

View file

@ -6,12 +6,12 @@
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.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;
@ -25,13 +25,13 @@ var BrowserDetect = {
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,
@ -97,7 +97,7 @@ var BrowserDetect = {
versionSearch: "Mozilla"
}
],
dataOS : [
{
string: navigator.platform,

View file

@ -31,6 +31,7 @@ var Bubble = (function () {
// Destroy all the elements
$('.bubble.hidable:visible').hide();
$('.bubble.removable').remove();
$('body').off('click');
} catch(e) {
Console.error('Bubble.close', e);
@ -53,33 +54,36 @@ var Bubble = (function () {
// Hidable bubbles special things
if($(selector).is('.hidable')) {
// This bubble is yet displayed? So abort!
if($(selector).is(':visible'))
if($(selector).is(':visible')) {
return self.close();
}
// Close all the bubbles
self.close();
// Show the requested bubble
$(selector).show();
}
// Removable bubbles special things
else {
// This bubble is yet added? So abort!
if(Common.exists(selector))
if(Common.exists(selector)) {
return self.close();
}
// Close all the bubbles
self.close();
}
// Creates a new click event to close the bubble
$('body').on('click', function(evt) {
var target = evt.target;
// If this is a click away from a bubble
if(!$(target).parents('.ibubble').size())
if(!$(target).parents('.ibubble').size()) {
self.close();
}
});
} catch(e) {
Console.error('Bubble.show', e);

File diff suppressed because it is too large Load diff

View file

@ -20,6 +20,444 @@ var Caps = (function () {
var self = {};
/* Constants */
self.disco_infos = {
'identity': {
'category': 'client',
'type': 'web',
'name': 'Jappix'
},
'items': [
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_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_URN_MAM,
NS_IPV6,
NS_LAST,
NS_PRIVATE,
NS_REGISTER,
NS_SEARCH,
NS_COMMANDS,
NS_VERSION,
NS_XDATA,
NS_VCARD,
NS_IETF_VCARD4,
NS_URN_ADATA,
NS_URN_AMETA,
NS_URN_TIME,
NS_URN_PING,
NS_URN_RECEIPTS,
NS_PRIVACY,
NS_IQOOB,
NS_XOOB,
NS_URN_CARBONS,
NS_URN_CORRECT,
NS_URN_MARKERS,
NS_URN_IDLE,
NS_URN_ATTENTION,
NS_URN_REACH,
NS_URN_HINTS
]
};
/**
* Parse identities from disco infos query response
* @private
* @param {object} query
* @return {object}
*/
self._parseDiscoIdentities = function(query) {
var identities = [];
try {
var cur_category, cur_type, cur_lang, cur_name;
$(query).find('identity').each(function() {
cur_category = $(this).attr('category') || '';
cur_type = $(this).attr('type') || '';
cur_lang = $(this).attr('xml:lang') || '';
cur_name = $(this).attr('name') || '';
identities.push(cur_category + '/' + cur_type + '/' + cur_lang + '/' + cur_name);
});
} catch(e) {
Console.error('Caps._parseDiscoIdentities', e);
} finally {
return identities;
}
};
/**
* Parse features from disco infos query response
* @private
* @param {object} query
* @return {object}
*/
self._parseDiscoFeatures = function(query) {
var features = [];
try {
var cur_var;
$(query).find('feature').each(function() {
cur_var = $(this).attr('var');
// Add the current value to the array
if(cur_var) {
features.push(cur_var);
}
});
} catch(e) {
Console.error('Caps._parseDiscoFatures', e);
} finally {
return features;
}
};
/**
* Parse data form from disco infos query response
* @private
* @param {object} query
* @return {object}
*/
self._parseDiscoDataForms = function(query) {
var data_forms = [];
try {
var cur_string, cur_sort_var,
cur_text, cur_var, cur_sort_val;
$(query).find('x[xmlns="' + NS_XDATA + '"]').each(function() {
// Initialize some stuffs
cur_string = '';
cur_sort_var = [];
// Add the form type field
$(this).find('field[var="FORM_TYPE"] value').each(function() {
cur_text = $(this).text();
if(cur_text) {
cur_string += cur_text + '<';
}
});
// Add the var attributes into an array
$(this).find('field:not([var="FORM_TYPE"])').each(function() {
cur_var = $(this).attr('var');
if(cur_var) {
cur_sort_var.push(cur_var);
}
});
// Sort the var attributes
cur_sort_var = cur_sort_var.sort();
// Loop this sorted var attributes
$.each(cur_sort_var, function(i) {
// Initialize the value sorting
cur_sort_val = [];
// Append it to the string
cur_string += cur_sort_var[i] + '<';
// Add each value to the array
$(this).find('field[var=' + cur_sort_var[i] + '] value').each(function() {
cur_sort_val.push($(this).text());
});
// Sort the values
cur_sort_val = cur_sort_val.sort();
// Append the values to the string
for(var j in cur_sort_val) {
cur_string += cur_sort_val[j] + '<';
}
});
// Any string?
if(cur_string) {
// Remove the undesired double '<' from the string
if(cur_string.match(/(.+)(<)+$/)) {
cur_string = cur_string.substring(0, cur_string.length - 1);
}
// Add the current string to the array
data_forms.push(cur_string);
}
});
} catch(e) {
Console.error('Caps._parseDiscoDataForms', e);
} finally {
return data_forms;
}
};
/**
* Apply XHTML-IM features from disco infos
* @private
* @param {string} xid
* @param {object} features
* @param {object} style_sel
* @param {object} message_area_sel
* @return {undefined}
*/
self._applyDiscoXHTMLIM = function(xid, features, style_sel, message_area_sel) {
try {
// Apply
if(NS_XHTML_IM in features) {
style_sel.show();
} else {
// Remove the tooltip elements
style_sel.hide();
style_sel.find('.bubble-style').remove();
// Reset the markers
message_area_sel.removeAttr('style')
.removeAttr('data-font')
.removeAttr('data-fontsize')
.removeAttr('data-color')
.removeAttr('data-bold')
.removeAttr('data-italic')
.removeAttr('data-underline');
}
} catch(e) {
Console.error('Caps._applyDiscoXHTMLIM', e);
}
};
/**
* Apply Jingle features from disco infos
* @private
* @param {string} xid
* @param {object} path_sel
* @param {object} roster_sel
* @return {undefined}
*/
self._applyDiscoJingle = function(xid, path_sel, roster_sel) {
try {
// Selectors
var roster_jingle_sel = roster_sel.find('.buddy-infos .call-jingle');
var jingle_audio = path_sel.find('.tools-jingle-audio');
var roster_jingle_audio = roster_jingle_sel.find('a.audio');
var jingle_video = path_sel.find('.tools-jingle-video');
var roster_jingle_video = roster_jingle_sel.find('a.video');
var roster_jingle_separator = roster_jingle_sel.find('span.separator');
// Apply
var jingle_local_supported = JSJAC_JINGLE_AVAILABLE;
var jingle_audio_xid = self.getFeatureResource(xid, NS_JINGLE_APPS_RTP_AUDIO);
var jingle_video_xid = self.getFeatureResource(xid, NS_JINGLE_APPS_RTP_VIDEO);
if(jingle_audio_xid && jingle_local_supported) {
jingle_audio.show();
roster_jingle_audio.show();
} else {
jingle_audio.hide();
roster_jingle_audio.hide();
}
if(jingle_video_xid && jingle_local_supported) {
jingle_video.show();
roster_jingle_video.show();
} else {
jingle_video.hide();
roster_jingle_video.hide();
}
if(jingle_audio_xid && jingle_video_xid && jingle_local_supported) {
roster_jingle_separator.show();
} else {
roster_jingle_separator.hide();
}
if((jingle_audio_xid || jingle_video_xid) && jingle_local_supported) {
roster_jingle_sel.show();
} else {
roster_jingle_sel.hide();
}
} catch(e) {
Console.error('Caps._applyDiscoJingle', e);
}
};
/**
* Apply Out of Band Data features from disco infos
* @private
* @param {string} xid
* @param {object} features
* @param {object} file_sel
* @return {undefined}
*/
self._applyDiscoOOB = function(xid, features, file_sel) {
try {
// Apply
var iq_oob_xid = self.getFeatureResource(xid, NS_IQOOB);
if(iq_oob_xid || NS_XOOB in features) {
file_sel.show();
// Set a marker
file_sel.attr(
'data-oob',
iq_oob_xid ? 'iq' : 'x'
);
} else {
// Remove the tooltip elements
file_sel.hide();
file_sel.find('.bubble-style').remove();
// Reset the marker
file_sel.removeAttr('data-oob');
}
} catch(e) {
Console.error('Caps._applyDiscoOOB', e);
}
};
/**
* Apply Receipts features from disco infos
* @private
* @param {string} xid
* @param {object} features
* @param {object} message_area_sel
* @return {undefined}
*/
self._applyDiscoReceipts = function(xid, features, message_area_sel) {
try {
// Apply
if(NS_URN_RECEIPTS in features) {
message_area_sel.attr('data-receipts', 'true');
} else {
message_area_sel.removeAttr('data-receipts');
}
} catch(e) {
Console.error('Caps._applyDiscoReceipts', e);
}
};
/**
* Apply Last Message Correction features from disco infos
* @private
* @param {string} xid
* @param {object} features
* @param {object} path_sel
* @return {undefined}
*/
self._applyDiscoCorrection = function(xid, features, path_sel) {
try {
// Apply
if(NS_URN_CORRECT in features) {
path_sel.attr('data-correction', 'true');
} else {
path_sel.removeAttr('data-correction');
}
} catch(e) {
Console.error('Caps._applyDiscoCorrection', e);
}
};
/**
* Apply Chat Markers features from disco infos
* @private
* @param {string} xid
* @param {object} features
* @param {object} path_sel
* @return {undefined}
*/
self._applyDiscoMarkers = function(xid, features, path_sel) {
try {
// Apply
if(NS_URN_MARKERS in features) {
path_sel.attr('data-markers', 'true');
} else {
path_sel.removeAttr('data-markers');
}
} catch(e) {
Console.error('Caps._applyDiscoMarkers', e);
}
};
/**
* Apply Attention features from disco infos
* @private
* @param {string} xid
* @param {object} features
* @param {object} path_sel
* @return {undefined}
*/
self._applyDiscoAttention = function(xid, features, path_sel) {
try {
// Apply
if(NS_URN_ATTENTION in features) {
path_sel.attr('data-attention', 'true');
} else {
path_sel.removeAttr('data-attention');
}
} catch(e) {
Console.error('Caps._applyDiscoAttention', e);
}
};
/**
* Reads a stored Caps
* @public
@ -47,62 +485,12 @@ var Caps = (function () {
self.myDiscoInfos = function() {
try {
var disco_base = [
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_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_URN_MAM,
NS_IPV6,
NS_LAST,
NS_PRIVATE,
NS_REGISTER,
NS_SEARCH,
NS_COMMANDS,
NS_VERSION,
NS_XDATA,
NS_VCARD,
NS_IETF_VCARD4,
NS_URN_ADATA,
NS_URN_AMETA,
NS_URN_TIME,
NS_URN_PING,
NS_URN_RECEIPTS,
NS_PRIVACY,
NS_IQOOB,
NS_XOOB,
NS_URN_CARBONS
];
var disco_base = self.disco_infos.items;
var disco_jingle = JSJaCJingle_disco();
var disco_jingle = JSJaCJingle.disco();
var disco_all = disco_base.concat(disco_jingle);
return disco_all;
return Utils.uniqueArrayValues(disco_all);
} catch(e) {
Console.error('Caps.myDiscoInfos', e);
}
@ -123,35 +511,35 @@ var Caps = (function () {
// No CAPS
if(!caps) {
Console.warn('No CAPS: ' + to);
self.displayDiscoInfos(to, '');
return false;
}
// Get the stored disco infos
var xml = self.read(caps);
// Yet stored
if(xml) {
Console.info('CAPS from cache: ' + to);
self.displayDiscoInfos(to, xml);
return true;
}
Console.info('CAPS from the network: ' + to);
// Not stored: get the disco#infos
var iq = new JSJaCIQ();
iq.setTo(to);
iq.setType('get');
iq.setQuery(NS_DISCO_INFO);
con.send(iq, self.handleDiscoInfos);
return true;
} catch(e) {
Console.error('Caps.getDiscoInfos', e);
@ -169,123 +557,37 @@ var Caps = (function () {
self.handleDiscoInfos = function(iq) {
try {
if(!iq || (iq.getType() == 'error'))
if(!iq || (iq.getType() == 'error')) {
return;
// IQ received, get some values
}
var from = Common.fullXID(Common.getStanzaFrom(iq));
var query = iq.getQuery();
// Generate the CAPS-processing values
var identities = [];
var features = [];
var data_forms = [];
// 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 = [];
// 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
$.each(sortVar, function(i) {
// Initialize the value sorting
var sortVal = [];
// 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(var 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);
}
});
// Parse values
var identities = self._parseDiscoIdentities(query);
var features = self._parseDiscoFeatures(query);
var data_forms = self._parseDiscoDataForms(query);
// Process the CAPS
var caps = self.process(identities, features, data_forms);
// Get the XML string
var xml = Common.xmlToString(query);
// Store the disco infos
DataStore.setPersistent('global', 'caps', caps, xml);
// This is our server
if(from == Utils.getServer()) {
// Handle the features
Features.handle(xml);
Console.info('Got our server CAPS');
} else {
// Display the disco infos
self.displayDiscoInfos(from, xml);
Console.info('Got CAPS: ' + from);
}
} catch(e) {
@ -307,11 +609,12 @@ var Caps = (function () {
try {
// Generate the chat path
var xid = Common.bareXID(from);
// This comes from a private groupchat chat?
if(Utils.isPrivate(xid))
if(Utils.isPrivate(xid)) {
xid = from;
}
hash = hex_md5(xid);
// Display the supported features
@ -324,98 +627,22 @@ var Caps = (function () {
features[current] = 1;
}
});
// Paths
var path = $('#' + hash);
var roster_path = $('#roster .buddy.' + hash);
var roster_jingle_path = roster_path.find('.buddy-infos .call-jingle');
var path_sel = $('#' + hash);
var roster_sel = $('#roster .buddy.' + hash);
var message_area_sel = path_sel.find('.message-area');
var style_sel = path_sel.find('.chat-tools-style');
var file_sel = path_sel.find('.chat-tools-file');
var message_area = path.find('.message-area');
var style = path.find('.chat-tools-style');
var jingle_audio = path.find('.tools-jingle-audio');
var roster_jingle_audio = roster_jingle_path.find('a.audio');
var jingle_video = path.find('.tools-jingle-video');
var roster_jingle_video = roster_jingle_path.find('a.video');
var roster_jingle_separator = roster_jingle_path.find('span.separator');
var file = path.find('.chat-tools-file');
// Apply xHTML-IM
if(NS_XHTML_IM in features) {
style.show();
} else {
// Remove the tooltip elements
style.hide();
style.find('.bubble-style').remove();
// Reset the markers
message_area.removeAttr('style')
.removeAttr('data-font')
.removeAttr('data-fontsize')
.removeAttr('data-color')
.removeAttr('data-bold')
.removeAttr('data-italic')
.removeAttr('data-underline');
}
// Apply Jingle
var jingle_local_supported = JSJAC_JINGLE_AVAILABLE;
var jingle_audio_xid = self.getFeatureResource(xid, NS_JINGLE_APPS_RTP_AUDIO);
var jingle_video_xid = self.getFeatureResource(xid, NS_JINGLE_APPS_RTP_VIDEO);
if(jingle_audio_xid && jingle_local_supported) {
jingle_audio.show();
roster_jingle_audio.show();
} else {
jingle_audio.hide();
roster_jingle_audio.hide();
}
if(jingle_video_xid && jingle_local_supported) {
jingle_video.show();
roster_jingle_video.show();
} else {
jingle_video.hide();
roster_jingle_video.hide();
}
if(jingle_audio_xid && jingle_video_xid && jingle_local_supported) {
roster_jingle_separator.show();
} else {
roster_jingle_separator.hide();
}
if((jingle_audio_xid || jingle_video_xid) && jingle_local_supported) {
roster_jingle_path.show();
} else {
roster_jingle_path.hide();
}
// Apply Out of Band Data
var iq_oob_xid = self.getFeatureResource(xid, NS_IQOOB);
if(iq_oob_xid || NS_XOOB in features) {
file.show();
// Set a marker
file.attr(
'data-oob',
iq_oob_xid ? 'iq' : 'x'
);
} else {
// Remove the tooltip elements
file.hide();
file.find('.bubble-style').remove();
// Reset the marker
file.removeAttr('data-oob');
}
// Apply receipts
if(NS_URN_RECEIPTS in features) {
message_area.attr('data-receipts', 'true');
} else {
message_area.removeAttr('data-receipts');
}
// Apply Features
self._applyDiscoXHTMLIM(xid, features, style_sel, message_area_sel);
self._applyDiscoJingle(xid, path_sel, roster_sel);
self._applyDiscoOOB(xid, features, file_sel);
self._applyDiscoReceipts(xid, features, message_area_sel);
self._applyDiscoCorrection(xid, features, path_sel);
self._applyDiscoMarkers(xid, features, path_sel);
self._applyDiscoAttention(xid, features, path_sel);
} catch(e) {
Console.error('Caps.displayDiscoInfos', e);
}
@ -426,40 +653,40 @@ var Caps = (function () {
/**
* Generates the CAPS hash
* @public
* @param {object} cIdentities
* @param {object} cFeatures
* @param {object} cDataForms
* @param {object} identities
* @param {object} features
* @param {object} dataforms
* @return {string}
*/
self.process = function(cIdentities, cFeatures, cDataForms) {
self.process = function(identities, features, dataforms) {
try {
// Initialize
var cString = '';
var caps_str = '';
// Sort the arrays
cIdentities = cIdentities.sort();
cFeatures = cFeatures.sort();
cDataForms = cDataForms.sort();
identities = identities.sort();
features = features.sort();
dataforms = dataforms.sort();
// Process the sorted identity string
for(var a in cIdentities) {
cString += cIdentities[a] + '<';
for(var a in identities) {
caps_str += identities[a] + '<';
}
// Process the sorted feature string
for(var b in cFeatures) {
cString += cFeatures[b] + '<';
for(var b in features) {
caps_str += features[b] + '<';
}
// Process the sorted data-form string
for(var c in cDataForms) {
cString += cDataForms[c] + '<';
for(var c in dataforms) {
caps_str += dataforms[c] + '<';
}
// Process the SHA-1 hash
var cHash = b64_sha1(cString);
var cHash = b64_sha1(caps_str);
return cHash;
} catch(e) {
Console.error('Caps.process', e);
@ -477,7 +704,12 @@ var Caps = (function () {
try {
return self.process(
['client/web//Jappix'],
[
self.disco_infos.identity.category + '/' +
self.disco_infos.identity.type + '//' +
self.disco_infos.identity.name
],
self.myDiscoInfos(),
[]
);
@ -507,8 +739,14 @@ var Caps = (function () {
var max_priority = null;
var cur_xid_full, cur_presence_sel, cur_caps, cur_features, cur_priority;
for(var cur_resource in Presence.resources(xid)) {
cur_xid_full = xid + '/' + cur_resource;
var resources_obj = Presence.resources(xid);
var fn_parse_resource = function(cur_resource) {
cur_xid_full = xid;
if(cur_resource) {
cur_xid_full += '/' + cur_resource;
}
cur_presence_sel = $(Presence.readStanza(cur_xid_full));
cur_priority = parseInt((cur_presence_sel.find('priority').text() || 0), 10);
@ -523,6 +761,14 @@ var Caps = (function () {
selected_xid = cur_xid_full;
}
}
};
if(resources_obj.bare === 1) {
fn_parse_resource(null);
}
for(var cur_resource in resources_obj.list) {
fn_parse_resource(cur_resource);
}
} catch(e) {
Console.error('Caps.getFeatureResource', e);
@ -538,4 +784,4 @@ var Caps = (function () {
*/
return self;
})();
})();

View file

@ -22,7 +22,7 @@ var Carbons = (function () {
/**
* Configures Message Carbons options
* @public
* @private
* @param {string} type
* @return {undefined}
*/
@ -35,9 +35,9 @@ var Carbons = (function () {
var iq = new JSJaCIQ();
iq.setType('set');
iq.appendNode(type, {'xmlns': NS_URN_CARBONS});
con.send(iq, function(iq) {
self._handleConfigure(iq, type);
});
@ -50,7 +50,7 @@ var Carbons = (function () {
/**
* Configures Message Carbons options
* @public
* @private
* @param {object} iq
* @param {string} type
* @return {undefined}
@ -193,6 +193,9 @@ var Carbons = (function () {
} else {
Console.debug('Got a sent message from another resource to: ' + (to || 'none') + ', was ignored because body empty');
}
// Handle chat markers change
Markers.handleCarbonChange(forwarded_message);
} else {
Console.debug('Got a sent message from another resource to: ' + (to || 'none') + ', was ignored because chat not open');
}

View file

@ -20,6 +20,290 @@ var Chat = (function () {
var self = {};
/**
* Apply generate events
* @private
* @param {string} path
* @param {string} id
* @param {string} xid
* @return {undefined}
*/
self._generateEvents = function(path, id, xid) {
try {
// Click event: chat cleaner
$(path + 'tools-clear').click(function() {
self.clean(id);
});
// Click event: call (audio)
$(path + 'tools-jingle-audio').click(function() {
Jingle.start(xid, 'audio');
});
// Click event: call (video)
$(path + 'tools-jingle-video').click(function() {
Jingle.start(xid, 'video');
});
// Click event: user-infos
$(path + 'tools-infos').click(function() {
UserInfos.open(xid);
});
} catch(e) {
Console.error('Chat._generateEvents', e);
}
};
/**
* Apply generate events
* @private
* @param {object} input_sel
* @param {string} xid
* @param {string} hash
* @return {undefined}
*/
self._createEvents = function(input_sel, xid, hash) {
try {
self._createEventsInput(input_sel, hash);
self._createEventsKey(input_sel, xid, hash);
self._createEventsMouse(xid, hash);
} catch(e) {
Console.error('Chat._createEvents', e);
}
};
/**
* Apply generate events (input)
* @private
* @param {object} input_sel
* @param {string} hash
* @return {undefined}
*/
self._createEventsInput = function(input_sel, hash) {
try {
input_sel.focus(function() {
// Clean notifications for this chat
Interface.chanCleanNotify(hash);
// Store focus on this chat!
Interface.chat_focus_hash = hash;
});
input_sel.blur(function() {
// Reset storage about focus on this chat!
if(Interface.chat_focus_hash == hash) {
Interface.chat_focus_hash = null;
}
});
} catch(e) {
Console.error('Chat._createEventsInput', e);
}
};
/**
* Apply generate events (key)
* @private
* @param {object} input_sel
* @param {string} xid
* @param {string} hash
* @return {undefined}
*/
self._createEventsKey = function(input_sel, xid, hash) {
try {
input_sel.keydown(function(e) {
if(e.keyCode == 13) {
// Enter key
if(e.shiftKey || e.ctrlKey) {
// Add a new line
input_sel.val(input_sel.val() + '\n');
} else {
if(Correction.isIn(xid) === true) {
var corrected_value = input_sel.val().trim();
if(corrected_value) {
// Send the corrected message
Correction.send(xid, 'chat', corrected_value);
}
Correction.leave(xid);
} else {
// Send the message
Message.send(hash, 'chat');
}
// Reset the composing database entry
DataStore.setDB(Connection.desktop_hash, 'chatstate', xid, 'off');
}
return false;
} else if(e.keyCode == 8) {
// Leave correction mode? (another way, by flushing input value progressively)
if(Correction.isIn(xid) === true && !input_sel.val()) {
Correction.leave(xid);
}
}
});
input_sel.keyup(function(e) {
if(e.keyCode == 27) {
// Escape key
input_sel.val('');
// Leave correction mode? (simple escape way)
if(Correction.isIn(xid) === true) {
Correction.leave(xid);
}
} else {
Correction.detect(xid, input_sel);
}
});
} catch(e) {
Console.error('Chat._createEventsKey', e);
}
};
/**
* Apply generate events (mouse)
* @private
* @param {string} xid
* @param {string} hash
* @return {undefined}
*/
self._createEventsMouse = function(xid, hash) {
try {
// Scroll in chat content
$('#page-engine #' + hash + ' .content').scroll(function() {
var self = this;
if(Features.enabledMAM() && !(xid in MAM.map_pending)) {
var has_state = xid in MAM.map_states;
var rsm_count = has_state ? MAM.map_states[xid].rsm.count : 1;
var rsm_before = has_state ? MAM.map_states[xid].rsm.first : '';
// Request more archives?
if(rsm_count > 0 && $(this).scrollTop() < MAM.SCROLL_THRESHOLD) {
var was_scroll_top = $(self).scrollTop() <= 32;
var wait_mam = $('#' + hash).find('.wait-mam');
wait_mam.show();
MAM.getArchives({
'with': xid
}, {
'max': MAM.REQ_MAX,
'before': rsm_before
}, function() {
var wait_mam_height = was_scroll_top ? 0 : wait_mam.height();
wait_mam.hide();
// Restore scroll?
if($(self).scrollTop() < MAM.SCROLL_THRESHOLD) {
var sel_mam_chunk = $(self).find('.mam-chunk:first');
var cont_padding_top = parseInt($(self).css('padding-top').replace(/[^-\d\.]/g, ''));
var cont_one_group_margin_bottom = parseInt(sel_mam_chunk.find('.one-group:last').css('margin-bottom').replace(/[^-\d\.]/g, ''));
var cont_mam_chunk_height = sel_mam_chunk.height();
$(self).scrollTop(wait_mam_height + cont_padding_top + cont_one_group_margin_bottom + cont_mam_chunk_height);
}
});
}
}
});
} catch(e) {
Console.error('Chat._createEventsMouse', e);
}
};
/**
* Apply generate events
* @private
* @param {string} type
* @param {string} id
* @param {string} xid
* @return {object}
*/
self._generateChatCode = function(type, id, xid) {
var code_args = {};
try {
// Groupchat special code
if(type == 'groupchat') {
code_args.attributes = ' data-type="groupchat" data-correction="true"';
code_args.avatar = '';
code_args.name = '<p class="bc-infos"><b>' + Common._e("Subject") + '</b> <span class="muc-topic">' + Common._e("no subject defined for this room.") + '</span></p>';
code_args.code = '<div class="content groupchat-content" id="chat-content-' + id + '"></div>' +
'<div class="list"><div class="moderator role"><p class="title">' + Common._e("Moderators") + '</p></div>' +
'<div class="participant role"><p class="title">' + Common._e("Participants") + '</p></div>' +
'<div class="visitor role"><p class="title">' + Common._e("Visitors") + '</p></div>' +
'<div class="none role"><p class="title">' + Common._e("Others") + '</p></div></div>';
code_args.link = '<a href="#" class="tools-mucadmin tools-tooltip talk-images chat-tools-content" title="' + Common._e("Administration panel for this room") + '"></a>';
code_args.style = '';
// Is this a gateway?
if(xid.match(/%/)) {
code_args.disabled = '';
} else {
code_args.disabled = ' disabled=""';
}
} else {
code_args.mam = '<div class="wait-mam wait-small"></div>';
code_args.attributes = ' data-type="chat"';
code_args.avatar = '<div class="avatar-container"><img class="avatar" src="' + './images/others/default-avatar.png' + '" alt="" /></div>';
code_args.name = '<div class="bc-pep"></div><p class="bc-infos"><span class="unavailable show talk-images"></span></p>';
code_args.code = '<div class="content" id="chat-content-' + id + '">' + code_args.mam + '</div>';
code_args.link = '<a href="#" class="tools-jingle-audio tools-tooltip talk-images chat-tools-content" title="' + Common._e("Call (audio only)") + '"></a>' +
'<a href="#" class="tools-jingle-video tools-tooltip talk-images chat-tools-content" title="' + Common._e("Call (video)") + '"></a>' +
'<a href="#" class="tools-infos tools-tooltip talk-images chat-tools-content" title="' + Common._e("Show user profile") + '"></a>';
code_args.style = ' style="display: none;"';
code_args.disabled = '';
}
// Not a groupchat private chat, we can use the buddy add icon
if((type == 'chat') || (type == 'groupchat')) {
var title;
if(type == 'chat') {
title = Common._e("Add this contact to your friends");
} else {
title = Common._e("Add this groupchat to your favorites");
}
code_args.link += '<a href="#" class="tools-add tools-tooltip talk-images chat-tools-content" title="' + title + '"></a>';
}
// IE DOM parsing bug fix
code_args.style_picker = '<div class="chat-tools-content chat-tools-style"' + code_args.style + '>' +
'<a href="#" class="tools-style tools-tooltip talk-images"></a>' +
'</div>';
if((BrowserDetect.browser == 'Explorer') && (BrowserDetect.version < 9)) {
code_args.style_picker = '';
}
} catch(e) {
Console.error('Chat._generateChatCode', e);
} finally {
return code_args;
}
};
/**
* Correctly opens a new chat
* @public
@ -34,38 +318,40 @@ var Chat = (function () {
try {
// No XID?
if(!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)
if(title) {
name = title;
else {
} else {
// Private groupchat chat
if(type == 'private')
if(type == 'private') {
name = Common.thisResource(xid);
}
// XMPP-ID
else if(xid.indexOf('@') != -1)
else if(xid.indexOf('@') != -1) {
name = Name.getBuddy(xid);
}
// Gateway
else
else {
name = xid;
}
}
// If the target div does not exist
if(!Common.exists('#' + hash)) {
// We check the type of the chat to open
if((type == 'chat') || (type == 'private'))
if((type == 'chat') || (type == 'private')) {
self.create(hash, xid, name, type);
else if(type == 'groupchat') {
} else if(type == 'groupchat') {
// Try to read the room stored configuration
if(!Utils.isAnonymous() && (!nickname || !password || !title)) {
// Catch the room data
@ -73,7 +359,7 @@ var Chat = (function () {
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;
@ -82,11 +368,11 @@ var Chat = (function () {
if(!title && fName)
name = fName;
}
Groupchat.create(hash, xid, name, nickname, password);
}
}
// Switch to the newly-created chat
Interface.switchChan(hash);
} catch(e) {
@ -113,121 +399,53 @@ var Chat = (function () {
// Generate some stuffs
var path = '#' + id + ' .';
var escaped_xid = escape(xid);
// Special code
var specialAttributes, specialAvatar, specialName, specialCode, specialLink, specialDisabled, specialStyle, specialMAM;
// Groupchat special code
if(type == 'groupchat') {
specialAttributes = ' data-type="groupchat"';
specialAvatar = '';
specialName = '<p class="bc-infos"><b>' + Common._e("Subject") + '</b> <span class="muc-topic">' + Common._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">' + Common._e("Moderators") + '</p></div><div class="participant role"><p class="title">' + Common._e("Participants") + '</p></div><div class="visitor role"><p class="title">' + Common._e("Visitors") + '</p></div><div class="none role"><p class="title">' + Common._e("Others") + '</p></div></div>';
specialLink = '<a href="#" class="tools-mucadmin tools-tooltip talk-images chat-tools-content" title="' + Common._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 {
specialMAM = '<div class="wait-mam wait-small"></div>';
specialAttributes = ' data-type="chat"';
specialAvatar = '<div class="avatar-container"><img class="avatar" src="' + './images/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 + '">' + specialMAM + '</div>';
specialLink = '<a href="#" class="tools-jingle-audio tools-tooltip talk-images chat-tools-content" title="' + Common._e("Call (audio only)") + '"></a>' +
'<a href="#" class="tools-jingle-video tools-tooltip talk-images chat-tools-content" title="' + Common._e("Call (video)") + '"></a>' +
'<a href="#" class="tools-infos tools-tooltip talk-images chat-tools-content" title="' + Common._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 = Common._e("Add this contact to your friends");
else
addTitle = Common._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 = '';
var chat_args = self._generateChatCode(type, id, xid);
// 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="' + Common._e("Clean current chat") + '"></a>' +
specialLink +
'</div>' +
'<div class="compose">' +
'<textarea class="message-area focusable" ' + specialDisabled + ' data-to="' + escaped_xid + '" /></textarea>' +
'</div>' +
'</div>' +
'<div id="' + id + '" class="page-engine-chan chat one-counter"' + chat_args.attributes + ' data-xid="' + escaped_xid + '">' +
'<div class="top ' + id + '">' +
chat_args.avatar +
'<div class="name">' +
'<p class="bc-name bc-name-nick">' + nick.htmlEnc() + '</p>' +
chat_args.name +
'</div>' +
'</div>' +
chat_args.code +
'<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>' +
chat_args.style_picker +
'<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="' + Common._e("Clean current chat") + '"></a>' +
chat_args.link +
'</div>' +
'<div class="compose">' +
'<textarea class="message-area focusable" ' + chat_args.disabled + ' data-to="' + escaped_xid + '" /></textarea>' +
'</div>' +
'</div>' +
'</div>'
);
// Click event: chat cleaner
$(path + 'tools-clear').click(function() {
self.clean(id);
});
// Click event: call (audio)
$(path + 'tools-jingle-audio').click(function() {
Jingle.start(xid, 'audio');
});
// Click event: call (video)
$(path + 'tools-jingle-video').click(function() {
Jingle.start(xid, 'video');
});
// Click event: user-infos
$(path + 'tools-infos').click(function() {
UserInfos.open(xid);
});
self._generateEvents(path, id, xid);
} catch(e) {
Console.error('Chat.generate', e);
}
@ -249,32 +467,38 @@ var Chat = (function () {
try {
// Path to the element
var chat_switch = '#page-switch .';
// Special code
var specialClass = ' unavailable';
var special_class = ' unavailable';
var show_close = true;
// Groupchat
if(type == 'groupchat') {
specialClass = ' groupchat-default';
if(Utils.isAnonymous() && (xid == Common.generateXID(ANONYMOUS_ROOM, 'groupchat')))
special_class = ' groupchat-default';
if(Utils.isAnonymous() && (xid == Common.generateXID(ANONYMOUS_ROOM, 'groupchat'))) {
show_close = false;
}
}
// Generate the HTML code
var html = '<div class="' + id + ' switcher chan" onclick="return Interface.switchChan(\'' + Utils.encodeOnclick(id) + '\')">' +
'<div class="icon talk-images' + specialClass + '"></div>' +
'<div class="name">' + nick.htmlEnc() + '</div>';
var html = '<div class="' + id + ' switcher chan" onclick="return Interface.switchChan(\'' + Utils.encodeOnclick(id) + '\')">' +
'<div class="icon talk-images' + special_class + '"></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="' + Common._e("Close this tab") + '" onclick="return Interface.quitThisChat(\'' + Utils.encodeOnclick(xid) + '\', \'' + Utils.encodeOnclick(id) + '\', \'' + Utils.encodeOnclick(type) + '\');">x</div>';
if(show_close) {
html += '<div class="exit" ' +
'title="' + Common._e("Close this tab") + '" ' +
'onclick="return Interface.quitThisChat(\'' + Utils.encodeOnclick(xid) + '\', \'' + Utils.encodeOnclick(id) + '\', \'' + Utils.encodeOnclick(type) + '\');">' +
'x' +
'</div>';
}
// Close the HTML
html += '</div>';
// Append the HTML code
$(chat_switch + 'chans, ' + chat_switch + 'more-content').append(html);
} catch(e) {
@ -295,10 +519,10 @@ var Chat = (function () {
try {
// Remove the messages
$('#page-engine #' + chat + ' .content .one-group').remove();
// Clear the history database
Message.removeLocalArchive(chat);
// Focus again
$(document).oneTime(10, function() {
$('#page-engine #' + chat + ' .text .message-area').focus();
@ -346,14 +570,14 @@ var Chat = (function () {
try {
Console.info('New chat: ' + xid);
// Create the chat content
self.generate(type, hash, xid, nick);
// Create the chat switcher
self.generateSwitch(type, hash, xid, nick);
// If the user is not in our roster
// Is this a chat?
if(type == 'chat') {
// MAM? Get archives from there!
if(Features.enabledMAM()) {
@ -366,130 +590,73 @@ var Chat = (function () {
} else {
// Restore the chat history
var chat_history = Message.readLocalArchive(hash);
if(chat_history) {
// Generate hashs
var my_hash = hex_md5(Common.getXID());
var friend_hash = hex_md5(xid);
// Add chat history HTML
$('#' + hash + ' .content').append(chat_history);
var path_sel = $('#' + hash);
path_sel.find('.content').append(chat_history);
// Filter old groups & messages
$('#' + hash + ' .one-group[data-type="user-message"]').addClass('from-history').attr('data-type', 'old-message');
$('#' + hash + ' .user-message').removeClass('user-message').addClass('old-message');
var one_group_sel = path_sel.find('.one-group');
one_group_sel.filter('[data-type="user-message"]').addClass('from-history').attr('data-type', 'old-message');
path_sel.find('.user-message').removeClass('user-message').addClass('old-message');
// Regenerate user names
$('#' + hash + ' .one-group.' + my_hash + ' b.name').text(Name.getBuddy(Common.getXID()));
$('#' + hash + ' .one-group.' + friend_hash + ' b.name').text(Name.getBuddy(xid));
one_group_sel.filter('.' + my_hash + ' b.name').text(
Name.getBuddy(Common.getXID())
);
one_group_sel.filter('.' + friend_hash + ' b.name').text(
Name.getBuddy(xid)
);
// Regenerate group dates
$('#' + hash + ' .one-group').each(function() {
var current_stamp = parseInt($(this).attr('data-stamp'));
one_group_sel.each(function() {
var current_stamp = parseInt($(this).attr('data-stamp'), 10);
$(this).find('span.date').text(DateUtils.relative(current_stamp));
});
// Regenerate avatars
if(Common.exists('#' + hash + ' .one-group.' + my_hash + ' .avatar-container'))
if(Common.exists('#' + hash + ' .one-group.' + my_hash + ' .avatar-container')) {
Avatar.get(Common.getXID(), 'cache', 'true', 'forget');
if(Common.exists('#' + hash + ' .one-group.' + friend_hash + ' .avatar-container'))
}
if(Common.exists('#' + hash + ' .one-group.' + friend_hash + ' .avatar-container')) {
Avatar.get(xid, 'cache', 'true', 'forget');
}
}
}
// Add button
if(!Roster.isFriend(xid))
if(!Roster.isFriend(xid)) {
$('#' + hash + ' .tools-add').click(function() {
// Hide the icon (to tell the user all is okay)
$(this).hide();
// Send the subscribe request
Roster.addThisContact(xid, nick);
}).show();
}
}
// We catch the user's informations (like this avatar, vcard, and so on...)
UserInfos.get(hash, xid, nick, type);
// The icons-hover functions
Tooltip.icons(xid, hash);
// The event handlers
var inputDetect = $('#page-engine #' + hash + ' .message-area');
inputDetect.focus(function() {
// Clean notifications for this chat
Interface.chanCleanNotify(hash);
// Store focus on this chat!
Interface.chat_focus_hash = hash;
});
inputDetect.blur(function() {
// Reset storage about focus on this chat!
if(Interface.chat_focus_hash == hash)
Interface.chat_focus_hash = null;
});
inputDetect.keypress(function(e) {
// Enter key
if(e.keyCode == 13) {
// Add a new line
if(e.shiftKey || e.ctrlKey) {
inputDetect.val(inputDetect.val() + '\n');
} else {
// Send the message
Message.send(hash, 'chat');
// Reset the composing database entry
DataStore.setDB(Connection.desktop_hash, 'chatstate', xid, 'off');
}
return false;
}
});
var input_sel = $('#page-engine #' + hash + ' .message-area');
self._createEvents(input_sel, xid, hash);
// Scroll in chat content
$('#page-engine #' + hash + ' .content').scroll(function() {
var self = this;
if(Features.enabledMAM() && !(xid in MAM.map_pending)) {
var has_state = xid in MAM.map_states;
var rsm_count = has_state ? MAM.map_states[xid].rsm.count : 1;
var rsm_before = has_state ? MAM.map_states[xid].rsm.first : '';
// Request more archives?
if(rsm_count > 0 && $(this).scrollTop() < MAM.SCROLL_THRESHOLD) {
var was_scroll_top = $(self).scrollTop() <= 32;
var wait_mam = $('#' + hash).find('.wait-mam');
wait_mam.show();
MAM.getArchives({
'with': xid
}, {
'max': MAM.REQ_MAX,
'before': rsm_before
}, function() {
var wait_mam_height = was_scroll_top ? 0 : wait_mam.height();
wait_mam.hide();
// Restore scroll?
if($(self).scrollTop() < MAM.SCROLL_THRESHOLD) {
var sel_mam_chunk = $(self).find('.mam-chunk:first');
var cont_padding_top = parseInt($(self).css('padding-top').replace(/[^-\d\.]/g, ''));
var cont_one_group_margin_bottom = parseInt(sel_mam_chunk.find('.one-group:last').css('margin-bottom').replace(/[^-\d\.]/g, ''));
var cont_mam_chunk_height = sel_mam_chunk.height();
$(self).scrollTop(wait_mam_height + cont_padding_top + cont_one_group_margin_bottom + cont_mam_chunk_height);
}
});
}
}
});
// Chatstate events
ChatState.events(inputDetect, xid, hash, 'chat');
// Input events
ChatState.events(input_sel, xid, hash, 'chat');
Markers.events(input_sel, xid, hash, 'chat');
} catch(e) {
Console.error('Chat.create', e);
}
@ -502,4 +669,4 @@ var Chat = (function () {
*/
return self;
})();
})();

View file

@ -32,24 +32,27 @@ var ChatState = (function () {
try {
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') && !Common.exists('#page-switch .' + hash + ' .unavailable'))) {
// Already sent?
if(DataStore.getDB(Connection.desktop_hash, 'currentchatstate', xid) == state)
if(DataStore.getDB(Connection.desktop_hash, 'currentchatstate', xid) == state) {
return;
}
// Write the state
DataStore.setDB(Connection.desktop_hash, '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});
aMsg.appendNode(state, {
'xmlns': NS_CHATSTATES
});
// Send this!
con.send(aMsg);
}
@ -74,58 +77,61 @@ var ChatState = (function () {
// Groupchat?
if(type == 'groupchat') {
self.reset(hash, type);
// "gone" state not allowed
if(state != 'gone')
if(state != 'gone') {
$('#page-engine .page-engine-chan .user.' + hash).addClass(state);
}
}
// Chat
else {
// We change the buddy name color in the page-switch
self.reset(hash, type);
$('#page-switch .' + hash + ' .name').addClass(state);
// We generate the chatstate text
var text = '';
switch(state) {
// Active
case 'active':
text = Common._e("Your friend is paying attention to the conversation.");
break;
// Composing
case 'composing':
text = Common._e("Your friend is writing a message...");
break;
// Paused
case 'paused':
text = Common._e("Your friend stopped writing a message.");
break;
// Inactive
case 'inactive':
text = Common._e("Your friend is doing something else.");
break;
// Gone
case 'gone':
text = Common._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>');
$('#' + hash + ' .content').after(
'<div class="' + state + ' chatstate">' + text + '</div>'
);
}
} catch(e) {
Console.error('ChatState.display', e);
@ -146,12 +152,13 @@ var ChatState = (function () {
try {
// Define the selector
var selector;
if(type == 'groupchat')
if(type == 'groupchat') {
selector = $('#page-engine .page-engine-chan .user.' + hash);
else
} else {
selector = $('#page-switch .' + hash + ' .name');
}
// Reset!
selector.removeClass('active composing paused inactive gone');
} catch(e) {
@ -179,53 +186,56 @@ var ChatState = (function () {
if($(this).val() && (DataStore.getDB(Connection.desktop_hash, 'chatstate', xid) != 'on')) {
// We change the state detect input
DataStore.setDB(Connection.desktop_hash, 'chatstate', xid, 'on');
// We send the friend a "composing" chatstate
self.send('composing', xid, hash);
}
// Flushed the message which was being composed
else if(!$(this).val() && (DataStore.getDB(Connection.desktop_hash, 'chatstate', xid) == 'on')) {
// We change the state detect input
DataStore.setDB(Connection.desktop_hash, 'chatstate', xid, 'off');
// We send the friend an "active" chatstate
self.send('active', xid, hash);
}
}
});
target.change(function() {
// Reset the composing database entry
DataStore.setDB(Connection.desktop_hash, 'chatstate', xid, 'off');
});
target.focus(function() {
// Not needed
if(target.is(':disabled'))
if(target.is(':disabled')) {
return;
}
// Something was written, user started writing again
if($(this).val())
if($(this).val()) {
self.send('composing', xid, hash);
}
// Chat only: Nothing in the input, user is active
else if(type == 'chat')
else if(type == 'chat') {
self.send('active', xid, hash);
}
});
target.blur(function() {
// Not needed
if(target.is(':disabled'))
if(target.is(':disabled')) {
return;
// Something was written, user paused
if($(this).val())
self.send('paused', xid, hash);
}
// Chat only: Nothing in the input, user is inactive
else if(type == 'chat')
// Something was written, user paused
if($(this).val()) {
self.send('paused', xid, hash);
} else if(type == 'chat') {
self.send('inactive', xid, hash);
}
});
} catch(e) {
Console.error('ChatState.events', e);

View file

@ -20,6 +20,10 @@ var Common = (function () {
var self = {};
/* Constants */
self.R_DOMAIN_NAME = /^(([a-zA-Z0-9-\.]+)\.)?[a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9]\.[a-zA-Z]{2,}$/i;
/**
* Checks if an element exists in the DOM
* @public
@ -109,6 +113,29 @@ var Common = (function () {
};
/**
* Matches a domain name
* @public
* @param {string} xid
* @return {boolean}
*/
self.isDomain = function(xid) {
is_domain = false;
try {
if(xid.match(self.R_DOMAIN_NAME)) {
is_domain = true;
}
} catch(e) {
Console.error('Common.isDomain', e);
} finally {
return is_domain;
}
};
/**
* Generates the good XID
* @public
@ -120,22 +147,23 @@ var Common = (function () {
try {
// XID needs to be transformed
// .. and made lowercase (uncertain though this is the right place...)
xid = xid.toLowerCase();
if(xid && (xid.indexOf('@') == -1)) {
// Groupchat
if(type == 'groupchat')
if(xid && (xid.indexOf('@') === -1)) {
// Groupchat XID
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;
}
// Gateway XID
if(self.isDomain(xid) === true) {
return xid;
}
// User XID
return xid + '@' + HOST_MAIN;
}
// Nothing special (yet bare XID)
return xid;
} catch(e) {
@ -190,15 +218,17 @@ var Common = (function () {
self.strAfterLast = function(given_char, str) {
try {
if(!given_char || !str)
if(!given_char || !str) {
return '';
}
var char_index = str.lastIndexOf(given_char);
var str_return = str;
if(char_index >= 0)
if(char_index >= 0) {
str_return = str.substr(char_index + 1);
}
return str_return;
} catch(e) {
Console.error('Common.strAfterLast', e);
@ -220,15 +250,16 @@ var Common = (function () {
try {
// 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)
if(i === 0) {
toStr = toStr.substr(0, index);
else
} else {
toStr = toStr.substr(index + 1);
}
}
// We return the value
return toStr;
} catch(e) {
@ -309,8 +340,9 @@ var Common = (function () {
// Spec: http://tools.ietf.org/html/rfc6122#appendix-A
try {
if(!node)
if(!node) {
return node;
}
// Remove prohibited chars
var prohibited_chars = ['"', '&', '\'', '/', ':', '<', '>', '@'];
@ -347,6 +379,40 @@ var Common = (function () {
};
/**
* Escapes quotes in a string
* @public
* @param {string} str
* @return {string}
*/
self.escapeQuotes = function(str) {
try {
return escape(self.encodeQuotes(str));
} catch(e) {
Console.error('Common.escapeQuotes', e);
}
};
/**
* Unescapes quotes in a string
* @public
* @param {string} str
* @return {string}
*/
self.unescapeQuotes = function(str) {
try {
return unescape(str);
} catch(e) {
Console.error('Common.unescapeQuotes', e);
}
};
/**
* Gets the bare XID from a XID
* @public
@ -358,12 +424,12 @@ var Common = (function () {
try {
// Cut the resource
xid = self.cutResource(xid);
// Launch nodeprep
if(xid.indexOf('@') != -1) {
xid = self.nodeprep(self.getXIDNick(xid)) + '@' + self.getXIDHost(xid);
if(xid.indexOf('@') !== -1) {
xid = self.nodeprep(self.getXIDNick(xid, true)) + '@' + self.getXIDHost(xid);
}
return xid;
} catch(e) {
Console.error('Common.bareXID', e);
@ -384,11 +450,12 @@ var Common = (function () {
// Normalizes the XID
var full = self.bareXID(xid);
var resource = self.thisResource(xid);
// Any resource?
if(resource)
if(resource) {
full += '/' + resource;
}
return full;
} catch(e) {
Console.error('Common.fullXID', e);
@ -401,15 +468,19 @@ var Common = (function () {
* Gets the nick from a XID
* @public
* @param {string} aXID
* @param {boolean} raw_explode
* @return {string}
*/
self.getXIDNick = function(aXID) {
self.getXIDNick = function(aXID, raw_explode) {
try {
// Gateway nick?
if(aXID.match(/\\40/))
return self.explodeThis('\\40', aXID, 0);
if(raw_explode !== true) {
// Gateway nick?
if(aXID.match(/\\40/)) {
return self.explodeThis('\\40', aXID, 0);
}
}
return self.explodeThis('@', aXID, 0);
} catch(e) {
Console.error('Common.getXIDNick', e);
@ -484,7 +555,7 @@ var Common = (function () {
/**
* Gets the full XID of the user
* Gets the bare XID of the user
* @public
* @return {string}
*/
@ -495,7 +566,7 @@ var Common = (function () {
if(con.username && con.domain) {
return con.username + '@' + con.domain;
}
return '';
} catch(e) {
Console.error('Common.getXID', e);
@ -504,6 +575,29 @@ var Common = (function () {
};
/**
* Gets the full XID of the user
* @public
* @return {string}
*/
self.getFullXID = function() {
try {
var xid = self.getXID();
// Return the full XID of the user
if(xid) {
return xid + '/' + con.resource;
}
return '';
} catch(e) {
Console.error('Common.getFullXID', e);
}
};
/**
* Generates the colors for a given user XID
* @public
@ -521,15 +615,15 @@ var Common = (function () {
'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;
} catch(e) {
Console.error('Common.generateColor', e);
@ -549,7 +643,7 @@ var Common = (function () {
is_gateway = true;
try {
if(xid.indexOf('@') != -1) {
if(xid.indexOf('@') !== -1) {
is_gateway = false;
}
} catch(e) {
@ -571,12 +665,12 @@ var Common = (function () {
try {
var from = stanza.getFrom();
// No from, we assume this is our XID
if(!from) {
from = self.getXID();
}
return from;
} catch(e) {
Console.error('Common.getStanzaFrom', e);
@ -618,13 +712,15 @@ var Common = (function () {
try {
// Negative number (without first 0)
if(i > -10 && i < 0)
if(i > -10 && i < 0) {
return '-0' + (i * -1);
}
// Positive number (without first 0)
if(i < 10 && i >= 0)
if(i < 10 && i >= 0) {
return '0' + i;
}
// All is okay
return i;
} catch(e) {
@ -643,23 +739,31 @@ var Common = (function () {
*/
self.escapeRegex = function(query) {
if (query instanceof Array) {
var result = new Array(query.length);
for(i=0; i<query.length; i++) {
var result = [];
try {
if(query instanceof Array) {
result = [query.length];
for(i = 0; i < query.length; i++) {
try {
result[i] = Common.escapeRegex(query[i]);
} catch(e) {
Console.error('Common.escapeRegex', e);
result[i] = null;
}
}
} else {
try {
result[i] = Common.escapeRegex(query[i]);
result = query.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
} catch(e) {
Console.error('Common.escapeRegex', e);
result[i] = null;
Console.error('Common.escapeRegex[inner]', e);
}
}
} catch(e) {
Console.error('Common.escapeRegex', e);
} finally {
return result;
} else {
try {
return query.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
} catch(e) {
Console.error('Common.escapeRegex', e);
}
}
};
@ -717,7 +821,7 @@ var Common = (function () {
if(window.XMLSerializer) {
xml_str = (new XMLSerializer()).serializeToString(xmlData);
}
// For Internet Explorer
if(window.ActiveXObject) {
xml_str = xmlData.xml;
@ -744,21 +848,21 @@ var Common = (function () {
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) {
@ -780,7 +884,7 @@ var Common = (function () {
try {
var timer = 0;
return function(callback, ms) {
clearTimeout(timer);
timer = setTimeout(callback, ms);
@ -799,4 +903,4 @@ var Common = (function () {
})();
var JappixCommon = Common;
var JappixCommon = Common;

View file

@ -29,6 +29,205 @@ var Connection = (function () {
self.resume = false;
/**
* Do registration on Register API
* @private
* @param {string} username
* @param {string} domain
* @param {string} pass
* @param {string} captcha
* @return {boolean}
*/
self._doRegisterAPI = function(username, domain, pass, captcha) {
var is_success = false;
try {
// Show the waiting image
Interface.showGeneralWait();
// Change the page title
Interface.title('wait');
// Send request
$.post('./server/register.php', {username: username, domain: domain, password: pass, captcha: captcha}, function(data) {
// Error registering
Interface.removeGeneralWait();
Interface.title('home');
// In all case, update CAPTCHA
$('#home img.captcha_img').attr('src', './server/captcha.php?id=' + genID());
$('#home input.captcha').val('');
// Registration okay
if($(data).find('query status').text() == '1') {
is_success = true;
self.handleRegistered();
} else {
// Show error message
var error_message = '';
switch($(data).find('query message').text()) {
case 'CAPTCHA Not Matching':
error_message = Common._e("The security code you entered is invalid. Please retry with another one.");
$('#home input.captcha').focus();
break;
case 'Username Unavailable':
error_message = Common._e("The username you picked is not available. Please try another one.");
$('#home input.nick').focus();
break;
default:
error_message = Common._e("There was an error registering your account. Please retry.");
break;
}
if(error_message) {
Errors.show('', error_message, '');
}
}
});
} catch(e) {
Console.error('Connection._doRegisterAPI', e);
} finally {
return is_success;
}
};
/**
* Do registration throug in-band stream
* @private
* @param {string} username
* @param {string} domain
* @param {string} pass
* @return {boolean}
*/
self._doRegisterInBand = function(username, domain, pass) {
var is_success = true;
try {
if(Common.hasWebSocket()) {
// WebSocket supported & configured
con = new JSJaCWebSocketConnection({
httpbase: HOST_WEBSOCKET
});
} else {
var httpbase = (HOST_BOSH_MAIN || HOST_BOSH);
// Check BOSH origin
BOSH_SAME_ORIGIN = Origin.isSame(httpbase);
// We create the new http-binding connection
con = new JSJaCHttpBindingConnection({
httpbase: httpbase
});
}
// We setup the connection !
con.registerHandler('onconnect', self.handleRegistered);
con.registerHandler('onerror', Errors.handle);
con.connect({
'domain': $.trim(domain),
'username': $.trim(username),
'resource': JAPPIX_RESOURCE + ' Register (' + (new Date()).getTime() + ')',
'pass': pass,
'register': true,
'secure': true,
'xmllang': XML_LANG
});
// Show the waiting image
Interface.showGeneralWait();
// Change the page title
Interface.title('wait');
} catch(e) {
Console.error('Connection._doRegisterInBand', e);
is_success = false;
} finally {
return is_success;
}
};
/**
* Attaches reconnect events
* @private
* @param {string} mode
* @return {undefined}
*/
self._eventsReconnect = function(mode) {
try {
// Click events
if(mode == 'normal') {
$('#reconnect a.finish.cancel').click(function() {
return self.cancelReconnect();
});
}
$('#reconnect a.finish.reconnect').click(function() {
return self.acceptReconnect(mode);
});
} catch(e) {
Console.error('Connection._eventsReconnect', e);
}
};
/**
* Schedules the next auto reconnect
* @private
* @param {string} mode
* @return {undefined}
*/
self._scheduleReconnect = function(mode) {
try {
// Try to reconnect automatically after a while
if(self.reconnect_try < 5) {
self.reconnect_timer = 5 + (5 * self.reconnect_try);
} else {
self.reconnect_timer = 120;
}
// Change the try number
self.reconnect_try++;
// Fire the event!
$('#reconnect a.finish.reconnect').everyTime('1s', function() {
// We can reconnect!
if(self.reconnect_timer === 0) {
return self.acceptReconnect(mode);
}
// Button text
if(self.reconnect_timer <= 10) {
$(this).text(Common._e("Reconnect") + ' (' + self.reconnect_timer + ')');
}
// Remove 1 second
self.reconnect_timer--;
});
} catch(e) {
Console.error('Connection._scheduleReconnect', e);
}
};
/**
* Does the user login
* @public
@ -45,14 +244,14 @@ var Connection = (function () {
try {
// get optionnal conn handlers
oExtend = loginOpts || {};
extend_obj = loginOpts || {};
// We remove the not completed class to avoid problems
$('#home .loginer input').removeClass('please-complete');
// We add the login wait div
Interface.showGeneralWait();
if(Common.hasWebSocket()) {
// WebSocket supported & configured
con = new JSJaCWebSocketConnection({
@ -63,56 +262,56 @@ var Connection = (function () {
// Check BOSH origin
BOSH_SAME_ORIGIN = Origin.isSame(httpbase);
// We create the new http-binding connection
con = new JSJaCHttpBindingConnection({
httpbase: httpbase
});
}
// And we handle everything that happen
self.setupCon(con, oExtend);
self.setupCon(con, extend_obj);
// Generate a resource
var random_resource = DataStore.getDB(self.desktop_hash, 'session', 'resource');
if(!random_resource) {
random_resource = lResource + ' (' + (new Date()).getTime() + ')';
}
// We retrieve what the user typed in the login inputs
oArgs = {};
oArgs.domain = $.trim(lServer);
oArgs.username = $.trim(lNick);
oArgs.resource = random_resource;
oArgs.pass = lPass;
oArgs.secure = true;
oArgs.xmllang = XML_LANG;
self.desktop_hash = 'jd.' + hex_md5(oArgs.username + '@' + oArgs.domain);
var con_args = {
'domain': lServer.trim(),
'username': lNick.trim(),
'resource': random_resource,
'pass': lPass,
'secure': true,
'xmllang': XML_LANG
};
self.desktop_hash = 'jd.' + hex_md5(con_args.username + '@' + con_args.domain);
// Store the resource (for reconnection)
DataStore.setDB(self.desktop_hash, 'session', 'resource', random_resource);
// Store session XML in temporary database
self.storeSession(lNick, lServer, lPass, lResource, lPriority, lRemember);
// We store the infos of the user into the data-base
DataStore.setDB(self.desktop_hash, 'priority', 1, lPriority);
// We connect !
con.connect(oArgs);
con.connect(con_args);
// Change the page title
Interface.title('wait');
Console.info('Jappix is connecting...');
} catch(e) {
Console.error('Connection.doLogin', e);
// Reset Jappix
Talk.destroy();
// Open an unknown error
Board.openThisError(2);
} finally {
@ -131,16 +330,16 @@ var Connection = (function () {
try {
Console.info('A new account has been registered.');
// We remove the waiting image
Interface.removeGeneralWait();
// Reset the title
Interface.title('home');
// We show the success information
$('#home .registerer .success').fadeIn('fast');
// We quit the session
if(Common.isConnected()) {
self.logout();
@ -165,116 +364,25 @@ var Connection = (function () {
try {
Console.info('Trying to register an account...');
// We change the registered information text
$('#home .homediv.registerer').append(
'<div class="info success">' +
Common._e("You have been registered, here is your XMPP address:") + ' <b>' + username.htmlEnc() + '@' + domain.htmlEnc() + '</b> - <a href="#">' + Common._e("Login") + '</a>' +
'<div class="info success">' +
Common._e("You have been registered, here is your XMPP address:") +
' <b>' + username.htmlEnc() + '@' + domain.htmlEnc() + '</b> - ' +
'<a href="#">' + Common._e("Login") + '</a>' +
'</div>'
);
// Login link
$('#home .homediv.registerer .success a').click(function() {
return self.doLogin(username, domain, pass, '', '10', false);
});
if((REGISTER_API == 'on') && (domain == HOST_MAIN) && captcha) {
// Show the waiting image
Interface.showGeneralWait();
// Change the page title
Interface.title('wait');
// Send request
$.post('./server/register.php', {username: username, domain: domain, password: pass, captcha: captcha}, function(data) {
// Error registering
Interface.removeGeneralWait();
Interface.title('home');
// In all case, update CAPTCHA
$('#home img.captcha_img').attr('src', './server/captcha.php?id=' + genID());
$('#home input.captcha').val('');
// Registration okay
if($(data).find('query status').text() == '1') {
self.handleRegistered();
} else {
// Show error message
var error_message = '';
switch($(data).find('query message').text()) {
case 'CAPTCHA Not Matching':
error_message = Common._e("The security code you entered is invalid. Please retry with another one.");
$('#home input.captcha').focus();
break;
case 'Username Unavailable':
error_message = Common._e("The username you picked is not available. Please try another one.");
$('#home input.nick').focus();
break;
default:
error_message = Common._e("There was an error registering your account. Please retry.");
break;
}
if(error_message)
Errors.show('', error_message, '');
}
});
self._doRegisterAPI(username, domain, pass, captcha);
} else {
try {
oArgs = {};
if(Common.hasWebSocket()) {
// WebSocket supported & configured
con = new JSJaCWebSocketConnection({
httpbase: HOST_WEBSOCKET
});
} else {
var httpbase = (HOST_BOSH_MAIN || HOST_BOSH);
// Check BOSH origin
BOSH_SAME_ORIGIN = Origin.isSame(httpbase);
// We create the new http-binding connection
con = new JSJaCHttpBindingConnection({
httpbase: httpbase
});
}
// We setup the connection !
con.registerHandler('onconnect', self.handleRegistered);
con.registerHandler('onerror', Errors.handle);
// We retrieve what the user typed in the register inputs
oArgs = {};
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);
// Show the waiting image
Interface.showGeneralWait();
// Change the page title
Interface.title('wait');
}
catch(e) {
// Logs errors
Console.error('doRegister', e);
}
self._doRegisterInBand(username, domain, pass);
}
} catch(e) {
Console.error('Connection.doRegister', e);
@ -294,31 +402,29 @@ var Connection = (function () {
try {
Console.info('Trying to login anonymously...');
var aPath = '#home .anonymouser ';
var room = $(aPath + '.room').val();
var nick = $(aPath + '.nick').val();
// If the form is correctly completed
var path_sel = $('#home .anonymouser');
var room = path_sel.find('.room').val();
var nick = path_sel.find('.nick').val();
// Form 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())
} else {
path_sel.find('input[type="text"]').each(function() {
var this_sel = $(this);
if(!this_sel.val()) {
$(document).oneTime(10, function() {
select.addClass('please-complete').focus();
this_sel.addClass('please-complete').focus();
});
else
select.removeClass('please-complete');
} else {
this_sel.removeClass('please-complete');
}
});
}
} catch(e) {
@ -339,23 +445,23 @@ var Connection = (function () {
try {
Console.info('Jappix is now connected.');
// Connection markers
self.connected = true;
self.reconnect_try = 0;
self.reconnect_timer = 0;
// We hide the home page
$('#home').hide();
// Any suggest to do before triggering connected event?
Groupchat.suggestCheck();
// Remove the waiting item
Interface.removeGeneralWait();
// Init Jingle
Jingle.init();
// Init call
Call.init();
} catch(e) {
Console.error('Connection.handleConnected', e);
}
@ -374,27 +480,28 @@ var Connection = (function () {
// Not resumed?
if(!self.resume) {
// Remember the session?
if(DataStore.getDB(self.desktop_hash, 'remember', 'session'))
if(DataStore.getDB(self.desktop_hash, 'remember', 'session')) {
DataStore.setPersistent('global', 'session', 1, self.current_session);
}
// We show the chatting app.
Talk.create();
// We reset the homepage
Home.change('default');
// We get all the other things
self.getEverything();
// Set last activity stamp
DateUtils.last_activity = DateUtils.getTimeStamp();
}
// Resumed
else {
// Send our presence
Presence.sendActions();
// Change the title
Interface.updateTitle();
}
@ -414,7 +521,10 @@ var Connection = (function () {
try {
Console.info('Jappix is now disconnected.');
// Abort ongoing call (if any)
Call.stop(true);
// Normal disconnection
if(!self.current_session && !self.connected) {
Talk.destroy();
@ -431,24 +541,32 @@ var Connection = (function () {
* Setups the normal connection
* @public
* @param {object} con
* @param {object} oExtend
* @param {object} extend_obj
* @return {undefined}
*/
self.setupCon = function(con, oExtend) {
self.setupCon = function(con, extend_obj) {
try {
// Setup connection handlers
con.registerHandler('message', Message.handle);
con.registerHandler('presence', Presence.handle);
con.registerHandler('iq', IQ.handle);
con.registerHandler('onconnect', self.handleConnected);
con.registerHandler('onerror', Errors.handle);
con.registerHandler('ondisconnect', self.handleDisconnected);
var connection_handlers = {
'message': Message.handle,
'presence': Presence.handle,
'iq': IQ.handle,
'onconnect': self.handleConnected,
'onerror': Errors.handle,
'ondisconnect': self.handleDisconnected
};
for(var cur_handler in connection_handlers) {
con.registerHandler(
cur_handler,
connection_handlers[cur_handler]
);
}
// Extended handlers
oExtend = oExtend || {};
jQuery.each(oExtend, function(keywd,funct) {
extend_obj = extend_obj || {};
jQuery.each(extend_obj, function(keywd,funct) {
con.registerHandler(keywd, funct);
});
} catch(e) {
@ -496,13 +614,13 @@ var Connection = (function () {
if(Common.isConnected()) {
// Clear temporary session storage
self.resetConMarkers();
// Show the waiting item (useful if BOSH is sloooow)
Interface.showGeneralWait();
// Change the page title
Interface.title('wait');
// Disconnect from the XMPP server
self.logout();
}
@ -525,13 +643,13 @@ var Connection = (function () {
if(!Common.isConnected()) {
return;
}
// We show the waiting image
Interface.showGeneralWait();
// Change the page title
Interface.title('wait');
// We disconnect from the XMPP server
self.logout();
} catch(e) {
@ -551,60 +669,34 @@ var Connection = (function () {
try {
Console.error('This is not a normal disconnection, show the reconnect pane...');
// Reconnect pane not yet displayed?
if(!Common.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">' +
Common._e("Due to a network issue, you were disconnected. What do you want to do now?");
var html = '<div id="reconnect" class="lock">' +
'<div class="pane">' +
Common._e("Due to a network issue, you were disconnected. What do you want to do now?");
// Can we cancel reconnection?
if(mode == 'normal')
if(mode == 'normal') {
html += '<a href="#" class="finish cancel">' + Common._e("Cancel") + '</a>';
html += '<a href="#" class="finish reconnect">' + Common._e("Reconnect") + '</a>' +
'</div></div>';
}
html += '<a href="#" class="finish reconnect">' + Common._e("Reconnect") + '</a>' +
'</div></div>';
// Append the code
$('body').append(html);
// Click events
if(mode == 'normal')
$('#reconnect a.finish.cancel').click(function() {
return self.cancelReconnect();
});
$('#reconnect a.finish.reconnect').click(function() {
return self.acceptReconnect(mode);
});
// Try to reconnect automatically after a while
if(self.reconnect_try < 5)
self.reconnect_timer = 5 + (5 * self.reconnect_try);
else
self.reconnect_timer = 120;
// Change the try number
self.reconnect_try++;
// Fire the event!
$('#reconnect a.finish.reconnect').everyTime('1s', function() {
// We can reconnect!
if(self.reconnect_timer === 0)
return self.acceptReconnect(mode);
// Button text
if(self.reconnect_timer <= 10)
$(this).text(Common._e("Reconnect") + ' (' + self.reconnect_timer + ')');
// Remove 1 second
self.reconnect_timer--;
});
// Attach events
self._eventsReconnect(mode);
// Schedule next reconnect
self._scheduleReconnect(mode);
// Page title
Interface.updateTitle();
}
@ -625,30 +717,33 @@ var Connection = (function () {
try {
Console.info('Trying to reconnect the user...');
// Resume marker
self.resume = true;
// Show waiting item
Interface.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');
var groupchats_sel = $(groupchats);
groupchats_sel.find('.list .role').hide();
groupchats_sel.find('.one-group, ' + groupchats + ' .list .user').remove();
groupchats_sel.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')
if(mode == 'normal') {
self.loginFromSession(Common.XMLFromString(self.current_session));
else if(mode == 'anonymous')
} else if(mode == 'anonymous') {
Anonymous.login(HOST_ANONYMOUS);
}
} catch(e) {
Console.error('Connection.acceptReconnect', e);
} finally {
@ -667,16 +762,16 @@ var Connection = (function () {
try {
Console.info('User has canceled automatic reconnection...');
// Stop the timer
$('#reconnect a.finish.reconnect').stopTime();
// Remove the reconnect pane
$('#reconnect').remove();
// Destroy the talk page
Talk.destroy();
// Renitialize the previous session parameters
self.resetConMarkers();
} catch(e) {
@ -698,7 +793,7 @@ var Connection = (function () {
try {
// Clear temporary storage
self.resetConMarkers();
// Clear persistent storage
if($(Common.XMLFromString(DataStore.getPersistent('global', 'session', 1))).find('stored').text() == 'true') {
DataStore.removePersistent('global', 'session', 1);
@ -741,7 +836,7 @@ var Connection = (function () {
try {
// Select the data
var session = $(data);
// Fire the login event
self.doLogin(
session.find('username').text(),
@ -768,10 +863,10 @@ var Connection = (function () {
try {
// Reset our database
self.clearLastSession();
// We quit the current session
self.quit();
// We show an info
Board.openThisInfo(3);
} catch(e) {
@ -817,16 +912,23 @@ var Connection = (function () {
try {
// 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>';
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)
self.current_session = session_xml;
// Remember me?
if(lRemember) {
DataStore.setDB(self.desktop_hash, 'remember', 'session', 1);
}
return session_xml;
} catch(e) {
Console.error('Connection.storeSession', e);
@ -846,11 +948,12 @@ var Connection = (function () {
$(document).ready(function() {
// Logouts when Jappix is closed
$(window).bind('beforeunload', Connection.terminate);
// Nothing to do when anonymous!
if(Utils.isAnonymous())
if(Utils.isAnonymous()) {
return;
}
// Connection params submitted in URL?
if(XMPPLinks.links_var.u && XMPPLinks.links_var.q) {
// Generate login data
@ -861,51 +964,56 @@ var Connection = (function () {
var login_resource = JAPPIX_RESOURCE + ' (' + (new Date()).getTime() + ')';
var login_priority = '10';
var login_remember = 1;
// Must store session?
if(XMPPLinks.links_var.h && (XMPPLinks.links_var.h === '1')) {
// Store session
var session_xml = self.storeSession(login_nick, login_server, login_pwd, login_resource, login_priority, true);
var session_xml = self.storeSession(
login_nick,
login_server,
login_pwd,
login_resource,
login_priority,
true
);
DataStore.setPersistent('global', 'session', 1, session_xml);
// Redirect to a clean URL
document.location.href = './';
} else {
// Hide the homepage
$('#home').hide();
// Show the waiting icon
Interface.showGeneralWait();
// Proceed login
self.doLogin(login_nick, login_server, login_pwd, login_resource, login_priority, login_remember);
}
return;
}
// Try to resume a stored session, if not anonymous
var session = Common.XMLFromString(
DataStore.getPersistent('global', 'session', 1)
);
if($(session).find('stored').text() == 'true') {
// Hide the homepage
$('#home').hide();
// Show the waiting icon
Interface.showGeneralWait();
// Login!
self.loginFromSession(session);
Console.info('Saved session found, resuming it...');
}
// Not connected, maybe a XMPP link is submitted?
else if((parent.location.hash != '#OK') && XMPPLinks.links_var.x) {
} else if((parent.location.hash != '#OK') && XMPPLinks.links_var.x) {
Home.change('loginer');
Console.info('A XMPP link is set, switch to login page.');
}
});

View file

@ -11,103 +11,109 @@ Authors: Stefan Strigler, Valérian Saliou, Kloadut, Maranda
*/
// 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:';
var NS_IETF_XMPP = NS_IETF + 'xmpp-';
var NS_XMPP = 'urn:xmpp:';
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:';
var NS_IETF_XMPP = NS_IETF + 'xmpp-';
var NS_XMPP = 'urn:xmpp:';
var NS_STORAGE = 'storage:';
var NS_BOOKMARKS = NS_STORAGE + 'bookmarks';
var NS_ROSTERNOTES = NS_STORAGE + 'rosternotes';
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_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_IETF_VCARD4 = NS_IETF + 'vcard-4.0';
var NS_XMPP_VCARD4 = NS_XMPP + 'vcard4';
var NS_URN_ADATA = NS_XMPP + 'avatar:data';
var NS_URN_AMETA = NS_XMPP + 'avatar:metadata';
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_CN = NS_PUBSUB + '#config-node';
var NS_PUBSUB_RI = NS_PUBSUB + '#retrieve-items';
var NS_COMMANDS = NS_PROTOCOL + 'commands';
var NS_BOSH = NS_PROTOCOL + 'httpbind';
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_IETF_VCARD4 = NS_IETF + 'vcard-4.0';
var NS_XMPP_VCARD4 = NS_XMPP + 'vcard4';
var NS_URN_ADATA = NS_XMPP + 'avatar:data';
var NS_URN_AMETA = NS_XMPP + 'avatar:metadata';
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_CN = NS_PUBSUB + '#config-node';
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_MBLOG = NS_XMPP + 'microblog:0';
var NS_URN_INBOX = NS_XMPP + 'inbox';
var NS_URN_FORWARD = NS_XMPP + 'forward:0';
var NS_URN_MAM = NS_XMPP + 'mam:tmp';
var NS_URN_DELAY = NS_XMPP + 'delay';
var NS_URN_RECEIPTS = NS_XMPP + 'receipts';
var NS_URN_CARBONS = NS_XMPP + 'carbons:2';
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_URN_TIME = NS_XMPP + 'time';
var NS_URN_PING = NS_XMPP + 'ping';
var NS_URN_MBLOG = NS_XMPP + 'microblog:0';
var NS_URN_INBOX = NS_XMPP + 'inbox';
var NS_URN_FORWARD = NS_XMPP + 'forward:0';
var NS_URN_MAM = NS_XMPP + 'mam:tmp';
var NS_URN_DELAY = NS_XMPP + 'delay';
var NS_URN_RECEIPTS = NS_XMPP + 'receipts';
var NS_URN_CARBONS = NS_XMPP + 'carbons:2';
var NS_URN_CORRECT = NS_XMPP + 'message-correct:0';
var NS_URN_IDLE = NS_XMPP + 'idle:1';
var NS_URN_REACH = NS_XMPP + 'reach:0';
var NS_URN_MARKERS = NS_XMPP + 'chat-markers:0';
var NS_URN_ATTENTION = NS_XMPP + 'attention:0';
var NS_URN_HINTS = NS_XMPP + 'hints';
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_XMPP + 'stanzas';
var NS_STREAMS = NS_IETF_XMPP + 'streams';
var NS_STANZAS = NS_IETF_XMPP + 'stanzas';
var NS_STREAMS = NS_IETF_XMPP + 'streams';
var NS_TLS = NS_IETF_XMPP + 'tls';
var NS_SASL = NS_IETF_XMPP + 'sasl';
var NS_SESSION = NS_IETF_XMPP + 'session';
var NS_BIND = NS_IETF_XMPP + 'bind';
var NS_TLS = NS_IETF_XMPP + 'tls';
var NS_SASL = NS_IETF_XMPP + 'sasl';
var NS_SESSION = NS_IETF_XMPP + 'session';
var NS_BIND = NS_IETF_XMPP + 'bind';
var NS_FEATURE_IQAUTH = NS_FEATURES + 'iq-auth';
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_FEATURE_COMPRESS = NS_FEATURES + 'compress';
var NS_COMPRESS = NS_PROTOCOL + 'compress';
var NS_COMPRESS = NS_PROTOCOL + 'compress';
var NS_METRONOME_MAM_PURGE = 'http://metronome.im/protocol/mam-purge';
@ -181,7 +187,7 @@ 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;

View file

@ -0,0 +1,509 @@
/*
Jappix - An open social platform
Implementation of XEP-0308: Last Message Correction
-------------------------------------------------
License: AGPL
Author: Valérian Saliou
*/
// Bundle
var Correction = (function () {
/**
* Alias of this
* @private
*/
var self = {};
/**
* @private
* @param {string} xid
* @return {boolean}
*/
self._hasSupport = function(xid) {
var support = false;
try {
if($('#' + hex_md5(xid) + '[data-correction="true"]').size()) {
support = true;
}
} catch(e) {
Console.error('Correction._hasSupport', e);
} finally {
return support;
}
};
/**
* @private
* @param {string} xid
* @return {string}
*/
self._getLastID = function(xid) {
var last_id = null;
try {
if(self._hasSupport(xid) === true) {
// Check last message from ourselves
last_id = $('#' + hex_md5(xid) + ' .content .one-line.user-message[data-mode="me"]:last').attr('data-id') || null;
}
} catch(e) {
Console.error('Correction._getLastID', e);
} finally {
return last_id;
}
};
/**
* @private
* @param {string} xid
* @return {string}
*/
self._getCurrentID = function(xid) {
var current_id = null;
try {
if(self._hasSupport(xid) === true) {
// Check the ID of the message being edited (if any)
current_id = $('#' + hex_md5(xid) + ' .message-area').attr('data-correction-current') || null;
}
} catch(e) {
Console.error('Correction._getCurrentID', e);
} finally {
return current_id;
}
};
/**
* @private
* @param {string} xid
* @return {object}
*/
self._getLastMessage = function(xid) {
var last_message_val = null;
var last_message_sel = null;
try {
if(self._hasSupport(xid) === true) {
// Check last message from ourselves
last_message_sel = $('#' + hex_md5(xid) + ' .content .one-line.user-message[data-mode="me"]:last');
last_message_val = last_message_sel.find('.message-content').text() || null;
if(last_message_val === null) {
last_message_sel = null;
}
}
} catch(e) {
Console.error('Correction._getLastMessage', e);
} finally {
return {
'value': last_message_val,
'selector': last_message_sel
};
}
};
/**
* @private
* @param {string} xid
* @param {object} message_sel
* @return {undefined}
*/
self._bindInterface = function(xid, message_sel) {
try {
// Add message area elements
var text_sel = $('#' + hex_md5(xid) + ' .text');
text_sel.addClass('correction-active');
text_sel.prepend(
'<div class="correction-toolbox">' +
'<span class="correction-editing">' + Common._e("Editing") + '</span>' +
'<a class="correction-cancel" href="#">' + Common._e("Cancel") + '</a>' +
'</div>'
);
// Add message correction marker
message_sel.addClass('correction-active');
message_sel.find('.correction-label').remove();
message_sel.find('.correction-edit').hide();
message_sel.append(
'<span class="correction-label">' +
Common._e("Being edited") +
'</span>'
);
// Bind click events
text_sel.find('.correction-cancel').click(function() {
self.leave(xid);
return false;
});
} catch(e) {
Console.error('Correction._bindInterface', e);
}
};
/**
* @private
* @param {string} xid
* @param {object} message_sel
* @return {undefined}
*/
self._unbindInterface = function(xid, message_sel) {
try {
// Remove message area elements
var text_sel = $('#' + hex_md5(xid) + ' .text');
text_sel.removeClass('correction-active');
text_sel.find('.correction-toolbox, .correction-label').remove();
if(message_sel.size()) {
message_sel.find('.correction-edit').css('display', '');
// Remove message correction marker
message_sel.removeClass('correction-active');
message_sel.find('.correction-label').remove();
}
} catch(e) {
Console.error('Correction._unbindInterface', e);
}
};
/**
* @private
* @param {string} xid
* @param {string} full_xid
* @param {string} type
* @param {string} message_id
* @param {string} message_body
* @return {string}
*/
self._sendStanza = function(xid, full_xid, type, message_id, message_body) {
var args = {
'id': null,
'xhtml': false,
'message': null
};
try {
var hash = hex_md5(xid);
var id = genID();
args.id = id;
// Initialize message stanza
var message = new JSJaCMessage();
args.message = message;
message.setType(type);
message.setTo(full_xid);
message.setID(id);
// Generates the correct message depending of the choosen style
var generate_message = Message.generate(message, message_body, hash);
args.xhtml = (generate_message === 'XHTML');
// Receipt request
var receipt_request = Receipts.request(hash);
if(receipt_request) {
message.appendNode('request', {'xmlns': NS_URN_RECEIPTS});
}
// Chatstate
message.appendNode('active', {'xmlns': NS_CHATSTATES});
if(message_id !== null) {
message.appendNode('replace', {
'xmlns': NS_URN_CORRECT,
'id': message_id
});
}
con.send(message, Errors.handleReply);
} catch(e) {
Console.error('Correction._sendStanza', e);
} finally {
return args;
}
};
/**
* Detects correction mode request (in input)
* @public
* @param {string} xid
* @param {object} input_sel
* @return {undefined}
*/
self.detect = function(xid, input_sel) {
try {
// Other keys
if(input_sel.val().match(/^\/correct/) && self.isIn(xid) === false) {
// Enter correction mode?
self.enter(xid);
}
} catch(e) {
Console.error('Correction.detect', e);
}
};
/**
* Enter correction mode (for last message)
* @public
* @param {string} xid
* @return {undefined}
*/
self.enter = function(xid) {
try {
Console.debug('Correction.enter', 'Requested to enter the correction mode with: ' + xid);
if(self._hasSupport(xid) === true && self.isIn(xid) === false) {
var last_message = self._getLastMessage(xid);
if(last_message.value && last_message.selector) {
Console.info('Correction.enter', 'Valid last message found for correction mode with: ' + xid);
var message_area_sel = $('#' + hex_md5(xid) + ' .message-area');
message_area_sel.val(last_message.value);
self._bindInterface(
xid,
last_message.selector
);
// Focus hack (to get cursor at the end of textarea)
message_area_sel.oneTime(10, function() {
message_area_sel[0].select();
message_area_sel[0].selectionStart = message_area_sel[0].selectionEnd;
});
}
}
} catch(e) {
Console.error('Correction.enter', e);
}
};
/**
* Leave correction mode
* @public
* @param {string} xid
* @return {undefined}
*/
self.leave = function(xid) {
try {
if(self.isIn(xid) === true) {
var base_sel = $('#' + hex_md5(xid));
var active_message_sel = base_sel.find('.content .one-line.user-message.correction-active');
self._unbindInterface(xid, active_message_sel);
var message_area_sel = base_sel.find('.message-area');
message_area_sel.val('');
message_area_sel.focus();
}
} catch(e) {
Console.error('Correction.leave', e);
}
};
/**
* Send corrected message
* @public
* @param {string} xid
* @param {string} type
* @param {string} replacement
* @return {undefined}
*/
self.send = function(xid, type, replacement) {
try {
if(self._hasSupport(xid) === true) {
if(self._getLastMessage(xid).value != replacement) {
var own_xid = Common.getXID();
var hash = hex_md5(xid);
var replace_id = self._getLastID(xid);
Console.info('Correction.send', 'Sending replacement message for: ' + xid + ' "' + replacement + '" with ID: ' + (replace_id || 'none'));
// Send the stanza itself
var full_xid = Presence.highestPriority(xid) || xid;
var stanza_args = self._sendStanza(
xid,
full_xid,
type,
replace_id,
replacement
);
// Update DOM (for chat only)
if(type == 'chat') {
// Filter the xHTML message (for us!)
var replacement_formatted = replacement;
if(stanza_args.xhtml) {
replacement_formatted = Filter.xhtml(stanza_args.message.getNode());
}
// Remove old message
old_message_sel = $('#' + hash + ' .content .one-line.user-message[data-mode="me"]').filter(function() {
return ($(this).attr('data-id') + '') === (replace_id + '');
}).filter(':last');
var edit_count = old_message_sel.attr('data-edit-count') || 0;
edit_count = isNaN(edit_count) ? 0 : parseInt(edit_count, 10);
if(type == 'chat') {
old_message_sel.remove();
}
// Display edited message
Message.display(
'chat',
own_xid,
hash,
Name.getBuddy(own_xid).htmlEnc(),
replacement_formatted,
DateUtils.getCompleteTime(),
DateUtils.getTimeStamp(),
'user-message',
!stanza_args.xhtml,
'',
'me',
stanza_args.id,
undefined,
undefined,
true,
(edit_count + 1)
);
}
}
}
} catch(e) {
Console.error('Correction.send', e);
}
};
/**
* Catches a replace message
* @public
* @param {object} message
* @param {string} hash
* @param {string} type
* @return {object}
*/
self.catch = function(message, hash, type) {
var edit_results = {
'has_replace': false,
'is_edited': false,
'count': 0,
'next_count': 0
};
try {
var replace_node = message.getChild('replace', NS_URN_CORRECT);
if(replace_node) {
edit_results.has_replace = true;
var message_edit_id = $(replace_node).attr('id');
if(typeof message_edit_id != 'undefined') {
var message_edit_sel = $('#' + hash + ' .one-line.user-message').filter(function() {
var this_sel = $(this);
var is_valid_mode = true;
if(type == 'chat') {
is_valid_mode = true ? this_sel.attr('data-mode') == 'him' : false;
}
return is_valid_mode && ((this_sel.attr('data-id') + '') === (message_edit_id + ''));
}).filter(':last');
if(message_edit_sel.size()) {
edit_results.count = message_edit_sel.attr('data-edit-count') || 0;
edit_results.count = isNaN(edit_results.count) ? 0 : parseInt(edit_results.count, 10);
edit_results.next_count = edit_results.count + 1;
edit_results.is_edited = true;
// Empty group?
var message_edit_group_sel = message_edit_sel.parents('.one-group');
if(message_edit_group_sel.find('.one-line').size() <= 1) {
message_edit_group_sel.remove();
} else {
message_edit_sel.remove();
}
}
}
}
} catch(e) {
Console.error('Correction.catch', e);
} finally {
return edit_results;
}
};
/**
* Returns whether we are in correction mode or not
* @public
* @param {string} xid
* @return {boolean}
*/
self.isIn = function(xid) {
var is_in = false;
try {
is_in = $('#' + hex_md5(xid) + ' .text').hasClass('correction-active');
} catch(e) {
Console.error('Correction.isIn', e);
} finally {
return is_in;
}
};
/**
* Return class scope
*/
return self;
})();

File diff suppressed because it is too large Load diff

View file

@ -39,8 +39,9 @@ var DataStore = (function () {
this.key = function(key) {
if(legacy) {
if(key >= this.length)
if(key >= this.length) {
return null;
}
var c = 0;
@ -56,8 +57,9 @@ var DataStore = (function () {
this.getItem = function(key) {
if(legacy) {
if(storage_emulated[key] !== undefined)
if(storage_emulated[key] !== undefined) {
return storage_emulated[key];
}
return null;
} else {
@ -67,8 +69,9 @@ var DataStore = (function () {
this.setItem = function(key, data) {
if(legacy) {
if(!(key in storage_emulated))
if(!(key in storage_emulated)) {
this.length++;
}
storage_emulated[key] = (data + '');
} else {
@ -162,7 +165,7 @@ var DataStore = (function () {
try {
return self.storageDB.getItem(dbID + '_' + type + '_' + id);
}
catch(e) {
Console.error('Error while getting a temporary database entry (' + dbID + ' -> ' + type + ' -> ' + id + ')', e);
}
@ -192,7 +195,7 @@ var DataStore = (function () {
return true;
}
catch(e) {
Console.error('Error while writing a temporary database entry (' + dbID + ' -> ' + type + ' -> ' + id + ')', e);
}
@ -218,10 +221,10 @@ var DataStore = (function () {
try {
try {
self.storageDB.removeItem(dbID + '_' + type + '_' + id);
return true;
}
catch(e) {
Console.error('Error while removing a temporary database entry (' + dbID + ' -> ' + type + ' -> ' + id + ')', e);
}
@ -263,15 +266,15 @@ var DataStore = (function () {
try {
try {
self.storageDB.clear();
Console.info('Temporary database cleared.');
return true;
}
catch(e) {
Console.error('Error while clearing temporary database', e);
return false;
}
} catch(e) {
@ -294,7 +297,7 @@ var DataStore = (function () {
// Try to write something
self.storagePersistent.setItem('haspersistent_check', 'ok');
self.storagePersistent.removeItem('haspersistent_check');
has_persistent = true;
} catch(e) {
Console.error('DataStore.hasPersistent', e);
@ -319,10 +322,10 @@ var DataStore = (function () {
try {
return self.storagePersistent.getItem(dbID + '_' + type + '_' + id);
}
catch(e) {
Console.error('Error while getting a persistent database entry (' + dbID + ' -> ' + type + ' -> ' + id + ')', e);
return null;
}
} catch(e) {
@ -346,24 +349,24 @@ var DataStore = (function () {
try {
try {
self.storagePersistent.setItem(dbID + '_' + type + '_' + id, value);
return true;
}
// Database might be full
catch(e) {
Console.warn('Retrying: could not write a persistent database entry (' + dbID + ' -> ' + type + ' -> ' + id + ')', e);
// Flush it!
self.flushPersistent();
// Set the item again
try {
self.storagePersistent.setItem(dbID + ' -> ' + type + '_' + id, value);
return true;
}
// New error!
catch(_e) {
Console.error('Aborted: error while writing a persistent database entry (' + dbID + ' -> ' + type + ' -> ' + id + ')', _e);
@ -394,7 +397,7 @@ var DataStore = (function () {
return true;
}
catch(e) {
Console.error('Error while removing a persistent database entry (' + dbID + ' -> ' + type + ' -> ' + id + ')', e);
}
@ -439,10 +442,10 @@ var DataStore = (function () {
self.storagePersistent.clear();
Console.info('Persistent database cleared.');
return true;
}
catch(e) {
Console.error('Error while clearing persistent database', e);
}
@ -467,19 +470,20 @@ var DataStore = (function () {
try {
// Get the stored session entry
var session = self.getPersistent('global', 'session', 1);
// Reset the persistent database
self.resetPersistent();
// Restaure the stored session entry
if(session)
if(session) {
self.setPersistent('global', 'session', 1, session);
}
Console.info('Persistent database flushed.');
return true;
}
catch(e) {
Console.error('Error while flushing persistent database', e);
}

View file

@ -84,9 +84,10 @@ var DateUtils = (function () {
try {
// Last activity not yet initialized?
if(self.last_activity === 0)
if(self.last_activity === 0) {
return 0;
}
return self.getTimeStamp() - self.last_activity;
} catch(e) {
Console.error('DateUtils.getLastActivity', e);
@ -95,6 +96,27 @@ var DateUtils = (function () {
};
/**
* Gets the last user activity as a date
* @public
* @return {string}
*/
self.getLastActivityDate = function() {
try {
var last_activity = self.last_activity || self.getTimeStamp();
var last_date = new Date();
last_date.setTime(last_activity * 1000);
return self.getDatetime(last_date, 'utc');
} catch(e) {
Console.error('DateUtils.getLastActivityDate', e);
}
};
/**
* Gets the last user available presence in seconds
* @public
@ -104,9 +126,10 @@ var DateUtils = (function () {
try {
// Last presence stamp not yet initialized?
if(self.presence_last_activity === 0)
if(self.presence_last_activity === 0) {
return 0;
}
return self.getTimeStamp() - self.presence_last_activity;
} catch(e) {
Console.error('DateUtils.getPresenceLast', e);
@ -115,6 +138,56 @@ var DateUtils = (function () {
};
/**
* Generates a normalized datetime
* @public
* @param {Date} date
* @param {string} location
* @return {string}
*/
self.getDatetime = function(date, location) {
/* FROM : http://trac.jwchat.org/jsjac/browser/branches/jsjac_1.0/jsextras.js?rev=221 */
var year, month, day, hours, minutes, seconds;
var date_string = null;
try {
if(location == 'utc') {
// UTC date
year = date.getUTCFullYear();
month = date.getUTCMonth();
day = date.getUTCDate();
hours = date.getUTCHours();
minutes = date.getUTCMinutes();
seconds = date.getUTCSeconds();
} else {
// Local date
year = date.getFullYear();
month = date.getMonth();
day = date.getDate();
hours = date.getHours();
minutes = date.getMinutes();
seconds = date.getSeconds();
}
// Generates the date string
date_string = year + '-';
date_string += Common.padZero(month + 1) + '-';
date_string += Common.padZero(day) + 'T';
date_string += Common.padZero(hours) + ':';
date_string += Common.padZero(minutes) + ':';
date_string += Common.padZero(seconds) + 'Z';
// Returns the date string
return date_string;
} catch(e) {
Console.error('DateUtils.getDatetime', e);
}
};
/**
* Generates the time for XMPP
* @public
@ -123,43 +196,11 @@ var DateUtils = (function () {
*/
self.getXMPPTime = function(location) {
/* FROM : http://trac.jwchat.org/jsjac/browser/branches/jsjac_1.0/jsextras.js?rev=221 */
try {
// 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 += Common.padZero(month + 1) + '-';
jDate += Common.padZero(day) + 'T';
jDate += Common.padZero(hours) + ':';
jDate += Common.padZero(minutes) + ':';
jDate += Common.padZero(seconds) + 'Z';
// Returns the date string
return jDate;
return self.getDatetime(
(new Date()),
location
);
} catch(e) {
Console.error('DateUtils.getXMPPTime', e);
}
@ -176,10 +217,11 @@ var DateUtils = (function () {
try {
var init = new Date();
var time = Common.padZero(init.getHours()) + ':';
time += Common.padZero(init.getMinutes()) + ':';
time += Common.padZero(init.getSeconds());
return time;
} catch(e) {
Console.error('DateUtils.getCompleteTime', e);
@ -199,26 +241,26 @@ var DateUtils = (function () {
// 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 + Common.padZero(hours) + ':' + Common.padZero(minutes);
// Return the processed value
return tzo;
} catch(e) {
@ -259,7 +301,7 @@ var DateUtils = (function () {
try {
var date = Date.jab2date(to_parse);
var parsed = date.toLocaleDateString() + ' (' + date.toLocaleTimeString() + ')';
return parsed;
} catch(e) {
Console.error('DateUtils.parse', e);
@ -279,7 +321,7 @@ var DateUtils = (function () {
try {
var date = Date.jab2date(to_parse);
var parsed = date.toLocaleDateString();
return parsed;
} catch(e) {
Console.error('DateUtils.parseDay', e);
@ -299,7 +341,7 @@ var DateUtils = (function () {
try {
var date = Date.jab2date(to_parse);
var parsed = date.toLocaleTimeString();
return parsed;
} catch(e) {
Console.error('DateUtils.parseTime', e);
@ -321,32 +363,36 @@ var DateUtils = (function () {
var current_date = Date.jab2date(self.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))
if(isNaN(old_stamp) || isNaN(days)) {
return self.getCompleteTime();
}
// Is it today?
if(current_day == old_day)
if(current_day == old_day) {
return old_time;
}
// It is yesterday?
if(days <= 1)
if(days <= 1) {
return Common._e("Yesterday") + ' - ' + old_time;
}
// Is it less than a week ago?
if(days <= 7)
if(days <= 7) {
return Common.printf(Common._e("%s days ago"), days) + ' - ' + old_time;
}
// Another longer period
return old_date.toLocaleDateString() + ' - ' + old_time;
} catch(e) {
@ -360,30 +406,36 @@ var DateUtils = (function () {
* Reads a message delay
* @public
* @param {string} node
* @return {string}
* @param {boolean} return_date
* @return {string|Date}
*/
self.readMessageDelay = function(node) {
self.readMessageDelay = function(node, return_date) {
try {
// 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)
// Get delay
if(d_delay) {
// New delay (valid XEP)
delay = d_delay;
// Old delay (obsolete XEP!)
else {
// Try to read the old-school delay
} else {
// Old delay (obsolete XEP!)
var x_delay = jQuery(node).find('x[xmlns="' + NS_DELAY + '"]:first').attr('stamp');
if(x_delay)
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 a date object?
if(return_date === true && delay) {
return Date.jab2date(delay);
}
return delay;
} catch(e) {
Console.error('DateUtils.readMessageDelay', e);

View file

@ -1,10 +1,10 @@
/**
* Version: 1.0 Alpha-1
* Build Date: 13-Nov-2007
* Copyright (c) 2006-2007, Coolite Inc. (http://www.coolite.com/). All rights reserved.
* License: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/.
* Website: http://www.datejs.com/ or http://www.coolite.com/datejs/
*/
/**
* Version: 1.0 Alpha-1
* Build Date: 13-Nov-2007
* Copyright (c) 2006-2007, Coolite Inc. (http://www.coolite.com/). All rights reserved.
* License: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/.
* Website: http://www.datejs.com/ or http://www.coolite.com/datejs/
*/
Date.CultureInfo={name:"en-US",englishName:"English (United States)",nativeName:"English (United States)",dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],abbreviatedDayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],shortestDayNames:["Su","Mo","Tu","We","Th","Fr","Sa"],firstLetterDayNames:["S","M","T","W","T","F","S"],monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],abbreviatedMonthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],amDesignator:"AM",pmDesignator:"PM",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"mdy",formatPatterns:{shortDate:"M/d/yyyy",longDate:"dddd, MMMM dd, yyyy",shortTime:"h:mm tt",longTime:"h:mm:ss tt",fullDateTime:"dddd, MMMM dd, yyyy h:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^jan(uary)?/i,feb:/^feb(ruary)?/i,mar:/^mar(ch)?/i,apr:/^apr(il)?/i,may:/^may/i,jun:/^jun(e)?/i,jul:/^jul(y)?/i,aug:/^aug(ust)?/i,sep:/^sep(t(ember)?)?/i,oct:/^oct(ober)?/i,nov:/^nov(ember)?/i,dec:/^dec(ember)?/i,sun:/^su(n(day)?)?/i,mon:/^mo(n(day)?)?/i,tue:/^tu(e(s(day)?)?)?/i,wed:/^we(d(nesday)?)?/i,thu:/^th(u(r(s(day)?)?)?)?/i,fri:/^fr(i(day)?)?/i,sat:/^sa(t(urday)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\+|after|from)/i,subtract:/^(\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\.?m?\.?|p\.?m?\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt)/i,ordinalSuffix:/^\s*(st|nd|rd|th)/i,timeContext:/^\s*(\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
Date.getMonthNumberFromName=function(name){var n=Date.CultureInfo.monthNames,m=Date.CultureInfo.abbreviatedMonthNames,s=name.toLowerCase();for(var i=0;i<n.length;i++){if(n[i].toLowerCase()==s||m[i].toLowerCase()==s){return i;}}
return-1;};Date.getDayNumberFromName=function(name){var n=Date.CultureInfo.dayNames,m=Date.CultureInfo.abbreviatedDayNames,o=Date.CultureInfo.shortestDayNames,s=name.toLowerCase();for(var i=0;i<n.length;i++){if(n[i].toLowerCase()==s||m[i].toLowerCase()==s){return i;}}
@ -101,4 +101,4 @@ return _.any.apply(null,rx);}else{return _get(fx);}};g._formats=g.formats(["yyyy
return g._start.call({},s);};}());Date._parse=Date.parse;Date.parse=function(s){var r=null;if(!s){return null;}
try{r=Date.Grammar.start.call({},s);}catch(e){return null;}
return((r[1].length===0)?r[0]:null);};Date.getParseFunction=function(fx){var fn=Date.Grammar.formats(fx);return function(s){var r=null;try{r=fn.call({},s);}catch(e){return null;}
return((r[1].length===0)?r[0]:null);};};Date.parseExact=function(s,fx){return Date.getParseFunction(fx)(s);};
return((r[1].length===0)?r[0]:null);};};Date.parseExact=function(s,fx){return Date.getParseFunction(fx)(s);};

View file

@ -29,31 +29,31 @@ var Directory = (function () {
try {
// Popup HTML content
var html =
'<div class="top">' + Common._e("User directory") + '</div>' +
'<div class="content">' +
'<div class="directory-head">' +
'<div class="directory-server-text">' + Common._e("Server to query") + '</div>' +
'<input name="directory-server-input" class="directory-server-input" value="' + Common.encodeQuotes(HOST_VJUD) + '" />' +
'</div>' +
'<div class="results directory-results"></div>' +
'</div>' +
'<div class="bottom">' +
'<div class="wait wait-medium"></div>' +
'<a href="#" class="finish">' + Common._e("Close") + '</a>' +
var html =
'<div class="top">' + Common._e("User directory") + '</div>' +
'<div class="content">' +
'<div class="directory-head">' +
'<div class="directory-server-text">' + Common._e("Server to query") + '</div>' +
'<input name="directory-server-input" class="directory-server-input" value="' + Common.encodeQuotes(HOST_VJUD) + '" />' +
'</div>' +
'<div class="results directory-results"></div>' +
'</div>' +
'<div class="bottom">' +
'<div class="wait wait-medium"></div>' +
'<a href="#" class="finish">' + Common._e("Close") + '</a>' +
'</div>';
// Create the popup
Popup.create('directory', html);
// Associate the events
self.instance();
// Start a search!
self.start();
} catch(e) {
@ -94,10 +94,10 @@ var Directory = (function () {
try {
// Get the server to query
var server = $('#directory .directory-server-input').val();
// Launch the search!
DataForm.go($('#directory .directory-server-input').val(), 'search', '', '', 'directory');
Console.log('Directory search launched: ' + server);
} catch(e) {
Console.error('Directory.start', e);
@ -118,17 +118,18 @@ var Directory = (function () {
try {
// Click event
$('#directory .bottom .finish').click(self.close);
// Keyboard event
$('#directory .directory-server-input').keyup(function(e) {
if(e.keyCode == 13) {
// No value?
if(!$(this).val())
if(!$(this).val()) {
$(this).val(HOST_VJUD);
}
// Start the directory search
self.start();
return false;
}
});

View file

@ -29,99 +29,99 @@ var Discovery = (function () {
try {
// Popup HTML content
var html =
'<div class="top">' + Common._e("Service discovery") + '</div>' +
'<div class="content">' +
'<div class="discovery-head">' +
'<div class="disco-server-text">' + Common._e("Server to query") + '</div>' +
'<input name="disco-server-input" class="disco-server-input" value="' + Common.encodeQuotes(HOST_MAIN) + '" />' +
'</div>' +
'<div class="results discovery-results">' +
'<div class="disco-category disco-account">' +
'<p class="disco-category-title">' + Common._e("Accounts") + '</p>' +
'</div>' +
'<div class="disco-category disco-auth">' +
'<p class="disco-category-title">' + Common._e("Authentications") + '</p>' +
'</div>' +
'<div class="disco-category disco-automation">' +
'<p class="disco-category-title">' + Common._e("Automation") + '</p>' +
'</div>' +
'<div class="disco-category disco-client">' +
'<p class="disco-category-title">' + Common._e("Clients") + '</p>' +
'</div>' +
'<div class="disco-category disco-collaboration">' +
'<p class="disco-category-title">' + Common._e("Collaboration") + '</p>' +
'</div>' +
'<div class="disco-category disco-component">' +
'<p class="disco-category-title">' + Common._e("Components") + '</p>' +
'</div>' +
'<div class="disco-category disco-conference">' +
'<p class="disco-category-title">' + Common._e("Rooms") + '</p>' +
'</div>' +
'<div class="disco-category disco-directory">' +
'<p class="disco-category-title">' + Common._e("Directories") + '</p>' +
'</div>' +
'<div class="disco-category disco-gateway">' +
'<p class="disco-category-title">' + Common._e("Gateways") + '</p>' +
'</div>' +
'<div class="disco-category disco-headline">' +
'<p class="disco-category-title">' + Common._e("News") + '</p>' +
'</div>' +
'<div class="disco-category disco-hierarchy">' +
'<p class="disco-category-title">' + Common._e("Hierarchy") + '</p>' +
'</div>' +
'<div class="disco-category disco-proxy">' +
'<p class="disco-category-title">' + Common._e("Proxies") + '</p>' +
'</div>' +
'<div class="disco-category disco-pubsub">' +
'<p class="disco-category-title">' + Common._e("Publication/Subscription") + '</p>' +
'</div>' +
'<div class="disco-category disco-server">' +
'<p class="disco-category-title">' + Common._e("Server") + '</p>' +
'</div>' +
'<div class="disco-category disco-store">' +
'<p class="disco-category-title">' + Common._e("Storage") + '</p>' +
'</div>' +
'<div class="disco-category disco-others">' +
'<p class="disco-category-title">' + Common._e("Others") + '</p>' +
'</div>' +
'<div class="disco-category disco-wait">' +
'<p class="disco-category-title">' + Common._e("Loading") + '</p>' +
'</div>' +
'</div>' +
'</div>' +
'<div class="bottom">' +
'<div class="wait wait-medium"></div>' +
'<a href="#" class="finish">' + Common._e("Close") + '</a>' +
var html =
'<div class="top">' + Common._e("Service discovery") + '</div>' +
'<div class="content">' +
'<div class="discovery-head">' +
'<div class="disco-server-text">' + Common._e("Server to query") + '</div>' +
'<input name="disco-server-input" class="disco-server-input" value="' + Common.encodeQuotes(HOST_MAIN) + '" />' +
'</div>' +
'<div class="results discovery-results">' +
'<div class="disco-category disco-account">' +
'<p class="disco-category-title">' + Common._e("Accounts") + '</p>' +
'</div>' +
'<div class="disco-category disco-auth">' +
'<p class="disco-category-title">' + Common._e("Authentications") + '</p>' +
'</div>' +
'<div class="disco-category disco-automation">' +
'<p class="disco-category-title">' + Common._e("Automation") + '</p>' +
'</div>' +
'<div class="disco-category disco-client">' +
'<p class="disco-category-title">' + Common._e("Clients") + '</p>' +
'</div>' +
'<div class="disco-category disco-collaboration">' +
'<p class="disco-category-title">' + Common._e("Collaboration") + '</p>' +
'</div>' +
'<div class="disco-category disco-component">' +
'<p class="disco-category-title">' + Common._e("Components") + '</p>' +
'</div>' +
'<div class="disco-category disco-conference">' +
'<p class="disco-category-title">' + Common._e("Rooms") + '</p>' +
'</div>' +
'<div class="disco-category disco-directory">' +
'<p class="disco-category-title">' + Common._e("Directories") + '</p>' +
'</div>' +
'<div class="disco-category disco-gateway">' +
'<p class="disco-category-title">' + Common._e("Gateways") + '</p>' +
'</div>' +
'<div class="disco-category disco-headline">' +
'<p class="disco-category-title">' + Common._e("News") + '</p>' +
'</div>' +
'<div class="disco-category disco-hierarchy">' +
'<p class="disco-category-title">' + Common._e("Hierarchy") + '</p>' +
'</div>' +
'<div class="disco-category disco-proxy">' +
'<p class="disco-category-title">' + Common._e("Proxies") + '</p>' +
'</div>' +
'<div class="disco-category disco-pubsub">' +
'<p class="disco-category-title">' + Common._e("Publication/Subscription") + '</p>' +
'</div>' +
'<div class="disco-category disco-server">' +
'<p class="disco-category-title">' + Common._e("Server") + '</p>' +
'</div>' +
'<div class="disco-category disco-store">' +
'<p class="disco-category-title">' + Common._e("Storage") + '</p>' +
'</div>' +
'<div class="disco-category disco-others">' +
'<p class="disco-category-title">' + Common._e("Others") + '</p>' +
'</div>' +
'<div class="disco-category disco-wait">' +
'<p class="disco-category-title">' + Common._e("Loading") + '</p>' +
'</div>' +
'</div>' +
'</div>' +
'<div class="bottom">' +
'<div class="wait wait-medium"></div>' +
'<a href="#" class="finish">' + Common._e("Close") + '</a>' +
'</div>';
// Create the popup
Popup.create('discovery', html);
// Associate the events
self.instance();
// We request a disco to the default server
self.start();
} catch(e) {
@ -164,10 +164,10 @@ var Discovery = (function () {
try {
// We get the server to query
var discoServer = $('#discovery .disco-server-input').val();
// We launch the items query
DataForm.go(discoServer, 'browse', '', '', 'discovery');
Console.log('Service discovery launched: ' + discoServer);
} catch(e) {
Console.error('Discovery.start', e);
@ -188,10 +188,10 @@ var Discovery = (function () {
try {
// 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();
} catch(e) {
@ -211,17 +211,18 @@ var Discovery = (function () {
try {
// Click event
$('#discovery .bottom .finish').click(self.close);
// Keyboard event
$('#discovery .disco-server-input').keyup(function(e) {
if(e.keyCode == 13) {
// No value?
if(!$(this).val())
if(!$(this).val()) {
$(this).val(HOST_MAIN);
}
// Start the discovery
self.start();
return false;
}
});

View file

@ -35,30 +35,33 @@ var Errors = (function () {
if(condition || reason) {
// Initialize the error text
var eText = '';
// Any error condition
if(condition)
if(condition) {
eText += condition;
}
// Any error type
if(type && eText)
if(type && eText) {
eText += ' (' + type + ')';
}
// Any error reason
if(reason) {
if(eText)
if(eText) {
eText += ' - ';
}
eText += reason;
}
// We reveal the error
Board.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 {
Board.openThisError(2);
@ -84,75 +87,76 @@ var Errors = (function () {
// 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 = Common._e("Authorization failed");
break;
case '409':
reason = Common._e("Registration failed, please choose a different username");
break;
case '503':
reason = Common._e("Service unavailable");
break;
case '500':
reason = Common._e("Internal server error, try later");
break;
default:
reason = node.find('text').text();
break;
}
// Remove the general wait item (security)
Interface.removeGeneralWait();
// Show reconnect pane
if(Connection.current_session && Connection.connected) {
// Anonymous?
if(Utils.isAnonymous())
if(Utils.isAnonymous()) {
Connection.createReconnect('anonymous');
else
} else {
Connection.createReconnect('normal');
}
}
// Show the homepage (security)
else if(!Connection.current_session || !Connection.connected) {
$('#home').show();
Interface.title('home');
}
// Still connected? (security)
if(Common.isConnected()) {
con.disconnect();
}
Console.error('First level error received.');
}
// 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, ' ');
Console.error('Second level error received.');
} else {
return false;
}
// Show the error board
self.show(condition, reason, type);
// Return there's an error
return true;
} catch(e) {

View file

@ -29,103 +29,103 @@ var Favorites = (function () {
try {
// Popup HTML content
var html =
'<div class="top">' + Common._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>' +
Common._e("Change favorites") +
'</div>' +
'<div class="room-switcher room-search">' +
'<div class="icon search-icon talk-images"></div>' +
Common._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">' + Common._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>' + Common._e("Name") + '</label>' +
'<input class="fedit-title" type="text" required="" />' +
'</div>' +
'<div class="fedit-line">' +
'<label>' + Common._e("Nickname") + '</label>' +
'<input class="fedit-nick" type="text" value="' + Name.getNick() + '" required="" />' +
'</div>' +
'<div class="fedit-line">' +
'<label>' + Common._e("Room") + '</label>' +
'<input class="fedit-chan" type="text" required="" />' +
'</div>' +
'<div class="fedit-line">' +
'<label>' + Common._e("Server") + '</label>' +
'<input class="fedit-server" type="text" value="' + HOST_MUC + '" required="" />' +
'</div>' +
'<div class="fedit-line">' +
'<label>' + Common._e("Password") + '</label>' +
'<input class="fedit-password" type="password" />' +
'</div>' +
'<div class="fedit-line">' +
'<label>' + Common._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">' + Common._e("Add") + '</a>' +
'<a href="#" class="fedit-terminate fedit-edit one-button talk-images">' + Common._e("Edit") + '</a>' +
'<a href="#" class="fedit-terminate fedit-remove remove one-button talk-images">' + Common._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">' + Common._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">' + Common._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">' + Common._e("Close") + '</a>' +
var html =
'<div class="top">' + Common._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>' +
Common._e("Change favorites") +
'</div>' +
'<div class="room-switcher room-search">' +
'<div class="icon search-icon talk-images"></div>' +
Common._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">' + Common._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>' + Common._e("Name") + '</label>' +
'<input class="fedit-title" type="text" required="" />' +
'</div>' +
'<div class="fedit-line">' +
'<label>' + Common._e("Nickname") + '</label>' +
'<input class="fedit-nick" type="text" value="' + Name.getNick() + '" required="" />' +
'</div>' +
'<div class="fedit-line">' +
'<label>' + Common._e("Room") + '</label>' +
'<input class="fedit-chan" type="text" required="" />' +
'</div>' +
'<div class="fedit-line">' +
'<label>' + Common._e("Server") + '</label>' +
'<input class="fedit-server" type="text" value="' + HOST_MUC + '" required="" />' +
'</div>' +
'<div class="fedit-line">' +
'<label>' + Common._e("Password") + '</label>' +
'<input class="fedit-password" type="password" />' +
'</div>' +
'<div class="fedit-line">' +
'<label>' + Common._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">' + Common._e("Add") + '</a>' +
'<a href="#" class="fedit-terminate fedit-edit one-button talk-images">' + Common._e("Edit") + '</a>' +
'<a href="#" class="fedit-terminate fedit-remove remove one-button talk-images">' + Common._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">' + Common._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">' + Common._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">' + Common._e("Close") + '</a>' +
'</div>';
// Create the popup
Popup.create('favorites', html);
// Load the favorites
self.load();
// Associate the events
self.instance();
} catch(e) {
@ -143,16 +143,21 @@ var Favorites = (function () {
self.reset = function() {
try {
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(Name.getNick());
$(path + '.fsearch-head-server, ' + path + '.fedit-server').val(HOST_MUC);
$(path + '.fedit-autojoin').removeAttr('checked');
var path_sel = $('#favorites');
path_sel.find('.wait');
path_sel.find('.fedit-terminate').hide();
path_sel.find('.fedit-add').show();
path_sel.find('.fsearch-oneresult').remove();
path_sel.find('input').val('');
path_sel.find('.please-complete').removeClass('please-complete');
path_sel.find('.fedit-nick').val(Name.getNick());
path_sel.find('.fsearch-head-server').val(HOST_MUC);
path_sel.find('.fedit-server').val(HOST_MUC);
path_sel.find('.fedit-autojoin').removeAttr('checked');
} catch(e) {
Console.error('Favorites.reset', e);
}
@ -182,30 +187,35 @@ var Favorites = (function () {
/**
* Adds a room to the favorites
* @public
* @param {string} roomXID
* @param {string} roomName
* @param {string} room_xid
* @param {string} room_name
* @return {boolean}
*/
self.addThis = function(roomXID, roomName) {
self.addThis = function(room_xid, room_name) {
try {
// Button path
var button = '#favorites .fsearch-results div[data-xid="' + escape(roomXID) + '"] a.one-button';
var button_sel = $('#favorites .fsearch-results div[data-xid="' + escape(room_xid) + '"] a.one-button');
// Add a remove button instead of the add one
$(button + '.add').replaceWith('<a href="#" class="one-button remove talk-images">' + Common._e("Remove") + '</a>');
button_sel.filter('.add').replaceWith(
'<a href="#" class="one-button remove talk-images">' + Common._e("Remove") + '</a>'
);
// Click event
$(button + '.remove').click(function() {
return self.removeThis(roomXID, roomName);
button_sel.filter('.remove').click(function() {
return self.removeThis(room_xid, room_name);
});
// Hide the add button in the (opened?) groupchat
$('#' + hex_md5(roomXID) + ' .tools-add').hide();
$('#' + hex_md5(room_xid) + ' .tools-add').hide();
// Add the database entry
self.display(roomXID, Common.explodeThis(' (', roomName, 0), Name.getNick(), '0', '');
self.display(
room_xid,
Common.explodeThis(' (', room_name, 0), Name.getNick(), '0', ''
);
// Publish the favorites
self.publish();
} catch(e) {
@ -220,30 +230,30 @@ var Favorites = (function () {
/**
* Removes a room from the favorites
* @public
* @param {string} roomXID
* @param {string} roomName
* @param {string} room_xid
* @param {string} room_name
* @return {boolean}
*/
self.removeThis = function(roomXID, roomName) {
self.removeThis = function(room_xid, room_name) {
try {
// Button path
var button = '#favorites .fsearch-results div[data-xid="' + escape(roomXID) + '"] a.one-button';
var button_sel = $('#favorites .fsearch-results div[data-xid="' + escape(room_xid) + '"] a.one-button');
// Add a remove button instead of the add one
$(button + '.remove').replaceWith('<a href="#" class="one-button add talk-images">' + Common._e("Add") + '</a>');
button_sel.filter('.remove').replaceWith('<a href="#" class="one-button add talk-images">' + Common._e("Add") + '</a>');
// Click event
$(button + '.add').click(function() {
return self.addThis(roomXID, roomName);
button_sel.filter('.add').click(function() {
return self.addThis(room_xid, room_name);
});
// Show the add button in the (opened?) groupchat
$('#' + hex_md5(roomXID) + ' .tools-add').show();
$('#' + hex_md5(room_xid) + ' .tools-add').show();
// Remove the favorite
self.remove(roomXID, true);
self.remove(room_xid, true);
// Publish the favorites
self.publish();
} catch(e) {
@ -264,31 +274,34 @@ var Favorites = (function () {
try {
// Path to favorites
var favorites = '#favorites .';
var favorites_sel = $('#favorites');
// Reset the favorites
self.reset();
// Show the edit/remove button, hide the others
$(favorites + 'fedit-terminate').hide();
$(favorites + 'fedit-edit').show();
$(favorites + 'fedit-remove').show();
favorites_sel.find('.fedit-terminate').hide();
favorites_sel.find('.fedit-edit').show();
favorites_sel.find('.fedit-remove').show();
// We retrieve the values
var xid = $(favorites + 'fedit-head-select').val();
var data = Common.XMLFromString(DataStore.getDB(Connection.desktop_hash, 'favorites', xid));
var xid = favorites_sel.find('.fedit-head-select').val();
var data_sel = $(Common.XMLFromString(
DataStore.getDB(Connection.desktop_hash, '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(Common.getXIDNick(xid));
$(favorites + 'fedit-server').val(Common.getXIDHost(xid));
$(favorites + 'fedit-password').val($(data).find('password').text());
if($(data).find('autojoin').text() == 'true')
$(favorites + 'fedit-autojoin').attr('checked', true);
favorites_sel.find('.fedit-title').val(data_sel.find('name').text());
favorites_sel.find('.fedit-nick').val(data_sel.find('nick').text());
favorites_sel.find('.fedit-chan').val(Common.getXIDNick(xid));
favorites_sel.find('.fedit-server').val(Common.getXIDHost(xid));
favorites_sel.find('.fedit-password').val(data_sel.find('password').text());
if(data_sel.find('autojoin').text() == 'true') {
favorites_sel.find('.fedit-autojoin').attr('checked', true);
}
}
} catch(e) {
Console.error('Favorites.edit', e);
@ -307,61 +320,59 @@ var Favorites = (function () {
try {
// Path to favorites
var favorites = '#favorites ';
var favorites_sel = $('#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 old_xid = favorites_sel.find('.fedit-head-select').val();
var title = favorites_sel.find('.fedit-title').val();
var nick = favorites_sel.find('.fedit-nick').val();
var room = favorites_sel.find('.fedit-chan').val();
var server = favorites_sel.find('.fedit-server').val();
var xid = room + '@' + server;
var password = $(favorites + '.fedit-password').val();
var password = favorites_sel.find('.fedit-password').val();
var autojoin = 'false';
if($(favorites + '.fedit-autojoin').filter(':checked').size())
if(favorites_sel.find('.fedit-autojoin').filter(':checked').size()) {
autojoin = 'true';
}
// 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')
if(type == 'edit') {
self.remove(old_xid, true);
}
// Display the favorites
self.display(xid, title, nick, autojoin, password);
// Reset the inputs
self.reset();
}
else {
$(favorites + 'input[required]').each(function() {
} else {
favorites_sel.find('input[required]').each(function() {
var select = $(this);
if(!select.val())
if(!select.val()) {
$(document).oneTime(10, function() {
select.addClass('please-complete').focus();
});
else
select.removeClass('please-complete');
} else {
select.removeClass('please-complete');
}
});
}
}
// Must remove a favorite?
else if(type == 'remove') {
} else if(type == 'remove') {
self.remove(old_xid, true);
// Reset the inputs
self.reset();
}
// Publish the new favorites
self.publish();
Console.info('Action on this bookmark: ' + room + '@' + server + ' / ' + type);
} catch(e) {
Console.error('Favorites.terminateThis', e);
@ -385,7 +396,7 @@ var Favorites = (function () {
// 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) {
DataStore.removeDB(Connection.desktop_hash, 'favorites', xid);
@ -407,37 +418,55 @@ var Favorites = (function () {
try {
var iq = new JSJaCIQ();
iq.setType('set');
var query = iq.setQuery(NS_PRIVATE);
var storage = query.appendChild(iq.buildNode('storage', {'xmlns': NS_BOOKMARKS}));
var storage = query.appendChild(iq.buildNode('storage', {
'xmlns': NS_BOOKMARKS
}));
// We generate the XML
var db_regex = new RegExp(('^' + Connection.desktop_hash + '_') + 'favorites_(.+)');
for(var i = 0; i < DataStore.storageDB.length; i++) {
// Get the pointer values
var current = DataStore.storageDB.key(i);
// If the pointer is on a stored favorite
if(current.match(db_regex)) {
var data = Common.XMLFromString(DataStore.storageDB.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();
var data_sel = $(Common.XMLFromString(
DataStore.storageDB.getItem(current)
));
var xid = data_sel.find('xid').text();
var rName = data_sel.find('name').text();
var nick = data_sel.find('nick').text();
var password = data_sel.find('password').text();
var autojoin = data_sel.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));
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));
}
Console.info('Bookmark sent: ' + xid);
}
}
con.send(iq);
} catch(e) {
Console.error('Favorites.publish', e);
@ -454,20 +483,20 @@ var Favorites = (function () {
self.getGCList = function() {
try {
var path = '#favorites .';
var gcServer = $('.fsearch-head-server').val();
var path_sel = $('#favorites');
var groupchat_server = $('.fsearch-head-server').val();
// We reset some things
$(path + 'fsearch-oneresult').remove();
$(path + 'fsearch-noresults').hide();
$(path + 'wait').show();
path_sel.find('.fsearch-oneresult').remove();
path_sel.find('.fsearch-noresults').hide();
path_sel.find('.wait').show();
var iq = new JSJaCIQ();
iq.setType('get');
iq.setTo(gcServer);
iq.setTo(groupchat_server);
iq.setQuery(NS_DISCO_ITEMS);
con.send(iq, self.handleGCList);
} catch(e) {
Console.error('Favorites.getGCList', e);
@ -485,60 +514,72 @@ var Favorites = (function () {
self.handleGCList = function(iq) {
try {
var path = '#favorites .';
var path_sel = $('#favorites');
var from = Common.fullXID(Common.getStanzaFrom(iq));
if(!iq || (iq.getType() != 'result')) {
Board.openThisError(3);
$(path + 'wait').hide();
path_sel.find('.wait').hide();
Console.error('Error while retrieving the rooms: ' + from);
}
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) {
var this_sel = $(this);
var room_xid = this_sel.attr('jid');
var room_name = this_sel.attr('name');
if(room_xid && room_name) {
// Escaped values
var escaped_xid = Utils.encodeOnclick(roomXID);
var escaped_name = Utils.encodeOnclick(roomName);
var escaped_xid = Utils.encodeOnclick(room_xid);
var escaped_name = Utils.encodeOnclick(room_name);
// Initialize the room HTML
html += '<div class="oneresult fsearch-oneresult" data-xid="' + escape(roomXID) + '">' +
'<div class="room-name">' + roomName.htmlEnc() + '</div>' +
html += '<div class="oneresult fsearch-oneresult" data-xid="' + escape(room_xid) + '">' +
'<div class="room-name">' + room_name.htmlEnc() + '</div>' +
'<a href="#" class="one-button join talk-images" onclick="return Favorites.join(\'' + escaped_xid + '\');">' + Common._e("Join") + '</a>';
// This room is yet a favorite
if(DataStore.existDB('favorites', roomXID))
html += '<a href="#" class="one-button remove talk-images" onclick="return Favorites.removeThis(\'' + escaped_xid + '\', \'' + escaped_name + '\');">' + Common._e("Remove") + '</a>';
else
html += '<a href="#" class="one-button add talk-images" onclick="return Favorites.addThis(\'' + escaped_xid + '\', \'' + escaped_name + '\');">' + Common._e("Add") + '</a>';
if(DataStore.existDB(Connection.desktop_hash, 'favorites', room_xid)) {
html += '<a href="#" ' +
'class="one-button remove talk-images" ' +
'onclick="return Favorites.removeThis(\'' + escaped_xid + '\', \'' + escaped_name + '\');"' +
'>' +
Common._e("Remove") +
'</a>';
} else {
html += '<a href="#" ' +
'class="one-button add talk-images" ' +
'onclick="return Favorites.addThis(\'' + escaped_xid + '\', \'' + escaped_name + '\');"' +
'>' +
Common._e("Add") +
'</a>';
}
// Close the room HTML
html += '</div>';
}
});
// Append this code to the popup
$(path + 'fsearch-results').append(html);
path_sel.find('.fsearch-results').append(html);
} else {
path_sel.find('.fsearch-noresults').show();
}
else
$(path + 'fsearch-noresults').show();
Console.info('Rooms retrieved: ' + from);
}
$(path + 'wait').hide();
path_sel.find('.wait').hide();
} catch(e) {
Console.error('Favorites.handleGCList', e);
}
@ -556,7 +597,14 @@ var Favorites = (function () {
try {
self.quit();
Chat.checkCreate(room, 'groupchat', '', '', Common.getXIDNick(room));
Chat.checkCreate(
room,
'groupchat',
'',
'',
Common.getXIDNick(room)
);
} catch(e) {
Console.error('Favorites.join', e);
} finally {
@ -581,15 +629,22 @@ var Favorites = (function () {
try {
// Generate the HTML code
var html = '<option value="' + Common.encodeQuotes(xid) + '">' + name.htmlEnc() + '</option>';
// Remove the existing favorite
self.remove(xid, false);
// We complete the select forms
$('#roster .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>';
var value = '<groupchat>' +
'<xid>' + xid.htmlEnc() + '</xid>' +
'<name>' + name.htmlEnc() + '</name>' +
'<nick>' + nick.htmlEnc() + '</nick>' +
'<autojoin>' + autojoin.htmlEnc() + '</autojoin>' +
'<password>' + password.htmlEnc() + '</password>' +
'</groupchat>';
DataStore.setDB(Connection.desktop_hash, 'favorites', xid, value);
} catch(e) {
Console.error('Favorites.display', e);
@ -608,27 +663,34 @@ var Favorites = (function () {
try {
// Initialize the HTML code
var html = '';
// Read the database
var db_regex = new RegExp(('^' + Connection.desktop_hash + '_') + 'favorites_(.+)');
for(var i = 0; i < DataStore.storageDB.length; i++) {
// Get the pointer values
var current = DataStore.storageDB.key(i);
// If the pointer is on a stored favorite
if(current.match(db_regex)) {
var data = Common.XMLFromString(DataStore.storageDB.getItem(current));
// Add the current favorite to the HTML code
html += '<option value="' + Common.encodeQuotes($(data).find('xid').text()) + '">' + $(data).find('name').text().htmlEnc() + '</option>';
html += '<option value="' + Common.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="">' + Common._e("Select a favorite") + '</option>' + html;
var favorites_popup = '<option value="none" class="fedit-head-select-first-option" selected="">' + Common._e("Select a favorite") + '</option>' + html;
var favorites_bubble = '<option value="none" class="gc-join-first-option" selected="">' +
Common._e("Select a favorite") +
'</option>' + html;
var favorites_popup = '<option value="none" class="fedit-head-select-first-option" selected="">' +
Common._e("Select a favorite") +
'</option>' + html;
// Append the HTML code
$('#roster .buddy-conf-groupchat-select').html(favorites_bubble);
$('#favorites .fedit-head-select').html(favorites_popup);
@ -647,63 +709,65 @@ var Favorites = (function () {
self.instance = function() {
try {
var path = '#favorites .';
var favorites_sel = $('#favorites');
// Keyboard events
$(path + 'fsearch-head-server').keyup(function(e) {
favorites_sel.find('.fsearch-head-server').keyup(function(e) {
if(e.keyCode == 13) {
var this_sel = $(this);
// No value?
if(!$(this).val())
$(this).val(HOST_MUC);
if(!this_sel.val()) {
this_sel.val(HOST_MUC);
}
// Get the list
self.getGCList();
}
});
$(path + 'fedit-line input').keyup(function(e) {
favorites_sel.find('.fedit-line input').keyup(function(e) {
if(e.keyCode == 13) {
// Edit a favorite
if($(path + 'fedit-edit').is(':visible'))
if(favorites_sel.find('.fedit-edit').is(':visible')) {
self.terminateThis('edit');
// Add a favorite
else
} else {
self.terminateThis('add');
}
}
});
// Change events
$('.fedit-head-select').change(self.edit);
// Click events
$(path + 'room-switcher').click(function() {
$(path + 'favorites-content').hide();
favorites_sel.find('.room-switcher').click(function() {
favorites_sel.find('.favorites-content').hide();
self.reset();
});
$(path + 'room-list').click(function() {
$(path + 'favorites-edit').show();
favorites_sel.find('.room-list').click(function() {
favorites_sel.find('.favorites-edit').show();
});
$(path + 'room-search').click(function() {
$(path + 'favorites-search').show();
favorites_sel.find('.room-search').click(function() {
favorites_sel.find('.favorites-search').show();
self.getGCList();
});
$(path + 'fedit-add').click(function() {
favorites_sel.find('.fedit-add').click(function() {
return self.terminateThis('add');
});
$(path + 'fedit-edit').click(function() {
favorites_sel.find('.fedit-edit').click(function() {
return self.terminateThis('edit');
});
$(path + 'fedit-remove').click(function() {
favorites_sel.find('.fedit-remove').click(function() {
return self.terminateThis('remove');
});
$(path + 'bottom .finish').click(function() {
favorites_sel.find('.bottom .finish').click(function() {
return self.quit();
});
} catch(e) {

View file

@ -50,29 +50,29 @@ var Features = (function () {
var to = Utils.getServer();
var caps = con.server_caps;
var xml = null;
// Try to get the stored data
if(caps) {
xml = Common.XMLFromString(
DataStore.getPersistent('global', 'caps', caps)
);
}
// Any stored data?
if(xml) {
self.handle(xml);
Console.log('Read server CAPS from cache.');
} else {
// Not stored (or no CAPS)!
var iq = new JSJaCIQ();
iq.setTo(to);
iq.setType('get');
iq.setQuery(NS_DISCO_INFO);
con.send(iq, Caps.handleDiscoInfos);
Console.log('Read server CAPS from network.');
}
} catch(e) {
@ -93,7 +93,7 @@ var Features = (function () {
try {
// Selector
var selector = $(xml);
// Functions
var check_feature_fn = function(namespace) {
// This weird selector fixes an IE8 bug...
@ -103,7 +103,7 @@ var Features = (function () {
};
// Markers
var namespaces = [NS_PUBSUB, NS_PUBSUB_CN, NS_URN_MAM, NS_COMMANDS, NS_URN_CARBONS];
var namespaces = [NS_PUBSUB, NS_PUBSUB_CN, NS_URN_MAM, NS_COMMANDS, NS_URN_CARBONS, NS_URN_CORRECT];
var identity = selector.find('identity');
@ -137,21 +137,21 @@ var Features = (function () {
// Get the PEP nodes to initiate
Microblog.getInit();
PEP.getInitGeoloc();
// Get the notifications
Notification.get();
// Geolocate the user
PEP.geolocate();
// Enable microblogging send tools
Microblog.wait('sync');
$('.postit.attach').css('display', 'block');
Console.info('XMPP server supports PEP.');
} else {
Microblog.wait('unsync');
Console.warn('XMPP server does not support PEP.');
}
@ -159,10 +159,10 @@ var Features = (function () {
if(features.pep === false && features[NS_URN_MAM] === false) {
$('#options fieldset.privacy').hide();
}
// Apply the features
self.apply('talk');
// Process the roster height
if(features.pep === true) {
Roster.adapt();
@ -192,12 +192,12 @@ var Features = (function () {
try {
// Path to the elements
var path = '#' + id + ' .';
// PEP features
if(self.enabledPEP()) {
$(path + 'pep-hidable').show();
}
// PubSub features
if(self.enabledPubSub()) {
$(path + 'pubsub-hidable').show();
@ -207,7 +207,7 @@ var Features = (function () {
if(self.enabledPubSubCN()) {
$(path + 'pubsub-hidable-cn').show();
}
// MAM features
if(self.enabledMAM()) {
$(path + 'mam-hidable').show();
@ -218,12 +218,17 @@ var Features = (function () {
if(self.enabledMAMPurge()) {
$(path + 'mam-purge-hidable').show();
}
// Message correction features
if(self.enabledCorrection()) {
$(path + 'correction-hidable').show();
}
// Commands features
if(self.enabledCommands()) {
$(path + 'commands-hidable').show();
}
// XMPP links (browser feature)
if(navigator.registerProtocolHandler) {
$(path + 'xmpplinks-hidable').show();
@ -385,6 +390,22 @@ var Features = (function () {
};
/**
* Returns the XMPP server correction support
* @public
* @return {boolean}
*/
self.enabledCorrection = function() {
try {
return self.isEnabled(NS_URN_CORRECT);
} catch(e) {
Console.error('Features.enabledCorrection', e);
}
};
/**
* Normalizes the XMPP server name
* @private

View file

@ -20,6 +20,300 @@ var Filter = (function () {
var self = {};
/* Constants */
self.message_regex = {
'commands': {
'me': /((^)|((.+)(>)))(\/me )([^<]+)/
},
'emotes': {
'angry': [
/(:-?@)($|\s|<)/gi,
'$2'
],
'bat': [
/(:-?\[)($|\s|<)/gi,
'$2'
],
'beer': [
/(\(B\))($|\s|<)/g,
'$2'
],
'biggrin': [
/((:-?D)|(XD))($|\s|<)/gi,
'$4'
],
'blush': [
/(:-?\$)($|\s|<)/gi,
'$2'
],
'boy': [
/(\(Z\))($|\s|<)/g,
'$2'
],
'brflower': [
/(\(W\))($|\s|<)/g,
'$2'
],
'brheart': [
/((&lt;\/3)|(\(U\)))($|\s|<)/g,
'$4'
],
'coffee': [
/(\(C\))($|\s|<)/g,
'$2'
],
'coolglasses': [
/((8-\))|(\(H\)))($|\s|<)/g,
'$4'
],
'cry': [
/(:'-?\()($|\s|<)/gi,
'$2'
],
'cuffs': [
/(\(%\))($|\s|<)/g,
'$2'
],
'devil': [
/(\]:-?&gt;)($|\s|<)/gi,
'$2'
],
'drink': [
/(\(D\))($|\s|<)/g,
'$2'
],
'flower': [
/(@}-&gt;--)($|\s|<)/gi,
'$2'
],
'frowning': [
/((:-?\/)|(:-?S))($|\s|<)/gi,
'$4'
],
'girl': [
/(\(X\))($|\s|<)/g,
'$2'
],
'heart': [
/((&lt;3)|(\(L\)))($|\s|<)/g,
'$4'
],
'hugleft': [
/(\(}\))($|\s|<)/g,
'$2'
],
'hugright': [
/(\({\))($|\s|<)/g,
'$2'
],
'kis': [
/(:-?{})($|\s|<)/gi,
'$2'
],
'lamp': [
/(\(I\))($|\s|<)/g,
'$2'
],
'lion': [
/(:-?3)($|\s|<)/gi,
'$2'
],
'mail': [
/(\(E\))($|\s|<)/g,
'$2'
],
'moon': [
/(\(S\))($|\s|<)/g,
'$2'
],
'music': [
/(\(8\))($|\s|<)/g,
'$2'
],
'oh': [
/((=-?O)|(:-?O))($|\s|<)/gi,
'$4'
],
'phone': [
/(\(T\))($|\s|<)/g,
'$2'
],
'photo': [
/(\(P\))($|\s|<)/g,
'$2'
],
'puke': [
/(:-?!)($|\s|<)/gi,
'$2'
],
'pussy': [
/(\(@\))($|\s|<)/g,
'$2'
],
'rainbow': [
/(\(R\))($|\s|<)/g,
'$2'
],
'smile': [
/(:-?\))($|\s|<)/gi,
'$2'
],
'star': [
/(\(\*\))($|\s|<)/g,
'$2'
],
'stare': [
/(:-?\|)($|\s|<)/gi,
'$2'
],
'thumbdown': [
/(\(N\))($|\s|<)/g,
'$2'
],
'thumbup': [
/(\(Y\))($|\s|<)/g,
'$2'
],
'tongue': [
/(:-?P)($|\s|<)/gi,
'$2'
],
'unhappy': [
/(:-?\()($|\s|<)/gi,
'$2'
],
'wink': [
/(;-?\))($|\s|<)/gi,
'$2'
]
},
'formatting': {
'bold': [
/(^|\s|>|\()((\*)([^<>'"\*]+)(\*))($|\s|<|\))/gi,
'$1<b>$2</b>$6'
],
'italic': [
/(^|\s|>|\()((\/)([^<>'"\/]+)(\/))($|\s|<|\))/gi,
'$1<em>$2</em>$6'
],
'underline': [
/(^|\s|>|\()((_)([^<>'"_]+)(_))($|\s|<|\))/gi,
'$1<span style="text-decoration: underline;">$2</span>$6'
]
}
};
self.xhtml_allow = {
'elements': [
'a',
'abbr',
'acronym',
'address',
'blockquote',
'body',
'br',
'cite',
'code',
'dd',
'dfn',
'div',
'dt',
'em',
'h1',
'h2',
'h3',
'h4',
'h5',
'h6',
'head',
'html',
'kbd',
'li',
'ol',
'p',
'pre',
'q',
'samp',
'span',
'strong',
'title',
'ul',
'var'
],
'attributes': [
'accesskey',
'alt',
'charset',
'cite',
'class',
'height',
'href',
'hreflang',
'id',
'longdesc',
'profile',
'rel',
'rev',
'src',
'style',
'tabindex',
'title',
'type',
'uri',
'version',
'width',
'xml:lang',
'xmlns'
]
};
/**
* Generates a given emoticon HTML code
* @public
@ -42,83 +336,64 @@ var Filter = (function () {
/**
* Filters a given message
* @public
* @param {string} neutralMessage
* @param {string} message
* @param {string} nick
* @param {string} html_escape
* @return {string}
*/
self.message = function(neutralMessage, nick, html_escape) {
self.message = function(message, nick, html_escape) {
try {
var filteredMessage = neutralMessage;
var filtered = message;
// We encode the HTML special chars
if(html_escape)
filteredMessage = filteredMessage.htmlEnc();
// /me command
filteredMessage = filteredMessage.replace(/((^)|((.+)(>)))(\/me )([^<]+)/, nick + ' $7')
// We replace the smilies text into images
.replace(/(:-?@)($|\s|<)/gi, self.emoteImage('angry', '$1', '$2'))
.replace(/(:-?\[)($|\s|<)/gi, self.emoteImage('bat', '$1', '$2'))
.replace(/(\(B\))($|\s|<)/g, self.emoteImage('beer', '$1', '$2'))
.replace(/((:-?D)|(XD))($|\s|<)/gi, self.emoteImage('biggrin', '$1', '$4'))
.replace(/(:-?\$)($|\s|<)/gi, self.emoteImage('blush', '$1', '$2'))
.replace(/(\(Z\))($|\s|<)/g, self.emoteImage('boy', '$1', '$2'))
.replace(/(\(W\))($|\s|<)/g, self.emoteImage('brflower', '$1', '$2'))
.replace(/((&lt;\/3)|(\(U\)))($|\s|<)/g, self.emoteImage('brheart', '$1', '$4'))
.replace(/(\(C\))($|\s|<)/g, self.emoteImage('coffee', '$1', '$2'))
.replace(/((8-\))|(\(H\)))($|\s|<)/g, self.emoteImage('coolglasses', '$1', '$4'))
.replace(/(:'-?\()($|\s|<)/gi, self.emoteImage('cry', '$1', '$2'))
.replace(/(\(%\))($|\s|<)/g, self.emoteImage('cuffs', '$1', '$2'))
.replace(/(\]:-?&gt;)($|\s|<)/gi, self.emoteImage('devil', '$1', '$2'))
.replace(/(\(D\))($|\s|<)/g, self.emoteImage('drink', '$1', '$2'))
.replace(/(@}-&gt;--)($|\s|<)/gi, self.emoteImage('flower', '$1', '$2'))
.replace(/((:-?\/)|(:-?S))($|\s|<)/gi, self.emoteImage('frowning', '$1', '$4'))
.replace(/(\(X\))($|\s|<)/g, self.emoteImage('girl', '$1', '$2'))
.replace(/((&lt;3)|(\(L\)))($|\s|<)/g, self.emoteImage('heart', '$1', '$4'))
.replace(/(\(}\))($|\s|<)/g, self.emoteImage('hugleft', '$1', '$2'))
.replace(/(\({\))($|\s|<)/g, self.emoteImage('hugright', '$1', '$2'))
.replace(/(:-?{})($|\s|<)/gi, self.emoteImage('kiss', '$1', '$2'))
.replace(/(\(I\))($|\s|<)/g, self.emoteImage('lamp', '$1', '$2'))
.replace(/(:-?3)($|\s|<)/gi, self.emoteImage('lion', '$1', '$2'))
.replace(/(\(E\))($|\s|<)/g, self.emoteImage('mail', '$1', '$2'))
.replace(/(\(S\))($|\s|<)/g, self.emoteImage('moon', '$1', '$2'))
.replace(/(\(8\))($|\s|<)/g, self.emoteImage('music', '$1', '$2'))
.replace(/((=-?O)|(:-?O))($|\s|<)/gi, self.emoteImage('oh', '$1', '$4'))
.replace(/(\(T\))($|\s|<)/g, self.emoteImage('phone', '$1', '$2'))
.replace(/(\(P\))($|\s|<)/g, self.emoteImage('photo', '$1', '$2'))
.replace(/(:-?!)($|\s|<)/gi, self.emoteImage('puke', '$1', '$2'))
.replace(/(\(@\))($|\s|<)/g, self.emoteImage('pussy', '$1', '$2'))
.replace(/(\(R\))($|\s|<)/g, self.emoteImage('rainbow', '$1', '$2'))
.replace(/(:-?\))($|\s|<)/gi, self.emoteImage('smile', '$1', '$2'))
.replace(/(\(\*\))($|\s|<)/g, self.emoteImage('star', '$1', '$2'))
.replace(/(:-?\|)($|\s|<)/gi, self.emoteImage('stare', '$1', '$2'))
.replace(/(\(N\))($|\s|<)/g, self.emoteImage('thumbdown', '$1', '$2'))
.replace(/(\(Y\))($|\s|<)/g, self.emoteImage('thumbup', '$1', '$2'))
.replace(/(:-?P)($|\s|<)/gi, self.emoteImage('tongue', '$1', '$2'))
.replace(/(:-?\()($|\s|<)/gi, self.emoteImage('unhappy', '$1', '$2'))
.replace(/(;-?\))($|\s|<)/gi, self.emoteImage('wink', '$1', '$2'))
// Text in bold
.replace(/(^|\s|>|\()((\*)([^<>'"\*]+)(\*))($|\s|<|\))/gi, '$1<b>$2</b>$6')
// Italic text
.replace(/(^|\s|>|\()((\/)([^<>'"\/]+)(\/))($|\s|<|\))/gi, '$1<em>$2</em>$6')
// Underlined text
.replace(/(^|\s|>|\()((_)([^<>'"_]+)(_))($|\s|<|\))/gi, '$1<span style="text-decoration: underline;">$2</span>$6');
// Add the links
if(html_escape) {
filteredMessage = Links.apply(filteredMessage, 'desktop');
filtered = filtered.htmlEnc();
}
// Filter integratebox links
filteredMessage = IntegrateBox.filter(filteredMessage);
return filteredMessage;
// Security: don't filter huge messages (avoids crash attacks)
if(filtered.length < 10000) {
// /me command
filtered = filtered.replace(self.message_regex.commands.me, nick + ' $7');
// We replace the smilies text into images
var cur_emote;
for(var cur_emote_name in self.message_regex.emotes) {
cur_emote = self.message_regex.emotes[cur_emote_name];
filtered = filtered.replace(
cur_emote[0],
self.emoteImage(
cur_emote_name,
'$1',
cur_emote[1]
)
);
}
// Text formatting
var cur_formatting;
for(var cur_formatting_name in self.message_regex.formatting) {
cur_formatting = self.message_regex.formatting[cur_formatting_name];
filtered = filtered.replace(
cur_formatting[0],
cur_formatting[1]
);
}
// Add the links
if(html_escape) {
filtered = Links.apply(filtered, 'desktop');
}
// Filter integratebox links
filtered = IntegrateBox.filter(filtered);
}
return filtered;
} catch(e) {
Console.error('Filter.message', e);
}
@ -126,6 +401,32 @@ var Filter = (function () {
};
/**
* Returns whether XHTML body exists or not
* @public
* @param {DOM} xhtml_sel
* @return {boolean}
*/
self.has_xhtml_body = function(xhtml_sel) {
var has_xhtml_body = false;
try {
xhtml_sel.find('*').each(function() {
if($(this).text()) {
has_xhtml_body = true;
return false;
}
});
} catch(e) {
Console.error('Filter.has_xhtml_body', e);
} finally {
return has_xhtml_body;
}
};
/**
* Filters a xHTML message to be displayed in Jappix
* @public
@ -135,106 +436,46 @@ var Filter = (function () {
self.xhtml = function(code) {
try {
// 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',
'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'
);
var code_sel = $(code);
// Check if Filter for XHTML-IM images is enabled
if(DataStore.getDB(Connection.desktop_hash, 'options', 'no-xhtml-images') != '1') {
elements.push("img");
self.xhtml_allow.elements.push("img");
}
// Remove forbidden elements
$(code).find('html body *').each(function() {
code_sel.find('html body *').each(function() {
// This element is not authorized
if(!Utils.existArrayValue(elements, (this).nodeName.toLowerCase()))
if(!Utils.existArrayValue(self.xhtml_allow.elements, (this).nodeName.toLowerCase())) {
$(this).remove();
}
});
// Remove forbidden attributes
$(code).find('html body *').each(function() {
code_sel.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(!Utils.existArrayValue(attributes, cName.toLowerCase()) || ((cVal.toLowerCase()).match(/(^|"|')javascript:/)))
if(!Utils.existArrayValue(self.xhtml_allow.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();
code_sel.find('a').attr('target', '_blank');
return code_sel.find('html body').html();
} catch(e) {
Console.error('Filter.xhtml', e);
}

View file

@ -21,7 +21,199 @@ var Groupchat = (function () {
/* Variables */
var JOIN_SUGGEST = [];
self.join_suggest = [];
/**
* Apply generate events
* @private
* @param {object} input_sel
* @param {string} hash
* @param {string} room
* @return {undefined}
*/
self._createEvents = function(input_sel, hash, room) {
try {
self._createEventsInput(input_sel, hash);
self._createEventsKey(input_sel, hash, room);
} catch(e) {
Console.error('Groupchat._createEvents', e);
}
};
/**
* Apply generate events (input)
* @private
* @param {object} input_sel
* @param {string} hash
* @return {undefined}
*/
self._createEventsInput = function(input_sel, hash) {
try {
// Focus event
input_sel.focus(function() {
// Clean notifications for this chat
Interface.chanCleanNotify(hash);
// Store focus on this chat!
Interface.chat_focus_hash = hash;
});
// Blur event
input_sel.blur(function() {
// Reset storage about focus on this chat!
if(Interface.chat_focus_hash == hash) {
Interface.chat_focus_hash = null;
}
// Reset autocompletion
Autocompletion.reset(hash);
});
} catch(e) {
Console.error('Groupchat._createEventsInput', e);
}
};
/**
* Apply generate events (key)
* @private
* @param {object} input_sel
* @param {string} hash
* @param {string} room
* @return {undefined}
*/
self._createEventsKey = function(input_sel, hash, room) {
try {
// Lock to the input
input_sel.keydown(function(e) {
// Enter key
if(e.keyCode == 13) {
// If shift key (without any others modifiers) was pressed, add a new line
if(e.shiftKey && !e.ctrlKey && !e.altKey && !e.metaKey) {
input_sel.val(input_sel.val() + '\n');
} else {
if(Correction.isIn(room) === true) {
var corrected_value = input_sel.val().trim();
if(corrected_value) {
// Send the corrected message
Correction.send(room, 'groupchat', corrected_value);
}
Correction.leave(room);
} else {
// Send the message
Message.send(hash, 'groupchat');
// Reset the composing database entry
DataStore.setDB(Connection.desktop_hash, 'chatstate', room, 'off');
}
}
return false;
}
// Remove chars (leave correction)
else if(e.keyCode == 8) {
// Leave correction mode? (another way, by flushing input value progressively)
if(Correction.isIn(room) === true && !input_sel.val()) {
Correction.leave(room);
}
}
// Tabulation key (without any modifiers)
else if(!e.shiftKey && !e.ctrlKey && !e.altKey && !e.metaKey && e.keyCode == 9) {
Autocompletion.create(hash);
return false;
}
// Reset the autocompleter
else {
Autocompletion.reset(hash);
}
});
input_sel.keyup(function(e) {
if(e.keyCode == 27) {
// Escape key
input_sel.val('');
// Leave correction mode? (simple escape way)
if(Correction.isIn(room) === true) {
Correction.leave(room);
}
} else {
Correction.detect(room, input_sel);
}
});
} catch(e) {
Console.error('Groupchat._createEventsKey', e);
}
};
/**
* Apply suggest check events
* @private
* @return {undefined}
*/
self._suggestCheckEvents = function() {
try {
// Click events
$('#suggest .content a.one').click(function() {
var this_sel = $(this);
// Add/remove the active class
this_sel.toggleClass('active');
// We require at least one room to be chosen
if(Common.exists('#suggest .content a.one.active')) {
$('#suggest a.next').removeClass('disabled');
} else {
$('#suggest a.next').addClass('disabled');
}
return false;
});
$('#suggest a.next').click(function() {
var this_sel = $(this);
// Disabled?
if(this_sel.hasClass('disabled')) {
return false;
}
// Store groupchats to join?
if(this_sel.is('.continue')) {
$('#suggest .content a.one.active').each(function() {
self.join_suggest.push(
$(this).attr('data-xid')
);
});
}
// Switch to talk UI
$('#suggest').remove();
Connection.triggerConnected();
return false;
});
} catch(e) {
Console.error('Groupchat._suggestCheckEvents', e);
}
};
/**
@ -37,17 +229,20 @@ var Groupchat = (function () {
try {
// We must be in the "login" mode
if(Utils.isAnonymous())
if(Utils.isAnonymous()) {
return;
}
// We check if the user is a room owner or administrator to give him privileges
if(affiliation == 'owner' || affiliation == 'admin')
if(affiliation == 'owner' || affiliation == 'admin') {
$('#' + id + ' .tools-mucadmin').show();
}
// We check if the room hasn't been yet created
if(statuscode == 201)
if(statuscode == 201) {
Board.openThisInfo(4);
}
// We add the click event
$('#' + id + ' .tools-mucadmin').click(function() {
MUCAdmin.open(xid, affiliation);
@ -72,33 +267,35 @@ var Groupchat = (function () {
try {
// 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(!Utils.isAnonymous())
if(!Utils.isAnonymous()) {
nickname = Name.getNick();
else
} else {
nickname = ANONYMOUS_NICK;
}
// If the nickname could not be retrieved, ask it
if(!nickname)
if(!nickname) {
self.generateMUCAsk('nickname', room, hash, nickname, password);
}
}
// Got our nickname?
if(nickname) {
// Get our general presence
var show = DataStore.getDB(Connection.desktop_hash, 'presence-show', 1);
var status = DataStore.getDB(Connection.desktop_hash, 'options', 'presence-status');
// Set my nick
$('#' + hash).attr('data-nick', escape(nickname));
// Send the appropriate presence
Presence.send(room + '/' + nickname, '', show, status, '', true, password, self.handleMUC);
}
@ -126,43 +323,50 @@ var Groupchat = (function () {
var room = Common.bareXID(from);
var nickname = Common.thisResource(from);
var hash = hex_md5(room);
var id = presence.getID();
// No ID: must fix M-Link bug
if(presence.getID() === null) {
presence.setID(1);
if(id === null) {
id = 1;
presence.setID(id);
}
Console.info('First MUC presence: ' + from);
// Catch the errors
if(!Errors.handle(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'));
var statuscode = parseInt(muc_user.find('status').attr('code'));
// Handle my presence
Presence.handle(presence);
// Configure the new room
if(affiliation == 'owner' || affiliation == 'admin') {
self._initialConfiguration(id, room);
}
// Check if I am a room owner
self.openAdmin(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()) {
self.generateMUCAsk('password', room, hash, nickname);
}
// There's a nickname conflict
else if($(xml).find('error[type="cancel"] conflict').size()) {
self.generateMUCAsk('nickname', room, hash);
@ -189,34 +393,34 @@ var Groupchat = (function () {
try {
// 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 = Common._e("Nickname");
break;
case 'password':
label_text = Common._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 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) {
// $.trim() fixes #304
@ -224,14 +428,14 @@ var Groupchat = (function () {
nickname = $.trim(value_input);
return self.getMUC(room, nickname, password);
}
if(type == 'password' && value_input) {
password = value_input;
return self.getMUC(room, nickname, password);
}
}
});
// Focus on the input
$(document).oneTime(10, function() {
$(path_to + ' input').focus();
@ -259,86 +463,37 @@ var Groupchat = (function () {
try {
Console.info('New groupchat: ' + room);
// Create the chat content
Chat.generate('groupchat', hash, room, chan);
// Create the chat switcher
Chat.generateSwitch('groupchat', hash, room, chan);
// The icons-hover functions
Tooltip.icons(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
Favorites.addThis(room, chan);
});
// Must show the add button?
if(!DataStore.existDB('favorites', room))
$('#' + hash + ' .tools-add').show();
// The event handlers
var inputDetect = $('#' + hash + ' .message-area');
// Focus event
inputDetect.focus(function() {
// Clean notifications for this chat
Interface.chanCleanNotify(hash);
// Store focus on this chat!
Interface.chat_focus_hash = hash;
});
// Blur event
inputDetect.blur(function() {
// Reset storage about focus on this chat!
if(Interface.chat_focus_hash == hash)
Interface.chat_focus_hash = null;
// Reset autocompletion
Autocompletion.reset(hash);
});
// Lock to the input
inputDetect.keydown(function(e) {
// Enter key
if(e.keyCode == 13) {
// If shift key (without any others modifiers) was pressed, add a new line
if(e.shiftKey && !e.ctrlKey && !e.altKey && !e.metaKey)
inputDetect.val(inputDetect.val() + '\n');
// Send the message
else {
Message.send(hash, 'groupchat');
// Reset the composing database entry
DataStore.setDB(Connection.desktop_hash, 'chatstate', room, 'off');
}
return false;
}
// Tabulation key (without any modifiers)
else if(!e.shiftKey && !e.ctrlKey && !e.altKey && !e.metaKey && e.keyCode == 9) {
Autocompletion.create(hash);
return false;
}
// Reset the autocompleter
else {
Autocompletion.reset(hash);
}
});
// Must show the add button?
if(!DataStore.existDB(Connection.desktop_hash, 'favorites', room)) {
$('#' + hash + ' .tools-add').show();
}
// The event handlers
var input_sel = $('#' + hash + ' .message-area');
self._createEvents(input_sel, hash, room);
// Chatstate events
ChatState.events(inputDetect, room, hash, 'groupchat');
ChatState.events(input_sel, room, hash, 'groupchat');
// Get the current muc informations and content
self.getMUC(room, nickname, password);
} catch(e) {
@ -359,27 +514,30 @@ var Groupchat = (function () {
// Values array
var muc_arr = [GROUPCHATS_JOIN];
var new_arr = [];
// Try to split it
if(GROUPCHATS_JOIN.indexOf(',') != -1)
if(GROUPCHATS_JOIN.indexOf(',') != -1) {
muc_arr = GROUPCHATS_JOIN.split(',');
}
for(var i in muc_arr) {
// Get the current value
var muc_current = $.trim(muc_arr[i]);
// No current value?
if(!muc_current)
if(!muc_current) {
continue;
}
// Filter the current value
muc_current = Common.generateXID(muc_current, 'groupchat');
// Add the current value
if(!Utils.existArrayValue(new_arr, muc_current))
if(!Utils.existArrayValue(new_arr, muc_current)) {
new_arr.push(muc_current);
}
}
return new_arr;
} catch(e) {
Console.error('Groupchat.arrayJoin', e);
@ -397,13 +555,14 @@ var Groupchat = (function () {
try {
// Nothing to join?
if(!JOIN_SUGGEST)
if(!self.join_suggest) {
return;
}
// Join the chats
if(JOIN_SUGGEST.length) {
for(var g in JOIN_SUGGEST) {
Chat.checkCreate(JOIN_SUGGEST[g], 'groupchat');
if(self.join_suggest.length) {
for(var g in self.join_suggest) {
Chat.checkCreate(self.join_suggest[g], 'groupchat');
}
}
} catch(e) {
@ -422,16 +581,17 @@ var Groupchat = (function () {
try {
var groupchat_arr = self.arrayJoin();
// Must suggest the user?
if((GROUPCHATS_SUGGEST == 'on') && groupchat_arr.length) {
if(Common.exists('#suggest'))
if(Common.exists('#suggest')) {
return;
}
// Create HTML code
var html = '<div id="suggest" class="removable">';
html += '<div class="title">' + Common._e("Suggested chatrooms") + '</div>';
html += '<div class="content">';
for(var g in groupchat_arr) {
html += '<a class="one" href="#" data-xid="' + Common.encodeQuotes(groupchat_arr[g]) + '">';
@ -442,52 +602,21 @@ var Groupchat = (function () {
html += '</a>';
}
html += '</div>';
html += '<div class="bottom">';
html += '<a class="next continue disabled" href="#">' + Common._e("Continue") + '</a>';
html += '<a class="next skip" href="#">' + Common._e("Skip") + '</a>';
html += '</div>';
html += '</div>';
// Append HTML code
$('body').append(html);
// Click events
$('#suggest .content a.one').click(function() {
// Add/remove the active class
$(this).toggleClass('active');
// We require at least one room to be chosen
if(Common.exists('#suggest .content a.one.active'))
$('#suggest a.next').removeClass('disabled');
else
$('#suggest a.next').addClass('disabled');
return false;
});
$('#suggest a.next').click(function() {
// Disabled?
if($(this).hasClass('disabled')) {
return false;
}
// Store groupchats to join?
if($(this).is('.continue')) {
$('#suggest .content a.one.active').each(function() {
JOIN_SUGGEST.push($(this).attr('data-xid'));
});
}
// Switch to talk UI
$('#suggest').remove();
Connection.triggerConnected();
return false;
});
// Attach events
self._suggestCheckEvents();
} else {
JOIN_SUGGEST = groupchat_arr;
self.join_suggest = groupchat_arr;
Connection.triggerConnected();
}
} catch(e) {
@ -512,20 +641,26 @@ var Groupchat = (function () {
if(!ban_xid) {
Board.openThisInfo(6);
Console.warning('Could not ban user with XID: ' + ban_xid + ' from room: ' + room_xid);
Console.warn('Could not ban user with XID: ' + ban_xid + ' from room: ' + room_xid);
} else {
// We generate the ban IQ
var iq = new JSJaCIQ();
iq.setTo(room_xid);
iq.setType('set');
var iqQuery = iq.setQuery(NS_MUC_ADMIN);
var item = iqQuery.appendChild(iq.buildNode('item', {'affiliation': 'outcast', 'jid': ban_xid, 'xmlns': NS_MUC_ADMIN}));
var item = iqQuery.appendChild(iq.buildNode('item', {
'affiliation': 'outcast',
'jid': ban_xid,
'xmlns': NS_MUC_ADMIN
}));
if(reason) {
item.appendChild(iq.buildNode('reason', {'xmlns': NS_MUC_ADMIN}, reason));
item.appendChild(iq.buildNode('reason', {
'xmlns': NS_MUC_ADMIN
}, reason));
}
con.send(iq, Errors.handleReply);
Console.log('Banned user with XID: ' + ban_xid + ' from room: ' + room_xid);
@ -559,14 +694,20 @@ var Groupchat = (function () {
var iq = new JSJaCIQ();
iq.setTo(room_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}));
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));
item.appendChild(iq.buildNode('reason', {
'xmlns': NS_MUC_ADMIN
}, reason));
}
con.send(iq, Errors.handleReply);
Console.info('Kicked user "' + nick + '" from room: ' + room_xid);
@ -671,10 +812,54 @@ var Groupchat = (function () {
};
/**
* Sends initial configuration of the room
* @private
* @param {string} pid
* @param {string} xid
* @return {undefined}
*/
self._initialConfiguration = function(pid, xid) {
try {
var iq = new JSJaCIQ();
iq.setTo(xid);
iq.setType('set');
iq.setID('first-muc-config-' + pid);
var iqQuery = iq.setQuery(NS_MUC_OWNER);
// Configure room with nil(null) fields
var iqX = iqQuery.appendChild(iq.buildNode('x', {
'xmlns': NS_XDATA,
'type': 'submit'
}));
// Build a new field node
var iqField = iqX.appendChild(iq.buildNode('field', {
'var': 'FORM_TYPE',
'type': 'hidden',
'xmlns': NS_XDATA
}));
iqField.appendChild(iq.buildNode('value', {
'xmlns': NS_XDATA
}, NS_MUC_CONFIG));
con.send(iq);
Console.info('Groupchat._initialConfiguration', 'Sent initial room configuration: ' + xid);
} catch(e) {
Console.error('Groupchat._initialConfiguration', e);
}
};
/**
* Return class scope
*/
return self;
})();
})();

View file

@ -20,6 +20,119 @@ var Home = (function () {
var self = {};
/**
* Apply change events
* @private
* @param {object} current_sel
* @param {string} div
* @return {undefined}
*/
self._eventsChange = function(current_sel, div) {
try {
// Create the attached events
switch(div) {
// Login tool
case 'loginer':
current_sel.find('a.to-anonymous').click(function() {
return self.change('anonymouser');
});
current_sel.find('a.advanced').click(self.showAdvanced);
current_sel.find('form').submit(self.loginForm);
break;
// Anonymous login tool
case 'anonymouser':
current_sel.find('a.to-home').click(function() {
return self.change('loginer');
});
current_sel.find('form').submit(Connection.doAnonymous);
// Keyup event on anonymous join's room input
current_sel.find('input.room').keyup(function() {
var value = $(this).val();
var report_sel = current_sel.find('.report');
var span_sel = current_sel.find('span');
if(!value) {
report_sel.hide();
span_sel.text('');
} else {
report_sel.show();
span_sel.text(JAPPIX_LOCATION + '?r=' + value);
}
});
break;
// Register tool
case 'registerer':
// Server input change
$('#home input.server').keyup(function(e) {
if($.trim($(this).val()) == HOST_MAIN) {
$('#home .captcha_grp').show();
$('#home input.captcha').removeAttr('disabled');
} else {
$('#home .captcha_grp').hide();
$('#home input.captcha').attr('disabled', true);
}
});
// Register input placeholder
// FIXME: breaks IE compatibility
//$('#home input[placeholder]').placeholder();
// Register form submit
current_sel.find('form').submit(self.registerForm);
break;
}
} catch(e) {
Console.error('Home._eventsChange', e);
}
};
/**
* Create obsolete form
* @private
* @param {string} home
* @param {string} locale
* @return {undefined}
*/
self._obsolete = function(home, locale) {
try {
// Add the code
$(locale).after(
'<div class="obsolete">' +
'<p>' + Common._e("Your browser is out of date!") + '</p>' +
'<a class="firefox browsers-images" title="' + Common.printf(Common._e("Last %s version is better!"), 'Mozilla Firefox') + '" href="http://www.mozilla.com/firefox/"></a>' +
'<a class="chrome browsers-images" title="' + Common.printf(Common._e("Last %s version is better!"), 'Google Chrome') + '" href="http://www.google.com/chrome"></a>' +
'<a class="safari browsers-images" title="' + Common.printf(Common._e("Last %s version is better!"), 'Safari') + '" href="http://www.apple.com/safari/"></a>' +
'<a class="opera browsers-images" title="' + Common.printf(Common._e("Last %s version is better!"), 'Opera') + '" href="http://www.opera.com/"></a>' +
'<a class="ie browsers-images" title="' + Common.printf(Common._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();
});
Console.warn('Jappix does not support this browser!');
} catch(e) {
Console.error('Home._obsolete', e);
}
};
/**
* Allows the user to switch the difference home page elements
* @public
@ -33,19 +146,19 @@ var Home = (function () {
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':
@ -54,196 +167,144 @@ var Home = (function () {
if(!Common.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">' + Common._e("Previous") + '</a></h1>');
// Click event on previous link
$(home + 'top.sub a.previous').click(function() {
return self.change('default');
});
}
break;
}
// Apply the form
switch(div) {
// Login tool
case 'loginer':
lock_host = Utils.disableInput(LOCK_HOST, 'on');
code = '<p>' + Common.printf(Common._e("Login to your existing XMPP account. You can also use the %s to join a groupchat."), '<a href="#" class="to-anonymous">' + Common._e("anonymous mode") + '</a>') + '</p>' +
'<form action="#" method="post">' +
'<fieldset>' +
'<legend>' + Common._e("Required") + '</legend>' +
'<label for="lnick">' + Common._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">' + Common._e("Password") + '</label>' +
'<input type="password" class="password" id="lpassword" required="" />' +
'<label for="lremember">' + Common._e("Remember me") + '</label>' +
'<input type="checkbox" class="remember" id="lremember" />' +
'</fieldset>' +
'<a href="#" class="advanced home-images">' + Common._e("Advanced") + '</a>' +
'<fieldset class="advanced">' +
'<legend>' + Common._e("Advanced") + '</legend>' +
'<label for="lresource">' + Common._e("Resource") + '</label>' +
'<input type="text" class="resource" id="lresource" value="' + JAPPIX_RESOURCE + '" />' +
'<label for="lpriority">' + Common._e("Priority") + '</label>' +
'<select class="priority" id="lpriority">' +
'<option value="1">' + Common._e("Low") + '</option>' +
'<option value="10" selected="">' + Common._e("Medium") + '</option>' +
'<option value="100">' + Common._e("High") + '</option>' +
'</select>' +
'</fieldset>' +
'<div class="submit">' +
'<input type="submit" value="' + Common._e("Here we go!") + '" />' +
code = '<p>' + Common.printf(Common._e("Login to your existing XMPP account. You can also use the %s to join a groupchat."), '<a href="#" class="to-anonymous">' + Common._e("anonymous mode") + '</a>') + '</p>' +
'<div class="clear"></div>' +
'</div>' +
'<form action="#" method="post">' +
'<fieldset>' +
'<legend>' + Common._e("Required") + '</legend>' +
'<label for="lnick">' + Common._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="" list="server" />' +
'<label for="lpassword">' + Common._e("Password") + '</label>' +
'<input type="password" class="password" id="lpassword" required="" />' +
'<label for="lremember">' + Common._e("Remember me") + '</label>' +
'<input type="checkbox" class="remember" id="lremember" />' +
'</fieldset>' +
'<a href="#" class="advanced home-images">' + Common._e("Advanced") + '</a>' +
'<fieldset class="advanced">' +
'<legend>' + Common._e("Advanced") + '</legend>' +
'<label for="lresource">' + Common._e("Resource") + '</label>' +
'<input type="text" class="resource" id="lresource" value="' + JAPPIX_RESOURCE + '" />' +
'<label for="lpriority">' + Common._e("Priority") + '</label>' +
'<select class="priority" id="lpriority">' +
'<option value="1">' + Common._e("Low") + '</option>' +
'<option value="10" selected="">' + Common._e("Medium") + '</option>' +
'<option value="100">' + Common._e("High") + '</option>' +
'</select>' +
'</fieldset>' +
'<div class="submit">' +
'<input type="submit" value="' + Common._e("Here we go!") + '" />' +
'<div class="clear"></div>' +
'</div>' +
'</form>';
break;
// Anonymous login tool
case 'anonymouser':
disable_form = Utils.disableInput(ANONYMOUS, 'off');
code = '<p>' + Common.printf(Common._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">' + Common._e("login page") + '</a>') + '</p>';
if(LEGAL)
if(LEGAL) {
code += '<p>' + Common.printf(Common._e("By using our service, you accept %s."), '<b><a href="' + Common.encodeQuotes(LEGAL) + '" target="_blank">' + Common._e("our terms of use") + '</a></b>') + '</p>';
code += '<form action="#" method="post">' +
'<fieldset>' +
'<legend>' + Common._e("Required") + '</legend>' +
'<label>' + Common._e("Room") + '</label>' +
'<input type="text" class="room"' + disable_form + ' pattern="[^/]+" required="" />' +
'<label>' + Common._e("Nickname") + '</label>' +
'<input type="text" class="nick"' + disable_form + ' required="" />' +
'</fieldset>' +
'<input type="submit" value="' + Common._e("Here we go!") + '"' + disable_form + ' />' +
'</form>' +
'<div class="info report">' +
Common._e("Share this link with your friends:") + ' <span></span>' +
}
code += '<form action="#" method="post">' +
'<fieldset>' +
'<legend>' + Common._e("Required") + '</legend>' +
'<label>' + Common._e("Room") + '</label>' +
'<input type="text" class="room"' + disable_form + ' pattern="[^/]+" required="" />' +
'<label>' + Common._e("Nickname") + '</label>' +
'<input type="text" class="nick"' + disable_form + ' required="" />' +
'</fieldset>' +
'<input type="submit" value="' + Common._e("Here we go!") + '"' + disable_form + ' />' +
'</form>' +
'<div class="info report">' +
Common._e("Share this link with your friends:") + ' <span></span>' +
'</div>';
break;
// Register tool
case 'registerer':
disable_form = Utils.disableInput(REGISTRATION, 'off');
if(!disable_form)
if(!disable_form) {
lock_host = Utils.disableInput(LOCK_HOST, 'on');
}
code = '<p>' + Common._e("Register a new XMPP account to join your friends on your own social cloud. That's simple!") + '</p>';
if(LEGAL)
if(LEGAL) {
code += '<p>' + Common.printf(Common._e("By using our service, you accept %s."), '<b><a href="' + Common.encodeQuotes(LEGAL) + '" target="_blank">' + Common._e("our terms of use") + '</a></b>') + '</p>';
code += '<form action="#" method="post">' +
'<fieldset>' +
'<legend>' + Common._e("Required") + '</legend>' +
'<label for="rnick">' + Common._e("Address") + '</label>' +
'<input type="text" class="nick" id="rnick" ' + disable_form + ' pattern="[^@/]+" required="" placeholder="' + Common._e("Username") + '" /><span class="jid">@</span><input type="text" class="server" id="rserver" value="' + HOST_MAIN + '" ' + disable_form + lock_host + ' pattern="[^@/]+" required="" placeholder="' + Common._e("Server") + '" />' +
'<label for="rpassword">' + Common._e("Password") + '</label>' +
}
code += '<form action="#" method="post">' +
'<fieldset>' +
'<legend>' + Common._e("Required") + '</legend>' +
'<label for="rnick">' + Common._e("Address") + '</label>' +
'<input type="text" class="nick" id="rnick" ' + disable_form + ' pattern="[^@/]+" required="" placeholder="' + Common._e("Username") + '" /><span class="jid">@</span><input type="text" class="server" id="rserver" value="' + HOST_MAIN + '" ' + disable_form + lock_host + ' pattern="[^@/]+" required="" list="server" placeholder="' + Common._e("Server") + '" />' +
'<label for="rpassword">' + Common._e("Password") + '</label>' +
'<input type="password" class="password" id="rpassword" ' + disable_form + ' required="" placeholder="' + Common._e("Enter password") + '" /><input type="password" class="spassword" id="spassword" ' + disable_form + ' required="" placeholder="' + Common._e("Once again...") + '" />';
if(REGISTER_API == 'on')
code += '<div class="captcha_grp">' +
'<label for="captcha">' + Common._e("Code") + '</label><input type="text" class="captcha" id="captcha" ' + disable_form + ' maxlength="6" pattern="[a-zA-Z0-9]{6}" required="" placeholder="' + Common._e("Security code") + '" /><img class="captcha_img" src="./server/captcha.php?id=' + genID() + '" alt="" />' +
if(REGISTER_API == 'on') {
code += '<div class="captcha_grp">' +
'<label for="captcha">' + Common._e("Code") + '</label><input type="text" class="captcha" id="captcha" ' + disable_form + ' maxlength="6" pattern="[a-zA-Z0-9]{6}" required="" placeholder="' + Common._e("Security code") + '" /><img class="captcha_img" src="./server/captcha.php?id=' + genID() + '" alt="" />' +
'</div>';
code += '</fieldset>' +
'<input type="submit" value="' + Common._e("Here we go!") + '" ' + disable_form + '/>' +
}
code += '</fieldset>' +
'<input type="submit" value="' + Common._e("Here we go!") + '" ' + disable_form + '/>' +
'</form>';
break;
}
// Form disabled?
if(disable_form)
code += '<div class="info fail">' +
Common._e("This tool has been disabled!") +
if(disable_form) {
code += '<div class="info fail">' +
Common._e("This tool has been disabled!") +
'</div>';
}
// Create this HTML code
if(code && !Common.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 self.change('anonymouser');
});
$(current + ' a.advanced').click(self.showAdvanced);
$(current + ' form').submit(self.loginForm);
break;
// Anonymous login tool
case 'anonymouser':
$(current + ' a.to-home').click(function() {
return self.change('loginer');
});
$(current + ' form').submit(Connection.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':
// Server input change
$('#home input.server').keyup(function(e) {
if($.trim($(this).val()) == HOST_MAIN) {
$('#home .captcha_grp').show();
$('#home input.captcha').removeAttr('disabled');
} else {
$('#home .captcha_grp').hide();
$('#home input.captcha').attr('disabled', true);
}
});
// Register input placeholder
// FIXME: breaks IE compatibility
//$('#home input[placeholder]').placeholder();
// Register form submit
$(current + ' form').submit(self.registerForm);
break;
}
$(right + '.homediv.default').after(
'<div class="' + div + ' homediv">' + code + '</div>'
);
self._eventsChange(
$(current),
div
);
}
// We focus on the first input
$(document).oneTime(10, function() {
$(right + 'input:visible:first').focus();
@ -267,7 +328,7 @@ var Home = (function () {
try {
// Hide the link
$('#home a.advanced').hide();
// Show the fieldset
$('#home fieldset.advanced').show();
} catch(e) {
@ -288,27 +349,29 @@ var Home = (function () {
try {
// We get the values
var lPath = '#home .loginer ';
var lServer = $(lPath + '.server').val();
var lNick = Common.nodeprep($(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();
var path_sel = $('#home .loginer');
var lServer = path_sel.find('.server').val();
var lNick = Common.nodeprep(path_sel.find('.nick').val());
var lPass = path_sel.find('.password').val();
var lResource = path_sel.find('.resource').val();
var lPriority = path_sel.find('.priority').val();
var lRemember = path_sel.find('.remember').filter(':checked').size();
// Enough values?
if(lServer && lNick && lPass && lResource && lPriority) {
Connection.doLogin(lNick, lServer, lPass, lResource, lPriority, lRemember);
} else {
$(lPath + 'input[type="text"], ' + lPath + 'input[type="password"]').each(function() {
var select = $(this);
if(!select.val())
if(!select.val()) {
$(document).oneTime(10, function() {
select.addClass('please-complete').focus();
});
else
select.removeClass('please-complete');
} else {
select.removeClass('please-complete');
}
});
}
} catch(e) {
@ -328,38 +391,40 @@ var Home = (function () {
self.registerForm = function() {
try {
var rPath = '#home .registerer ';
var path = '#home .registerer';
var path_sel = $(path);
// Remove the success info
$(rPath + '.success').remove();
path_sel.find('.success').remove();
// Get the values
var username = Common.nodeprep($(rPath + '.nick').val());
var domain = $(rPath + '.server').val();
var pass = $(rPath + '.password').val();
var spass = $(rPath + '.spassword').val();
var captcha = $(rPath + '.captcha').val();
var username = Common.nodeprep(path_sel.find('.nick').val());
var domain = path_sel.find('.server').val();
var pass = path_sel.find('.password').val();
var spass = path_sel.find('.spassword').val();
var captcha = path_sel.find('.captcha').val();
// Enough values?
if(domain && username && pass && spass && (pass == spass) && !((REGISTER_API == 'on') && (domain == HOST_MAIN) && !captcha)) {
// We remove the not completed class to avoid problems
$('#home .registerer input').removeClass('please-complete');
// Fire the register event!
Connection.doRegister(username, domain, pass, captcha);
}
// Something is missing?
else {
$(rPath + 'input[type="text"], ' + rPath + 'input[type="password"]').each(function() {
$(path + ' input[type="text"], ' + path + ' input[type="password"]').each(function() {
var select = $(this);
if(!select.val() || (select.is('#spassword') && pass && (pass != spass)))
if(!select.val() || (select.is('#spassword') && pass && (pass != spass))) {
$(document).oneTime(10, function() {
select.addClass('please-complete').focus();
});
else
select.removeClass('please-complete');
} else {
select.removeClass('please-complete');
}
});
}
} catch(e) {
@ -387,76 +452,61 @@ var Home = (function () {
var corp = home + '.corporation';
var aboutus = home + '.aboutus';
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'))
if($(this).is('.login')) {
return self.change('loginer');
}
// Register button
else
else {
return self.change('registerer');
}
});
// Allows the user to view the corporation & about infobox
$(corp + ', ' + aboutus).hover(function() {
$(this).addClass('hovered');
}, function() {
$(this).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(var 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) && !System.isDeveloper())
if((e.keyCode == 27) && !System.isDeveloper()) {
return false;
}
});
// Warns for an obsolete browser
if(Utils.isObsolete()) {
// Add the code
$(locale).after(
'<div class="obsolete">' +
'<p>' + Common._e("Your browser is out of date!") + '</p>' +
'<a class="firefox browsers-images" title="' + Common.printf(Common._e("Last %s version is better!"), 'Mozilla Firefox') + '" href="http://www.mozilla.com/firefox/"></a>' +
'<a class="chrome browsers-images" title="' + Common.printf(Common._e("Last %s version is better!"), 'Google Chrome') + '" href="http://www.google.com/chrome"></a>' +
'<a class="safari browsers-images" title="' + Common.printf(Common._e("Last %s version is better!"), 'Safari') + '" href="http://www.apple.com/safari/"></a>' +
'<a class="opera browsers-images" title="' + Common.printf(Common._e("Last %s version is better!"), 'Opera') + '" href="http://www.opera.com/"></a>' +
'<a class="ie browsers-images" title="' + Common.printf(Common._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();
});
Console.warn('Jappix does not support this browser!');
self._obsolete();
}
Console.log('Welcome to Jappix! Happy coding in developer mode!');
});
} catch(e) {
@ -473,4 +523,4 @@ var Home = (function () {
})();
Home.launch();
Home.launch();

View file

@ -34,8 +34,6 @@ var HTTPAuth = (function () {
try {
// We add the login wait div
Interface.showGeneralWait();
oArgs = {};
if(Common.hasWebSocket()) {
// WebSocket supported & configured
@ -47,60 +45,58 @@ var HTTPAuth = (function () {
// Check BOSH origin
BOSH_SAME_ORIGIN = Origin.isSame(httpbase);
// We create the new http-binding connection
con = new JSJaCHttpBindingConnection({
httpbase: httpbase
});
}
// And we handle everything that happen
Connection.setupCon(con);
// Generate a resource
var random_resource = DataStore.getDB(Connection.desktop_hash, 'session', 'resource');
if(!random_resource) {
random_resource = JAPPIX_RESOURCE + ' (' + (new Date()).getTime() + ')';
}
// Generate a priority
lPriority = lPriority ? lPriority : 10;
// We retrieve what the user typed in the login inputs
oArgs = {};
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)
DataStore.setDB(Connection.desktop_hash, '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>' + random_resource + '</resource><password>' + lPass.htmlEnc() + '</password><priority>' + (lPriority + '').htmlEnc() + '</priority></session>';
// Save the session parameters (for reconnect if network issue)
Connection.current_session = session_xml;
// We store the infos of the user into the data-base
DataStore.setDB(Connection.desktop_hash, 'priority', 1, 10);
// We connect !
con.connect(oArgs);
con.connect({
'domain': $.trim(lServer),
'username': $.trim(lNick),
'resource': random_resource,
'pass': lPass,
'secure': true,
'xmllang': XML_LANG
});
// Change the page title
Interface.title('wait');
Console.info('Jappix is connecting...');
} catch(e) {
Console.error('HTTPAuth.go', e);
// Reset Jappix
Talk.destroy();
// Open an unknown error
Board.openThisError(2);
} finally {

View file

@ -37,23 +37,31 @@ var HTTPReply = (function () {
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'});
aMsg.appendNode('error', {
'code': '401',
'type': 'auth'
});
}
// We set the confirm node
aMsg.appendNode('confirm', {'xmlns': xmlns, 'url': url, 'id': id, 'method': method});
aMsg.appendNode('confirm', {
'xmlns': xmlns,
'url': url,
'id': id,
'method': method
});
// We send the message
con.send(aMsg, Errors.handleReply);
Console.info('Replying HTTP auth request: ' + from);
} catch(e) {
Console.error('HTTPReply.go', e);

View file

@ -29,69 +29,69 @@ var Inbox = (function () {
try {
// Popup HTML content
var html =
'<div class="top">' + Common._e("Your inbox") + '</div>' +
'<div class="content">' +
'<div class="head inbox-head">' +
'<div class="head-text inbox-head-text">' + Common._e("Available actions") + '</div>' +
'<div class="head-actions inbox-head-actions">' +
'<a href="#" class="a-delete-messages">' + Common._e("Clean") + '</a>' +
'<a href="#" class="a-new-message">' + Common._e("New") + '</a>' +
'<a href="#" class="a-show-messages">' + Common._e("Received") + '</a>' +
'</div>' +
'</div>' +
'<div class="inbox-results">' +
'<p class="inbox-noresults">' + Common._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">' + Common._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">' + Common._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">' + Common._e("Content") + '</p>' +
'<textarea class="inbox-new-textarea" rows="8" cols="60" required=""></textarea>' +
'</div>' +
'<form class="inbox-new-file inbox-new-block" action="./server/file-share.php" method="post" enctype="multipart/form-data">' +
'<p class="inbox-new-text">' + Common._e("File") + '</p>' +
Interface.generateFileShare() +
'</form>' +
'<div class="inbox-new-send inbox-new-block">' +
'<a href="#" class="send one-button talk-images">' + Common._e("Send message") + '</a>' +
'</div>' +
'</div>' +
'</div>' +
'<div class="bottom">' +
'<div class="wait wait-medium"></div>' +
'<a href="#" class="finish">' + Common._e("Close") + '</a>' +
var html =
'<div class="top">' + Common._e("Your inbox") + '</div>' +
'<div class="content">' +
'<div class="head inbox-head">' +
'<div class="head-text inbox-head-text">' + Common._e("Available actions") + '</div>' +
'<div class="head-actions inbox-head-actions">' +
'<a href="#" class="a-delete-messages">' + Common._e("Clean") + '</a>' +
'<a href="#" class="a-new-message">' + Common._e("New") + '</a>' +
'<a href="#" class="a-show-messages">' + Common._e("Received") + '</a>' +
'</div>' +
'</div>' +
'<div class="inbox-results">' +
'<p class="inbox-noresults">' + Common._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">' + Common._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">' + Common._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">' + Common._e("Content") + '</p>' +
'<textarea class="inbox-new-textarea" rows="8" cols="60" required=""></textarea>' +
'</div>' +
'<form class="inbox-new-file inbox-new-block" action="./server/file-share.php" method="post" enctype="multipart/form-data">' +
'<p class="inbox-new-text">' + Common._e("File") + '</p>' +
Interface.generateFileShare() +
'</form>' +
'<div class="inbox-new-send inbox-new-block">' +
'<a href="#" class="send one-button talk-images">' + Common._e("Send message") + '</a>' +
'</div>' +
'</div>' +
'</div>' +
'<div class="bottom">' +
'<div class="wait wait-medium"></div>' +
'<a href="#" class="finish">' + Common._e("Close") + '</a>' +
'</div>';
// Create the popup
Popup.create('inbox', html);
// Associate the events
self.instance();
// Load the messages
self.load();
} catch(e) {
@ -134,10 +134,10 @@ var Inbox = (function () {
// Open things
self.open();
self.newMessage();
// Apply XID
$('#inbox .inbox-new-to-input').val(xid);
// Focus to the next item
$(document).oneTime(10, function() {
$('#inbox .inbox-new-subject-input').focus();
@ -163,33 +163,32 @@ var Inbox = (function () {
iq.setType('set');
var query = iq.setQuery(NS_PRIVATE);
var storage = query.appendChild(iq.buildNode('storage', {'xmlns': NS_INBOX}));
var db_regex = new RegExp(('^' + Connection.desktop_hash + '_') + 'inbox' + ('_(.+)'));
for(var i = 0; i < DataStore.storageDB.length; i++) {
// Get the pointer values
var current = DataStore.storageDB.key(i);
// If the pointer is on a stored message
if(current.match(db_regex)) {
// Get the values
var value = $(Common.XMLFromString(DataStore.storageDB.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()
));
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);
} catch(e) {
Console.error('Inbox.store', e);
@ -207,20 +206,20 @@ var Inbox = (function () {
try {
// Init
var mPath = '#inbox .';
var inbox_sel = $('#inbox');
// Reset the previous buddy search
Search.resetBuddy('#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();
inbox_sel.find('.inbox-results, .a-new-message, .a-delete-messages').hide();
inbox_sel.find('.inbox-new, .a-show-messages').show();
// We focus on the first input
$(document).oneTime(10, function() {
$(mPath + 'inbox-new-to-input').focus();
inbox_sel.find('.inbox-new-to-input').focus();
});
// We reset some stuffs
self.cleanNewMessage();
} catch(e) {
@ -230,7 +229,7 @@ var Inbox = (function () {
}
};
/**
* Cleans the inbox
@ -241,16 +240,16 @@ var Inbox = (function () {
try {
// Init
var mPath = '#inbox .';
var inbox_sel = $('#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();
inbox_sel.find('.inbox-new-block:not(form) input, .inbox-new textarea').val('').removeClass('please-complete');
inbox_sel.find('.inbox-new-file a').remove();
inbox_sel.find('.inbox-new-file input').show();
// We close an eventual opened message
$(mPath + 'message-content').remove();
$(mPath + 'one-message').removeClass('message-reading');
inbox_sel.find('.message-content').remove();
inbox_sel.find('.one-message').removeClass('message-reading');
} catch(e) {
Console.error('Inbox.cleanNewMessage', e);
}
@ -270,26 +269,26 @@ var Inbox = (function () {
try {
// We send the message
var mess = new JSJaCMessage();
var message = new JSJaCMessage();
// Main attributes
mess.setTo(to);
mess.setSubject(subject);
mess.setType('normal');
message.setTo(to);
message.setSubject(subject);
message.setType('normal');
// Any file to attach?
var attached = '#inbox .inbox-new-file a.file';
if(Common.exists(attached)) {
body += '\n' +
'\n' +
$(attached).attr('data-attachedtitle') + ' - ' + $(attached).attr('data-attachedhref');
body += '\n' +
'\n' +
$(attached).attr('data-attachedtitle') + ' - ' + $(attached).attr('data-attachedhref');
}
// Set body
mess.setBody(body);
con.send(mess, Errors.handleReply);
message.setBody(body);
con.send(message, Errors.handleReply);
} catch(e) {
Console.error('Inbox.sendMessage', e);
}
@ -306,54 +305,54 @@ var Inbox = (function () {
try {
// 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();
var inbox_sel = $('#inbox');
var to = inbox_sel.find('.inbox-new-to-input').val();
var body = inbox_sel.find('.inbox-new-textarea').val();
var subject = inbox_sel.find('.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(var 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 = Common.generateXID(current, 'chat');
// We send the message
self.sendMessage(current, subject, body);
// We clean the inputs
self.cleanNewMessage();
Console.info('Inbox message sent: ' + current);
}
// Close the inbox
self.close();
}
else {
$(mPath + 'input[type="text"], ' + mPath + 'textarea').each(function() {
var current = this;
if(!$(current).val()) {
inbox_sel.find('input[type="text"], textarea').each(function() {
var this_sel = $(this);
if(!this_sel.val()) {
$(document).oneTime(10, function() {
$(current).addClass('please-complete').focus();
this_sel.addClass('please-complete').focus();
});
} else {
$(current).removeClass('please-complete');
this_sel.removeClass('please-complete');
}
});
}
@ -374,18 +373,17 @@ var Inbox = (function () {
self.showMessage = function() {
try {
// Init
var mPath = '#inbox .';
var inbox_sel = $('#inbox');
// We switch the divs
$(mPath + 'inbox-new').hide();
$(mPath + 'inbox-results').show();
inbox_sel.find('.inbox-new').hide();
inbox_sel.find('.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();
inbox_sel.find('.a-show-messages').hide();
inbox_sel.find('.a-delete-messages').show();
inbox_sel.find('.a-new-message').show();
// We reset some stuffs
self.cleanNewMessage();
} catch(e) {
@ -414,50 +412,50 @@ var Inbox = (function () {
// Generate some paths
var inbox = '#inbox .';
var one_message = inbox + 'one-message.' + id;
// Message yet displayed!
if(Common.exists(one_message)) {
return false;
}
// Get the nearest element
var stamp = DateUtils.extractStamp(Date.jab2date(date));
var nearest = Search.sortElementByStamp(stamp, '#inbox .one-message');
// Get the buddy name
var name = Name.getBuddy(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="' + './images/others/default-avatar.png' + '" alt="" />' +
'</div>' +
'<div class="message-jid">' + name + '</div>' +
'<div class="message-subject">' + subject.htmlEnc() + '</div>' +
'<div class="message-truncated">' + Utils.truncate(Utils.noLines(content), 90).htmlEnc() + '</div>' +
'</div>' +
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="' + './images/others/default-avatar.png' + '" alt="" />' +
'</div>' +
'<div class="message-jid">' + name + '</div>' +
'<div class="message-subject">' + subject.htmlEnc() + '</div>' +
'<div class="message-truncated">' + Utils.truncate(Utils.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(!Common.exists(one_message + ' .message-content'))
self.revealMessage(id, from, subject, content, name, date, status);
else
self.hideMessage(id);
return false;
});
// Get the user avatar
Avatar.get(from, 'cache', 'true', 'forget');
@ -484,11 +482,15 @@ var Inbox = (function () {
try {
// 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>';
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>' +
'</message>';
// Store this message!
DataStore.setDB(Connection.desktop_hash, 'inbox', id, xml);
} catch(e) {
@ -504,18 +506,18 @@ var Inbox = (function () {
* @param {string} id
* @return {boolean}
*/
self.deleteMessage = function() {
self.deleteMessage = function(id) {
try {
// Remove the message from the inbox
$('#inbox .one-message.' + id).remove();
// Remove the message from the database
DataStore.removeDB(Connection.desktop_hash, 'inbox', id);
// Check the unread messages
self.checkMessages();
// Store the new inbox
self.store();
} catch(e) {
@ -541,21 +543,21 @@ var Inbox = (function () {
for(var i = 0; i < DataStore.storageDB.length; i++) {
// Get the pointer values
var current = DataStore.storageDB.key(i);
// If the pointer is on a stored message
if(current.match(db_regex)) {
DataStore.removeDB(Connection.desktop_hash, 'inbox', RegExp.$1);
}
}
// Prevent the database lag
$(document).oneTime(100, function() {
// Store the new inbox
self.store();
// Remove all the messages from the inbox
$('#inbox .one-message').remove();
// Reload the inbox
self.load();
});
@ -579,56 +581,56 @@ var Inbox = (function () {
// 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
var db_regex = new RegExp(('^' + Connection.desktop_hash + '_') + 'inbox' + ('_(.+)'));
for(var i = 0; i < DataStore.storageDB.length; i++) {
// Database pointer
var current = DataStore.storageDB.key(i);
// Check inbox messages
if(current.match(db_regex)) {
// Read the current status
var status = $(Common.XMLFromString(DataStore.storageDB.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
Interface.updateTitle();
return true;
}
// Anyway, update the title
Interface.updateTitle();
} catch(e) {
@ -659,53 +661,53 @@ var Inbox = (function () {
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">' + Filter.message(content, name, true) + '</div>' +
'<div class="message-meta">' +
'<span class="date">' + DateUtils.parse(date) + '</span>' +
'<a href="#" class="reply one-button talk-images">' + Common._e("Reply") + '</a>' +
'<a href="#" class="remove one-button talk-images">' + Common._e("Delete") + '</a>' +
'<div class="clear">' +
'</div>' +
var html =
'<div class="message-content">' +
'<div class="message-body">' + Filter.message(content, name, true) + '</div>' +
'<div class="message-meta">' +
'<span class="date">' + DateUtils.parse(date) + '</span>' +
'<a href="#" class="reply one-button talk-images">' + Common._e("Reply") + '</a>' +
'<a href="#" class="remove one-button talk-images">' + Common._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 self.replyMessage(id, from, subject, content);
});
$(one_content + ' a.remove').click(function() {
return self.deleteMessage(id);
});
// Unread message
if(status == 'unread') {
// Update our database
var xml = DataStore.getDB(Connection.desktop_hash, 'inbox', id).replace(/<status>unread<\/status>/i,'<status>read</status>');
DataStore.setDB(Connection.desktop_hash, 'inbox', id, xml);
// Remove the unread class
$(one_message).removeClass('message-unread');
// Send it to the server!
self.store();
}
// Check the unread messages
self.checkMessages();
} catch(e) {
@ -727,7 +729,7 @@ var Inbox = (function () {
// 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();
@ -749,17 +751,17 @@ var Inbox = (function () {
try {
// We switch to the writing div
self.newMessage();
// Inbox path
var inbox = '#inbox .';
// Generate the body
body = '\n' + '____________' + '\n\n' + Utils.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);
});
@ -786,24 +788,24 @@ var Inbox = (function () {
for(var i = 0; i < DataStore.storageDB.length; i++) {
// Get the pointer values
var current = DataStore.storageDB.key(i);
// If the pointer is on a stored message
if(current.match(db_regex)) {
// Get the current value
var value = $(Common.XMLFromString(DataStore.storageDB.getItem(current)));
// Display the current message
self.displayMessage(
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()
);
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
self.checkMessages();
} catch(e) {
@ -840,37 +842,51 @@ var Inbox = (function () {
try {
// Data selector
var dData = $(responseXML).find('jappix');
// Process the returned data
if(dData.find('error').size()) {
Board.openThisError(4);
Console.error('Error while attaching the file', dData.find('error').text());
} 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 ' + Common.encodeQuotes(Utils.fileCategory(Common.explodeThis('/', fType, 1))) + ' talk-images" href="' + Common.encodeQuotes(fURL) + '" target="_blank">' + fName.htmlEnc() + '</a><a href="#" class="remove one-button talk-images">' + Common._e("Remove") + '</a>');
$('#inbox .inbox-new-file').append(
'<a class="file ' + Common.encodeQuotes(Utils.fileCategory(Common.explodeThis('/', fType, 1))) + ' talk-images" ' +
'href="' + Common.encodeQuotes(fURL) + '" ' +
'target="_blank">' +
fName.htmlEnc() +
'</a>' +
'<a href="#" class="remove one-button talk-images">' +
Common._e("Remove") +
'</a>'
);
// Set values to the file link
$('#inbox .inbox-new-file a.file').attr('data-attachedtitle', fName)
.attr('data-attachedhref', fURL);
var inbox_file_sel = $('#inbox .inbox-new-file a.file');
inbox_file_sel.attr('data-attachedtitle', fName);
inbox_file_sel.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();
var inbox_new_file_sel = $('#inbox .inbox-new-file');
inbox_new_file_sel.find('a.remove').click(function() {
inbox_new_file_sel.find('a').remove();
inbox_new_file_sel.find('input').show();
return false;
});
Console.info('File attached.');
}
// Reset the attach bubble
$('#inbox .inbox-new-file input[type="file"]').val('');
$('#inbox .wait').hide();
@ -891,21 +907,22 @@ var Inbox = (function () {
try {
// 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(Common.exists(dHovered))
if(Common.exists(dHovered)) {
Search.addBuddy(destination, $(dHovered).attr('data-xid'));
else
} else {
self.checkMessage();
}
}
});
// Buddy search
$(inbox + 'inbox-new-to-input').keyup(function(e) {
if(e.keyCode != 13) {
@ -913,61 +930,61 @@ var Inbox = (function () {
if((e.keyCode != 40) && (e.keyCode != 38)) {
Search.createBuddy(destination);
}
// Navigating with keyboard in the results
Search.arrowsBuddy(e, destination);
}
})
// Buddy search lost focus
.blur(function() {
if(!$(destination + ' ul').attr('mouse-hover')) {
Search.resetBuddy(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(self.purge);
$(inbox + 'a-new-message').click(self.newMessage);
$(inbox + 'a-show-messages').click(self.showMessage);
$(inbox + 'inbox-new-send a').click(self.checkMessage);
$(inbox + 'bottom .finish').click(function() {
return self.close();
});
// File upload
var attach_options = {
dataType: 'xml',
dataType: 'xml',
beforeSubmit: self.waitAttach,
success: self.handleAttach
};
// 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;
});
} catch(e) {

View file

@ -29,22 +29,22 @@ var IntegrateBox = (function () {
try {
// Popup HTML content
var html =
'<div class="top">' + Common._e("Media viewer") + '</div>' +
'<div class="content"></div>' +
'<div class="bottom">' +
'<div class="wait wait-medium"></div>' +
'<a href="#" class="finish close">' + Common._e("Close") + '</a>' +
'<a href="#" class="finish next disabled" title="' + Common._e("Next") + '">&gt;</a>' +
'<a href="#" class="finish previous disabled" title="' + Common._e("Previous") + '">&lt;</a>' +
var html =
'<div class="top">' + Common._e("Media viewer") + '</div>' +
'<div class="content"></div>' +
'<div class="bottom">' +
'<div class="wait wait-medium"></div>' +
'<a href="#" class="finish close">' + Common._e("Close") + '</a>' +
'<a href="#" class="finish next disabled" title="' + Common._e("Next") + '">&gt;</a>' +
'<a href="#" class="finish previous disabled" title="' + Common._e("Previous") + '">&lt;</a>' +
'</div>';
// Create the popup
Popup.create('integratebox', html);
// Associate the events
self.instance();
} catch(e) {
@ -84,17 +84,17 @@ var IntegrateBox = (function () {
try {
var code = '';
// Protocol to use
var protocol = Utils.isHTTPS() ? 'https' : 'http';
// 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':
@ -103,37 +103,37 @@ var IntegrateBox = (function () {
} else {
code = '<object width="640" height="385" data="' + Common.encodeQuotes(protocol) + '://www.youtube.com/embed/' + Common.encodeQuotes(url) + '?autoplay=1" type="text/html"><a href="http://www.youtube.com/watch?v=' + Common.encodeQuotes(url) + '" target="_blank">http://www.youtube.com/watch?v=' + Common.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/' + Common.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=' + Common.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=' + Common.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="' + Common.encodeQuotes(url) + '" controls autoplay><a href="' + Common.encodeQuotes(url) + '" target="_blank">' + Common.encodeQuotes(url) + '</a></video>';
break;
case 'vorbis':
case 'audio':
code = '<audio src="' + Common.encodeQuotes(url) + '" controls autoplay><a href="' + Common.encodeQuotes(url) + '" target="_blank">' + Common.encodeQuotes(url) + '</a></audio>';
break;
case 'image':
code = '<a href="' + Common.encodeQuotes(url) + '" target="_blank"><img alt="" src="' + Common.encodeQuotes(url) + '" /></a>';
break;
}
return code;
} catch(e) {
Console.error('IntegrateBox.code', e);
@ -159,64 +159,65 @@ var IntegrateBox = (function () {
try {
// Close the integratebox
self.close();
// Media integration not wanted?
if(DataStore.getDB(Connection.desktop_hash, 'options', 'integratemedias') == '0')
if(DataStore.getDB(Connection.desktop_hash, 'options', 'integratemedias') == '0') {
return true;
}
// Apply the HTML code
var dom_code = self.code(service, url);
// Any code: apply it!
if(dom_code) {
// We show the integratebox
self.open();
// 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="' + Common.encodeQuotes(comments_id) + '">' +
'<div class="comments-content">' +
'<div class="one-comment loading"><span class="icon talk-images"></span>' + Common._e("Loading comments...") + '</div>' +
'</div>' +
'<div class="comments" data-id="' + Common.encodeQuotes(comments_id) + '">' +
'<div class="comments-content">' +
'<div class="one-comment loading"><span class="icon talk-images"></span>' + Common._e("Loading comments...") + '</div>' +
'</div>' +
'</div>'
);
}
// Previous and next items?
var url_array = Utils.stringToArray(url_list);
var services_array = Utils.stringToArray(services_list);
var comments_e_array = Utils.stringToArray(comments_e_list);
var comments_n_array = Utils.stringToArray(comments_n_list);
var index = Utils.indexArrayValue(url_array, url);
// Any comments?
if(Common.exists('#integratebox .comments')) {
if(comments_e_array[index] && comments_n_array[index]) {
@ -225,57 +226,57 @@ var IntegrateBox = (function () {
$('#integratebox .comments .comments-content').html('<div class="one-comment loading"><span class="icon talk-images"></span>' + Common._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')) {
self.apply(previous_url, previous_services, url_list, services_list, comments_e_list, comments_n_list, width_style);
} else {
self.apply(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) {
self.apply(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;
} catch(e) {
@ -320,90 +321,90 @@ var IntegrateBox = (function () {
try {
// 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.$6;
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 = 'XMPPLinks.go(\'' + Utils.encodeOnclick(to) + '\')';
} else if(url && service) {
event = 'IntegrateBox.apply(\'' + Utils.encodeOnclick(url) + '\', \'' + Utils.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 += ' ' + Common.encodeQuotes(current_attr.name) + '="' + Common.encodeQuotes(current_attr.value) + '"';
});
// Add onclick attribute
new_a += ' onclick="return ' + event + ';"';
// Value
new_a += '>' + $(this).html() + '</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;
} catch(e) {
Console.error('IntegrateBox.filter', e);
@ -441,14 +442,14 @@ var IntegrateBox = (function () {
// Previous item?
if((Common.exists('#integratebox .bottom .finish.previous:not(.disabled)')) && (e.keyCode == 37)) {
$('#integratebox .bottom .finish.previous').click();
return false;
}
// Next item?
if((Common.exists('#integratebox .bottom .finish.next:not(.disabled)')) && (e.keyCode == 39)) {
$('#integratebox .bottom .finish.next').click();
return false;
}
});

View file

@ -35,25 +35,25 @@ var Interface = (function () {
try {
// Anonymous mode?
var head_name = Name.get();
if(Utils.isAnonymous()) {
head_name = ANONYMOUS_ROOM + ' (' + Common._e("anonymous mode") + ')';
}
// We change the title to give essential informations
switch(title_type) {
case 'home':
document.title = SERVICE_NAME + ' • ' + SERVICE_DESC;
break;
case 'talk':
document.title = SERVICE_NAME + ' • ' + head_name;
break;
case 'new':
document.title = '[' + self.pendingEvents() + '] ' + SERVICE_NAME + ' • ' + head_name;
break;
case 'wait':
document.title = SERVICE_NAME + ' • ' + Common._e("Please wait...");
break;
@ -74,18 +74,19 @@ var Interface = (function () {
try {
// Item exists?
if(Common.exists('#general-wait'))
if(Common.exists('#general-wait')) {
return false;
}
// Generate the HTML code
var html =
'<div id="general-wait" class="removable">' +
'<div class="general-wait-content wait-big"></div>' +
var html =
'<div id="general-wait" class="removable">' +
'<div class="general-wait-content wait-big"></div>' +
'</div>';
// Append the HTML code
$('body').append(html);
return true;
} catch(e) {
Console.error('Interface.showGeneralWait', e);
@ -118,11 +119,11 @@ var Interface = (function () {
self.generateFileShare = function() {
try {
return '<input type="hidden" name="MAX_FILE_SIZE" value="' + Common.encodeQuotes(JAPPIX_MAX_FILE_SIZE) + '">' +
'<input type="hidden" name="user" value="' + Common.encodeQuotes(Common.getXID()) + '" />' +
'<input type="hidden" name="location" value="' + Common.encodeQuotes(Utils.generateURL(JAPPIX_LOCATION)) + '" />' +
'<input type="hidden" name="id" value="' + (new Date()).getTime() + '" />' +
'<input type="file" name="file" required="" />' +
return '<input type="hidden" name="MAX_FILE_SIZE" value="' + Common.encodeQuotes(JAPPIX_MAX_FILE_SIZE) + '">' +
'<input type="hidden" name="user" value="' + Common.encodeQuotes(Common.getXID()) + '" />' +
'<input type="hidden" name="location" value="' + Common.encodeQuotes(Utils.generateURL(JAPPIX_LOCATION)) + '" />' +
'<input type="hidden" name="id" value="' + (new Date()).getTime() + '" />' +
'<input type="file" name="file" required="" />' +
'<input type="submit" value="' + Common._e("Send") + '" />';
} catch(e) {
Console.error('Interface.generateFileShare', e);
@ -144,16 +145,16 @@ var Interface = (function () {
// We show the page-engine content
$('.page-engine-chan').hide();
$('#' + id).show();
// We edit the tab switcher
$('#page-switch .switcher').removeClass('activechan').addClass('chan');
$('#page-switch .' + id).addClass('activechan').removeClass('chan');
// Scroll down to the last message
if(id != 'channel') {
self.autoScroll(id);
}
// Manage input focus
self.inputFocus();
}
@ -176,18 +177,19 @@ var Interface = (function () {
try {
// Path
var more_content = '#page-switch .more-content';
// Yet displayed?
if(Common.exists(more_content))
if(Common.exists(more_content)) {
return Bubble.close();
}
// Add the bubble
Bubble.show(more_content);
// Append the content
$('#page-switch .more').append(
'<div class="more-content bubble removable">' +
$('#page-switch .chans').html() +
'<div class="more-content bubble removable">' +
$('#page-switch .chans').html() +
'</div>'
);
} catch(e) {
@ -210,18 +212,18 @@ var Interface = (function () {
// Path
var join_content = '#page-switch .join-content';
var join_sel = $('#page-switch .join');
// Yet displayed?
if(Common.exists(join_content))
return Bubble.close();
// Add the bubble
Bubble.show(join_content);
// Append the content
join_sel.append(
'<div class="join-content bubble removable">' +
'<input type="text" class="join-groupchat-xid" required="" placeholder="' + Common._e("Groupchat name") + '" />' +
'<div class="join-content bubble removable">' +
'<input type="text" class="join-groupchat-xid" required="" placeholder="' + Common._e("Groupchat name") + '" />' +
'</div>'
);
@ -232,11 +234,11 @@ var Interface = (function () {
if(e.keyCode == 13) {
var this_sel = $(this);
var xid = $.trim(this_sel.val());
if(xid) {
// Generate a correct XID
xid = Common.generateXID(xid, 'groupchat');
Bubble.close();
Chat.checkCreate(xid, 'groupchat');
} else {
@ -272,14 +274,14 @@ var Interface = (function () {
// 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();
@ -322,7 +324,7 @@ var Interface = (function () {
if(type == 'groupchat') {
// Send our unavailable presence
Presence.send(xid + '/' + Name.getMUCNick(hash), 'unavailable');
// Remove all presence database entries for this groupchat
var db_regex = new RegExp(('^' + Connection.desktop_hash + '_') + 'presence' + ('_(.+)'));
@ -332,15 +334,15 @@ var Interface = (function () {
if(current.match(db_regex)) {
var cXID = RegExp.$1;
// If the pointer is on a presence from this groupchat
if(Common.bareXID(cXID) == xid) {
// Generate the hash for the current XID
var cHash = hex_md5(cXID);
// Disable the message textarea
$('#' + cHash + ' .message-area').attr('disabled', true);
// Remove the presence for this XID
DataStore.removeDB(Connection.desktop_hash, 'presence-stanza', cXID);
DataStore.removeDB(Connection.desktop_hash, 'presence-resources', cXID);
@ -356,18 +358,18 @@ var Interface = (function () {
if(xid in MAM.map_states) {
delete MAM.map_states[xid];
}
// Get the chat ID which is before
var previous = $('#' + hash).prev().attr('id');
// Remove the chat
self.deleteThisChat(hash);
// Reset the switcher
if(!Common.exists('#page-switch .switcher.activechan')) {
self.switchChan(previous);
}
// Reset the notifications
self.chanCleanNotify(hash);
} catch(e) {
@ -397,32 +399,48 @@ var Interface = (function () {
var date = DateUtils.getXMPPTime('local');
var type = $('#' + hash).attr('data-type');
var direction = $('html').attr('dir') || 'ltr';
var content_sel = $(content);
// Filter the content smileys
$(content).find('img.emoticon').each(function() {
content_sel.find('img.emoticon').each(function() {
$(this).replaceWith($(this).attr('alt'));
});
// Remove the useless attributes
$(content).removeAttr('data-type').removeAttr('data-stamp');
content_sel.removeAttr('data-type').removeAttr('data-stamp');
// Remove the content avatars
$(content).find('.avatar-container').remove();
content_sel.find('.avatar-container').remove();
// Remove the content info
content_sel.find('.correction-edit, .message-marker, .corrected-info, .correction-label').remove();
// Remove the content click events
$(content).find('a').removeAttr('onclick');
content_sel.find('a').removeAttr('onclick');
// Extract the content HTML code
content = $(content).parent().html();
content = content_sel.parent().html();
// No avatar?
if(!avatar || !avatar.match(/data:/))
if(!avatar || !avatar.match(/data:/)) {
avatar = 'none';
}
// POST the values to the server
$.post('./server/generate-chat.php', { 'content': content, 'xid': xid, 'nick': nick, 'avatar': avatar, 'date': date, 'type': type, 'direction': direction }, function(data) {
$.post('./server/generate-chat.php', {
'content': content,
'xid': xid,
'nick': nick,
'avatar': avatar,
'date': date,
'type': type,
'direction': direction
}, function(data) {
// Handled!
$(path + 'tooltip-waitlog').replaceWith('<a class="tooltip-actionlog" href="./server/download-chat.php?id=' + data + '" target="_blank">' + Common._e("Download file!") + '</a>');
$(path + 'tooltip-waitlog').replaceWith(
'<a class="tooltip-actionlog" href="./server/download-chat.php?id=' + data + '" target="_blank">' + Common._e("Download file!") + '</a>'
);
});
} catch(e) {
Console.error('Interface.generateChatLog', e);
@ -433,6 +451,31 @@ var Interface = (function () {
};
/**
* Returns whether chan has focus or not
* @public
* @param {string} hash
* @return {boolean}
*/
self.hasChanFocus = function(hash) {
var has_focus = true;
try {
if(!$('#page-switch .' + hash).hasClass('activechan') ||
!Common.isFocused() ||
(self.chat_focus_hash != hash)) {
has_focus = false;
}
} catch(e) {
Console.error('Interface.hasChanFocus', e);
} finally {
return has_focus;
}
};
/**
* Notifies the user from a new incoming message
* @public
@ -447,9 +490,9 @@ var Interface = (function () {
var chat_switch = '#page-switch .';
var tested = chat_switch + hash;
var active = $(tested).hasClass('activechan');
// We notify the user if he has not the focus on the chat
if(!active || !Common.isFocused() || (self.chat_focus_hash != hash)) {
if(self.hasChanFocus(hash) === false) {
if(!active) {
if(type == 'personal') {
$(tested + ', ' + chat_switch + 'more-button').addClass('chan-newmessage');
@ -457,17 +500,17 @@ var Interface = (function () {
$(tested).addClass('chan-unread');
}
}
// Count the number of pending messages
var pending = 1;
if(Common.exists('#' + hash + '[data-counter]')) {
pending = parseInt($('#' + hash).attr('data-counter')) + 1;
}
$('#' + hash).attr('data-counter', pending);
}
// Update the page title
self.updateTitle();
} catch(e) {
@ -487,11 +530,11 @@ var Interface = (function () {
try {
// Count the number of notifications
var number = 0;
$('.one-counter[data-counter]').each(function() {
number = number + parseInt($(this).attr('data-counter'));
});
return number;
} catch(e) {
Console.error('Interface.pendingEvents', e);
@ -509,10 +552,11 @@ var Interface = (function () {
try {
// Any pending events?
if(Common.exists('.one-counter[data-counter]'))
if(Common.exists('.one-counter[data-counter]')) {
self.title('new');
else
} else {
self.title('talk');
}
} catch(e) {
Console.error('Interface.updateTitle', e);
}
@ -532,14 +576,15 @@ var Interface = (function () {
// 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())
if(!$(chat_switch + 'chans .chan-newmessage').size()) {
$(chat_switch + 'more-button').removeClass('chan-newmessage');
}
// We reset the chat counter
$('#' + hash).removeAttr('data-counter');
// Update the page title
self.updateTitle();
} catch(e) {
@ -561,7 +606,7 @@ var Interface = (function () {
// Avoid a JS error
if(Common.exists('#' + hash)) {
var container = document.getElementById('chat-content-' + hash);
// Scroll down!
container.scrollTop = container.scrollHeight;
}
@ -583,24 +628,25 @@ var Interface = (function () {
try {
// Put a marker
Roster.blist_all = true;
// We switch the two modes
$('.buddy-conf-more-display-unavailable').hide();
$('.buddy-conf-more-display-available').show();
// Security: reset all the groups toggle event
$('#roster .group-buddies').show();
$('#roster .group span').text('-');
// We show the disconnected buddies
$('.hidden-buddy').show();
// We show all the groups
$('#roster .one-group').show();
if(Search.search_filtered)
if(Search.search_filtered) {
Search.funnelFilterBuddy();
}
// Store this in the options
if((from == 'roster') && Options.loaded()) {
DataStore.setDB(Connection.desktop_hash, 'options', 'roster-showall', '1');
@ -624,25 +670,25 @@ var Interface = (function () {
try {
// Remove the marker
Roster.blist_all = false;
// We switch the two modes
$('.buddy-conf-more-display-available').hide();
$('.buddy-conf-more-display-unavailable').show();
// Security: reset all the groups toggle event
$('#roster .group-buddies').show();
$('#roster .group span').text('-');
// We hide the disconnected buddies
$('.hidden-buddy').hide();
// We check the groups to hide
Roster.updateGroups();
if(Search.search_filtered) {
Search.funnelFilterBuddy();
}
// Store this in the options
if((from == 'roster') && Options.loaded()) {
DataStore.setDB(Connection.desktop_hash, 'options', 'roster-showall', '0');
@ -687,6 +733,39 @@ var Interface = (function () {
$(document).ready(function() {
// Focus on the first visible input
$(window).focus(self.inputFocus);
// Re-focus to visible chat/groupchat input if typing when input blurred
$(document).keypress(function(evt) {
try {
// Don't trigger if not connected or popup opened
if(Common.isConnected() && !Common.exists('div.lock')) {
// Cannot work if an input/textarea is already focused or chat is not opened
var target_input_sel = $('.page-engine-chan .message-area:visible');
if(!target_input_sel.size() || $('input, textarea').is(':focus')) {
return;
}
// Get key value
var key_value = $.trim(String.fromCharCode(evt.which));
// Re-focus on opened chat?
if(key_value) {
// Get input values
value_input = target_input_sel.val();
// Append pressed key value
target_input_sel.val(value_input + key_value);
target_input_sel.focus();
// Put cursor at the end of input
target_input_sel[0].selectionStart = target_input_sel[0].selectionEnd = value_input.length + 1;
}
}
} catch(e) {
Console.error('Interface.launch[autofocus]', e);
}
});
});
} catch(e) {
Console.error('Interface.launch', e);

View file

@ -140,7 +140,7 @@ var addToHome = (function (w) {
options.message = '';
}
if ( options.message === '' ) { // We look for a suitable language (defaulted to en_us)
options.message = language in intl ? intl[language] : intl['en_us'];
options.message = language in intl ? intl[language] : intl.en_us;
}
if ( options.touchIcon ) {

View file

@ -20,6 +20,352 @@ var IQ = (function () {
var self = {};
/**
* Handles OOB request
* @private
* @param {string} iqType
* @param {string} iqID
* @param {object} iqNode
* @return {undefined}
*/
self._handleOOBRequest = function(iqFrom, iqID, iqNode) {
try {
/* REF: http://xmpp.org/extensions/xep-0066.html */
OOB.handle(iqFrom, iqID, 'iq', iqNode);
Console.log('Received IQ OOB request: ' + iqFrom);
} catch(e) {
Console.error('IQ._handleOOBRequest', e);
}
};
/**
* Handles OOB reply
* @private
* @param {object} iqResponse
* @param {string} iqFrom
* @param {string} iqType
* @param {string} iqID
* @param {object} iqNode
* @return {undefined}
*/
self._handleOOBReply = function(iqResponse, iqFrom, iqType, iqID, iqNode) {
try {
// Get the values
var oob_url = DataStore.getDB(Connection.desktop_hash, 'send/url', iqID);
var oob_desc = DataStore.getDB(Connection.desktop_hash, 'send/desc', iqID);
var notif_id = hex_md5(oob_url + oob_desc + iqType + iqFrom + iqID);
if($(iqNode).find('error').size()) {
// Error?
if($(iqNode).find('error not-acceptable').size()) {
// Rejected?
Notification.create('send_reject', iqFrom, [iqFrom, oob_url, 'iq', iqID, iqNode], oob_desc, notif_id);
} else {
// Failed?
Notification.create('send_fail', iqFrom, [iqFrom, oob_url, 'iq', iqID, iqNode], oob_desc, notif_id);
}
// Remove the file
$.get(oob_url + '&action=remove');
} else if(iqType == 'result') {
// Success?
Notification.create('send_accept', iqFrom, [iqFrom, oob_url, 'iq', iqID, iqNode], oob_desc, notif_id);
}
} catch(e) {
Console.error('IQ._handleOOBReply', e);
}
};
/**
* Handles Software Version
* @private
* @param {object} iqResponse
* @param {string} iqFrom
* @return {undefined}
*/
self._handleSoftwareVersion = function(iqResponse, iqFrom) {
try {
/* REF: http://xmpp.org/extensions/xep-0092.html */
iqQuery = iqResponse.setQuery(NS_VERSION);
iqQuery.appendChild(iqResponse.buildNode('name', {'xmlns': NS_VERSION}, Caps.disco_infos.identity.name));
iqQuery.appendChild(iqResponse.buildNode('version', {'xmlns': NS_VERSION}, JAPPIX_VERSION));
iqQuery.appendChild(iqResponse.buildNode('os', {'xmlns': NS_VERSION}, BrowserDetect.OS));
con.send(iqResponse);
Console.log('Received software version query: ' + iqFrom);
} catch(e) {
Console.error('IQ._handleSoftwareVersion', e);
}
};
/**
* Handles Last Activity
* @private
* @param {object} iqResponse
* @param {string} iqFrom
* @return {undefined}
*/
self._handleLastActivity = function(iqResponse, iqFrom) {
try {
/* REF: http://xmpp.org/extensions/xep-0012.html */
iqQuery = iqResponse.setQuery(NS_LAST);
iqQuery.setAttribute('seconds', DateUtils.getLastActivity());
con.send(iqResponse);
Console.log('Received last activity query: ' + iqFrom);
} catch(e) {
Console.error('IQ._handleLastActivity', e);
}
};
/**
* Handles Privacy Lists
* @private
* @param {object} iqResponse
* @param {string} iqFrom
* @param {string} iqQuery
* @return {undefined}
*/
self._handlePrivacyLists = function(iqResponse, iqFrom, iqQuery) {
try {
// REF : http://xmpp.org/extensions/xep-0016.html
// Roster push
con.send(iqResponse);
// Get the lists
$(iqQuery).find('list').each(function() {
Privacy.get($(this).attr('name'));
});
Console.log('Received privacy lists push: ' + iqFrom);
} catch(e) {
Console.error('IQ._handlePrivacyLists', e);
}
};
/**
* Handles Roster Push
* @private
* @param {object} iqResponse
* @param {string} iqFrom
* @param {string} iqQuery
* @return {undefined}
*/
self._handleRosterPush = function(iqResponse, iqFrom, iqQuery) {
try {
// REF : http://xmpp.org/extensions/xep-0092.html
// Roster push
con.send(iqResponse);
// Get the values
$(iqQuery).find('item').each(function() {
Roster.parse($(this), 'presence');
});
Console.log('Received roster push: ' + iqFrom);
} catch(e) {
Console.error('IQ._handleRosterPush', e);
}
};
/**
* Handles Roster Item Exchange
* @private
* @param {object} iqNode
* @param {string} iqFrom
* @return {undefined}
*/
self._handleRosterItemExchange = function(iqNode, iqFrom) {
try {
// Open a new notification
Notification.create('rosterx', iqFrom, [iqNode], '');
Console.log('Roster Item Exchange from: ' + iqFrom);
} catch(e) {
Console.error('IQ._handleRosterItemExchange', e);
}
};
/**
* Handles Disco Info
* @private
* @param {object} iqResponse
* @param {string} iqFrom
* @return {undefined}
*/
self._handleDiscoInfo = function(iqResponse, iqFrom) {
try {
/* REF: http://xmpp.org/extensions/xep-0030.html */
iqQuery = iqResponse.setQuery(NS_DISCO_INFO);
// We set the name of the client
iqQuery.appendChild(iqResponse.buildNode('identity', {
'category': Caps.disco_infos.identity.category,
'type': Caps.disco_infos.identity.type,
'name': Caps.disco_infos.identity.name,
'xmlns': NS_DISCO_INFO
}));
// We set all the supported features
var disco_infos = Caps.myDiscoInfos();
$.each(disco_infos, function(i, disco_info) {
iqQuery.appendChild(iqResponse.buildNode('feature', {'var': disco_info, 'xmlns': NS_DISCO_INFO}));
});
con.send(iqResponse);
Console.log('Received disco#infos query: ' + iqFrom);
} catch(e) {
Console.error('IQ._handleDiscoInfo', e);
}
};
/**
* Handles User Time
* @private
* @param {object} iqResponse
* @param {string} iqFrom
* @return {undefined}
*/
self._handleUserTime = function(iqResponse, iqFrom) {
try {
/* REF: http://xmpp.org/extensions/xep-0202.html */
var iqTime = iqResponse.appendNode('time', {
'xmlns': NS_URN_TIME
});
iqTime.appendChild(iqResponse.buildNode('tzo', {
'xmlns': NS_URN_TIME
}, DateUtils.getTZO()));
iqTime.appendChild(iqResponse.buildNode('utc', {
'xmlns': NS_URN_TIME
}, DateUtils.getXMPPTime('utc')));
con.send(iqResponse);
Console.log('Received local time query: ' + iqFrom);
} catch(e) {
Console.error('IQ._handleUserTime', e);
}
};
/**
* Handles Ping
* @private
* @param {object} iqResponse
* @param {string} iqFrom
* @return {undefined}
*/
self._handlePing = function(iqResponse, iqFrom) {
try {
/* REF: http://xmpp.org/extensions/xep-0199.html */
con.send(iqResponse);
Console.log('Received a ping: ' + iqFrom);
} catch(e) {
Console.error('IQ._handlePing', e);
}
};
/**
* Handles Jingle
* @private
* @param {string} iqFrom
* @return {undefined}
*/
self._handleJingle = function(iqFrom) {
try {
/* REF: http://xmpp.org/extensions/xep-0166.html */
// Handled via JSJaCJingle.route() (see above)
Console.log('Received a Jingle packet: ' + iqFrom);
} catch(e) {
Console.error('IQ._handleJingle', e);
}
};
/**
* Raises a not implemented error
* @private
* @param {object} iqResponse
* @param {object} iqNode
* @param {string} iqFrom
* @return {undefined}
*/
self._raiseNotImplemented = function(iqResponse, iqNode, iqFrom) {
try {
// Change IQ type
iqResponse.setType('error');
// Append stanza content
for(var c = 0; c < iqNode.childNodes.length; c++) {
iqResponse.getNode().appendChild(iqNode.childNodes.item(c).cloneNode(true));
}
// Append error content
var iqError = iqResponse.appendNode('error', {'xmlns': NS_CLIENT, 'code': '501', 'type': 'cancel'});
iqError.appendChild(iqResponse.buildNode('feature-not-implemented', {'xmlns': NS_STANZAS}));
iqError.appendChild(iqResponse.buildNode('text', {'xmlns': NS_STANZAS}, Common._e("The feature requested is not implemented by the recipient or server and therefore cannot be processed.")));
con.send(iqResponse);
Console.log('Received an unsupported IQ query from: ' + iqFrom);
} catch(e) {
Console.error('IQ._raiseNotImplemented', e);
}
};
/**
* Handles an incoming IQ packet
* @public
@ -37,190 +383,71 @@ var IQ = (function () {
var iqQuery = iq.getQuery();
var iqType = iq.getType();
// Handle Jingle packet?
JSJaCJingle_route(iq);
// 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 */
OOB.handle(iqFrom, iqID, 'iq', iqNode);
Console.log('Received IQ OOB request: ' + iqFrom);
self._handleOOBRequest(iqFrom, iqID, iqNode);
}
// OOB reply
else if(DataStore.getDB(Connection.desktop_hash, 'send/url', iqID)) {
// Get the values
var oob_url = DataStore.getDB(Connection.desktop_hash, 'send/url', iqID);
var oob_desc = DataStore.getDB(Connection.desktop_hash, 'send/desc', iqID);
var notif_id = hex_md5(oob_url + oob_desc + iqType + iqFrom + iqID);
if($(iqNode).find('error').size()) {
// Error?
if($(iqNode).find('error not-acceptable').size()) {
// Rejected?
Notification.create('send_reject', iqFrom, [iqFrom, oob_url, 'iq', iqID, iqNode], oob_desc, notif_id);
} else {
// Failed?
Notification.create('send_fail', iqFrom, [iqFrom, oob_url, 'iq', iqID, iqNode], oob_desc, notif_id);
}
// Remove the file
$.get(oob_url + '&action=remove');
} else if(iqType == 'result') {
// Success?
Notification.create('send_accept', iqFrom, [iqFrom, oob_url, 'iq', iqID, iqNode], oob_desc, notif_id);
}
self._handleOOBReply(iqResponse, iqFrom, iqType, iqID, iqNode);
}
// Software version query
else if((iqQueryXMLNS == NS_VERSION) && (iqType == 'get')) {
/* REF: http://xmpp.org/extensions/xep-0092.html */
iqQuery = iqResponse.setQuery(NS_VERSION);
iqQuery.appendChild(iqResponse.buildNode('name', {'xmlns': NS_VERSION}, 'Jappix'));
iqQuery.appendChild(iqResponse.buildNode('version', {'xmlns': NS_VERSION}, JAPPIX_VERSION));
iqQuery.appendChild(iqResponse.buildNode('os', {'xmlns': NS_VERSION}, BrowserDetect.OS));
con.send(iqResponse);
Console.log('Received software version query: ' + iqFrom);
self._handleSoftwareVersion(iqResponse, iqFrom);
}
// Last activity query
else if((iqQueryXMLNS == NS_LAST) && (iqType == 'get')) {
/* REF: http://xmpp.org/extensions/xep-0012.html */
iqQuery = iqResponse.setQuery(NS_LAST);
iqQuery.setAttribute('seconds', DateUtils.getLastActivity());
con.send(iqResponse);
Console.log('Received last activity query: ' + iqFrom);
self._handleLastActivity(iqResponse, iqFrom);
}
// Privacy lists push
else if((iqQueryXMLNS == NS_PRIVACY) && (iqType == 'set') && Common.isSafeStanza(iq)) {
// REF : http://xmpp.org/extensions/xep-0016.html
// Roster push
con.send(iqResponse);
// Get the lists
$(iqQuery).find('list').each(function() {
Privacy.get($(this).attr('name'));
});
Console.log('Received privacy lists push: ' + iqFrom);
self._handlePrivacyLists(iqResponse, iqFrom, iqQuery);
}
// Roster push
else if((iqQueryXMLNS == NS_ROSTER) && (iqType == 'set') && Common.isSafeStanza(iq)) {
// REF : http://xmpp.org/extensions/xep-0092.html
// Roster push
con.send(iqResponse);
// Get the values
$(iqQuery).find('item').each(function() {
Roster.parse($(this), 'presence');
});
Console.log('Received roster push: ' + iqFrom);
self._handleRosterPush(iqResponse, iqFrom, iqQuery);
}
// Roster Item Exchange query
else if($(iqNode).find('x[xmlns="' + NS_ROSTERX + '"]').size()) {
// Open a new notification
Notification.create('rosterx', iqFrom, [iqNode], '');
Console.log('Roster Item Exchange from: ' + iqFrom);
self._handleRosterItemExchange(iqNode, iqFrom);
}
// Disco info query
else if((iqQueryXMLNS == NS_DISCO_INFO) && (iqType == 'get')) {
/* REF: http://xmpp.org/extensions/xep-0030.html */
iqQuery = iqResponse.setQuery(NS_DISCO_INFO);
// We set the name of the client
iqQuery.appendChild(iqResponse.buildNode('identity', {
'category': 'client',
'type': 'web',
'name': 'Jappix',
'xmlns': NS_DISCO_INFO
}));
// We set all the supported features
var disco_infos = Caps.myDiscoInfos();
$.each(disco_infos, function(i, disco_info) {
iqQuery.appendChild(iqResponse.buildNode('feature', {'var': disco_info, 'xmlns': NS_DISCO_INFO}));
});
con.send(iqResponse);
Console.log('Received disco#infos query: ' + iqFrom);
self._handleDiscoInfo(iqResponse, 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(iqResponse.buildNode('tzo', {'xmlns': NS_URN_TIME}, DateUtils.getTZO()));
iqTime.appendChild(iqResponse.buildNode('utc', {'xmlns': NS_URN_TIME}, DateUtils.getXMPPTime('utc')));
con.send(iqResponse);
Console.log('Received local time query: ' + iqFrom);
self._handleUserTime(iqResponse, iqFrom);
}
// Ping
else if($(iqNode).find('ping').size() && (iqType == 'get')) {
/* REF: http://xmpp.org/extensions/xep-0199.html */
con.send(iqResponse);
Console.log('Received a ping: ' + iqFrom);
self._handlePing(iqResponse, iqFrom);
}
// Jingle
else if($(iqNode).find('jingle').size()) {
/* REF: http://xmpp.org/extensions/xep-0166.html */
// Handled via JSJaCJingle_route() (see above)
Console.log('Received a Jingle packet: ' + iqFrom);
self._handleJingle(iqFrom);
}
// Not implemented
else if(!$(iqNode).find('error').size() && ((iqType == 'get') || (iqType == 'set'))) {
// Change IQ type
iqResponse.setType('error');
// Append stanza content
for(var c = 0; c < iqNode.childNodes.length; c++) {
iqResponse.getNode().appendChild(iqNode.childNodes.item(c).cloneNode(true));
}
// Append error content
var iqError = iqResponse.appendNode('error', {'xmlns': NS_CLIENT, 'code': '501', 'type': 'cancel'});
iqError.appendChild(iqResponse.buildNode('feature-not-implemented', {'xmlns': NS_STANZAS}));
iqError.appendChild(iqResponse.buildNode('text', {'xmlns': NS_STANZAS}, Common._e("The feature requested is not implemented by the recipient or server and therefore cannot be processed.")));
con.send(iqResponse);
Console.log('Received an unsupported IQ query from: ' + iqFrom);
self._raiseNotImplemented(iqResponse, iqNode, iqFrom);
}
} catch(e) {
Console.error('IQ.handle', e);

File diff suppressed because it is too large Load diff

View file

@ -72,7 +72,7 @@ feature.formdata = window.FormData !== undefined;
var hasProp = !!$.fn.prop;
// attr2 uses prop when it can but checks the return type for
// an expected string. this accounts for the case where a form
// an expected string. this accounts for the case where a form
// contains inputs with names like "action" or "method"; in those
// cases "prop" returns the element
$.fn.attr2 = function() {
@ -461,7 +461,7 @@ $.fn.ajaxSubmit = function(options) {
var CLIENT_TIMEOUT_ABORT = 1;
var SERVER_ABORT = 2;
function getDoc(frame) {
/* it looks like contentWindow or contentDocument do not
* carry the protocol property in ie8, when running under ssl
@ -469,9 +469,9 @@ $.fn.ajaxSubmit = function(options) {
* the protocol is know but not on the other two objects. strange?
* "Same origin policy" http://en.wikipedia.org/wiki/Same_origin_policy
*/
var doc = null;
// IE8 cascading access check
try {
if (frame.contentWindow) {
@ -507,8 +507,8 @@ $.fn.ajaxSubmit = function(options) {
// 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.attr2('target'),
a = $form.attr2('action'),
var t = $form.attr2('target'),
a = $form.attr2('action'),
mp = 'multipart/form-data',
et = $form.attr('enctype') || $form.attr('encoding') || mp;
@ -619,7 +619,7 @@ $.fn.ajaxSubmit = function(options) {
if (xhr.aborted || callbackProcessed) {
return;
}
doc = getDoc(io);
if(!doc) {
log('cannot access response document');

File diff suppressed because it is too large Load diff

View file

@ -1,138 +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);
});
});
/**
* 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

@ -13,12 +13,12 @@ Authors: Stefan Strigler, Valérian Saliou, Zash, Maranda
/**
* @fileoverview Magic dependency loading. Taken from script.aculo.us
* and modified to break it.
* @author Stefan Strigler steve@zeank.in-berlin.de
* @version $Revision$
* @author Stefan Strigler steve@zeank.in-berlin.de
* @version 1.3
*/
var JSJaC = {
Version: '$Rev$',
Version: '1.3',
bind: function(fn, obj, optArg) {
return function(arg) {
return fn.apply(obj, [arg, optArg]);
@ -26,9 +26,6 @@ var JSJaC = {
}
};
if (typeof JSJaCConnection == 'undefined')
JSJaC.load();
/* Copyright 2006 Erik Arvidsson
@ -52,7 +49,7 @@ if (typeof JSJaCConnection == 'undefined')
* this code is taken from
* http://webfx.eae.net/dhtml/xmlextras/xmlextras.html
* @author Stefan Strigler steve@zeank.in-berlin.de
* @version $Revision$
* @version 1.3
*/
/**
@ -71,18 +68,18 @@ XmlHttp.create = function () {
// Able to use CORS?
if (window.XMLHttpRequest) {
var req = new XMLHttpRequest();
if (req.withCredentials !== undefined)
return req;
}
// Fallback on JSONP
return new jXHR();
}
// Might be local-domain?
if (window.XMLHttpRequest) {
var req = new XMLHttpRequest();
// some versions of Moz do not support the readyState property
// and the onreadystate event so we patch it!
if (req.readyState == null) {
@ -93,7 +90,7 @@ XmlHttp.create = function () {
req.onreadystatechange();
}, false);
}
return req;
}
if (window.ActiveXObject) {
@ -112,7 +109,7 @@ XmlHttp.create = function () {
XmlHttp.getPrefix = function() {
if (XmlHttp.prefix) // I know what you did last summer
return XmlHttp.prefix;
var prefixes = ["MSXML2", "Microsoft", "MSXML", "MSXML3"];
var o;
for (var i = 0; i < prefixes.length; i++) {
@ -123,7 +120,7 @@ XmlHttp.getPrefix = function() {
}
catch (ex) {};
}
throw new Error("Could not find an installed XML parser");
};
@ -156,7 +153,7 @@ XmlDocument.create = function (name,ns) {
} else if (window.ActiveXObject) {
doc = new ActiveXObject(XmlDocument.getPrefix() + ".DomDocument");
}
if (!doc.documentElement || doc.documentElement.tagName != name ||
(doc.documentElement.namespaceURI &&
doc.documentElement.namespaceURI != ns)) {
@ -168,7 +165,7 @@ XmlDocument.create = function (name,ns) {
doc.appendChild(doc.createElement(name));
} catch (dex) {
doc = document.implementation.createDocument(ns,name,null);
if (doc.documentElement == null)
doc.appendChild(doc.createElement(name));
@ -179,7 +176,7 @@ XmlDocument.create = function (name,ns) {
}
}
}
return doc;
}
catch (ex) { }
@ -204,7 +201,7 @@ XmlDocument.getPrefix = function() {
}
catch (ex) {};
}
throw new Error("Could not find an installed XML parser");
};
@ -218,14 +215,14 @@ if (typeof(Document) != 'undefined' && window.DOMParser) {
* @private
*/
Document.prototype.loadXML = function (s) {
// parse the string to a new doc
var doc2 = (new DOMParser()).parseFromString(s, "text/xml");
// remove all initial children
while (this.hasChildNodes())
this.removeChild(this.lastChild);
// insert and import nodes
for (var i = 0; i < doc2.childNodes.length; i++) {
this.appendChild(this.importNode(doc2.childNodes[i], true));
@ -282,7 +279,7 @@ if (window.XMLSerializer &&
/**
* @fileoverview Collection of functions to make live easier
* @author Stefan Strigler
* @version $Revision$
* @version 1.3
*/
/**
@ -334,10 +331,10 @@ Date.jab2date = function(ts) {
// Timestamp
if(!isNaN(ts))
return new Date(ts * 1000);
// Get the UTC date
var date = new Date(Date.UTC(ts.substr(0,4),ts.substr(5,2)-1,ts.substr(8,2),ts.substr(11,2),ts.substr(14,2),ts.substr(17,2)));
if (ts.substr(ts.length-6,1) != 'Z') { // there's an offset
var date_offset = date.getTimezoneOffset() * 60 * 1000;
var offset = new Date();
@ -370,7 +367,7 @@ Date.hrTime = function(ts) {
if (!Date.now) {
Date.now = function() { return new Date().getTime(); }
}
/**
* somewhat opposit to {@link #hrTime}
* expects a javascript Date object as parameter and returns a jabber
@ -1088,7 +1085,7 @@ function utf8t2d(t)
}
return d;
}
// returns plaintext from an array of bytesrepresenting dezimal numbers, which
// represent an UTF-8 encoded text; browser which does not understand unicode
// like NN401 will show "?"-signs instead
@ -1206,7 +1203,7 @@ function cnonce(size) {
JSJAC_HAVEKEYS = true; // whether to use keys
JSJAC_NKEYS = 16; // number of keys to generate
JSJAC_INACTIVITY = 300; // qnd hack to make suspend/resume
JSJAC_INACTIVITY = 300; // qnd hack to make suspend/resume
// work more smoothly with polling
JSJAC_ERR_COUNT = 10; // number of retries in case of connection
// errors
@ -1230,7 +1227,7 @@ JSJAC_REGID_TIMEOUT = 20000; // time in msec until registered
JSJACHBC_MAX_HOLD = 1; // default for number of connctions
// held by connection manager
JSJACHBC_MAX_WAIT = 300; // default 'wait' param - how long an
JSJACHBC_MAX_WAIT = 20; // default 'wait' param - how long an
// idle connection should be held by
// connection manager
@ -1293,7 +1290,7 @@ JSJaCJSON.toString = function (obj) {
a[a.length] = v;
b = true;
}
} catch(e) {
} catch(e) {
}
}
}
@ -1334,7 +1331,7 @@ JSJaCJSON.toString = function (obj) {
}
}
}
a[a.length] = '}';
return a.join('');
}
@ -1362,7 +1359,7 @@ switch (typeof(obj)) {
return s.object(obj);
case 'array':
return s.array(obj);
}
};
@ -1381,7 +1378,7 @@ JSJaCJSON.parse = function (str) {
* @fileoverview This file contains all things that make life easier when
* dealing with JIDs
* @author Stefan Strigler
* @version $Revision$
* @version 1.3
*/
/**
@ -1714,7 +1711,7 @@ var JSJaCBuilder = {
/**
* @fileoverview Contains all Jabber/XMPP packet related classes.
* @author Stefan Strigler steve@zeank.in-berlin.de
* @version $Revision$
* @version 1.3
*/
var JSJACPACKET_USE_XMLNS = true;
@ -2502,7 +2499,7 @@ function JSJaCError(code,type,condition) {
* @constructor
* @param {Function} func The hash function to be used for creating the keys
* @param {Debugger} oDbg Reference to debugger implementation [optional]
*/
*/
function JSJaCKeys(func,oDbg) {
var seed = Math.random();
@ -2567,7 +2564,7 @@ function JSJaCKeys(func,oDbg) {
* @fileoverview Contains all things in common for all subtypes of connections
* supported.
* @author Stefan Strigler steve@zeank.in-berlin.de
* @version $Revision$
* @version 1.3
*/
/**
@ -2751,30 +2748,30 @@ JSJaCConnection.prototype.connected = function() { return this._connected; };
*/
JSJaCConnection.prototype.disconnect = function() {
this._setStatus('disconnecting');
if (!this.connected())
return;
this._connected = false;
clearInterval(this._interval);
clearInterval(this._inQto);
if (this._timeout)
clearTimeout(this._timeout); // remove timer
var slot = this._getFreeSlot();
// Intentionally synchronous
this._req[slot] = this._setupRequest(false);
request = this._getRequestString(false, true);
this.oDbg.log("Disconnecting: " + request,4);
this._req[slot].r.send(request);
try {
DataStore.removeDB(MINI_HASH, 'jsjac', 'state');
} catch (e) {}
this.oDbg.log("Disconnected: "+this._req[slot].r.responseText,2);
this._handleEvent('ondisconnect');
};
@ -3119,7 +3116,7 @@ JSJaCConnection.prototype.status = function() { return this._status; };
*/
JSJaCConnection.prototype.suspend = function(has_pause) {
var data = this.suspendToData(has_pause);
try {
var c = DataStore.setDB(MINI_HASH, 'jsjac', 'state', JSJaCJSON.toString(data));
return c;
@ -3136,7 +3133,7 @@ JSJaCConnection.prototype.suspend = function(has_pause) {
* @type Object
*/
JSJaCConnection.prototype.suspendToData = function(has_pause) {
// remove timers
if(has_pause) {
clearTimeout(this._timeout);
@ -3145,7 +3142,7 @@ JSJaCConnection.prototype.suspendToData = function(has_pause) {
this._suspend();
}
var u = ('_connected,_keys,_ID,_inQ,_pQueue,_regIDs,_errcnt,_inactivity,domain,username,resource,jid,fulljid,_sid,_httpbase,_timerval,_is_polling').split(',');
u = u.concat(this._getSuspendVars());
var s = new Object();
@ -3162,12 +3159,12 @@ JSJaCConnection.prototype.suspendToData = function(has_pause) {
s[u[i]] = o;
}
if(has_pause) {
this._connected = false;
this._setStatus('suspending');
}
return s;
};
@ -3601,10 +3598,6 @@ JSJaCConnection.prototype._handlePID = function(packet) {
if (!packet.getID())
return false;
if (packet.pType() != 'iq' ||
(packet.getType() != 'error' && packet.getType() != 'result'))
return false;
var jid = packet.getFrom() || this.jid;
if (packet.getFrom() == this.domain)
@ -3687,7 +3680,7 @@ JSJaCConnection.prototype._parseStreamFeatures = function(doc) {
this._handleEvent('ondisconnect');
return false;
}
this.mechs = new Object();
var lMec1 = doc.getElementsByTagName("mechanisms");
this.has_sasl = false;
@ -3706,7 +3699,7 @@ JSJaCConnection.prototype._parseStreamFeatures = function(doc) {
this.oDbg.log("No support for SASL detected",2);
return false;
}
// Get the server CAPS (if available)
this.server_caps=null;
var sCaps = doc.getElementsByTagName("c");
@ -3714,7 +3707,7 @@ JSJaCConnection.prototype._parseStreamFeatures = function(doc) {
var c_sCaps=sCaps.item(i);
var x_sCaps=c_sCaps.getAttribute("xmlns");
var v_sCaps=c_sCaps.getAttribute("ver");
if ((x_sCaps == NS_CAPS) && v_sCaps) {
this.server_caps=v_sCaps;
break;
@ -3723,10 +3716,10 @@ JSJaCConnection.prototype._parseStreamFeatures = function(doc) {
// Get legacy session capability if available
this.legacy_sessions=null;
if (doc.getElementsByTagName("session")[0]) {
if (doc.getElementsByTagName("session")) {
this.legacy_sessions=true;
}
return true;
};
@ -3955,7 +3948,7 @@ JSJaCConnection.prototype._setStatus = function(status) {
/**
* @fileoverview All stuff related to HTTP Binding
* @author Stefan Strigler steve@zeank.in-berlin.de
* @version $Revision$
* @version 1.3
*/
/**
@ -4169,13 +4162,13 @@ JSJaCHttpBindingConnection.prototype._getStreamID = function(req) {
return;
}
var body = req.responseXML.documentElement;
// any session error?
if(body.getAttribute('type') == 'terminate') {
this._handleEvent('onerror',JSJaCError('503','cancel','service-unavailable'));
return;
}
// extract stream id used for non-SASL authentication
if (body.getAttribute('authid')) {
this.streamid = body.getAttribute('authid');
@ -4451,7 +4444,7 @@ JSJaCHttpBindingConnection.prototype._reInitStreamWait = function(req, cb) {
var featuresNL = doc.getElementsByTagName('stream:features');
for (var i=0, l=featuresNL.length; i<l; i++) {
if (featuresNL.item(i).namespaceURI == 'http://etherx.jabber.org/streams' ||
featuresNL.item(i).getAttribute('xmlns') ==
featuresNL.item(i).getAttribute('xmlns') ==
'http://etherx.jabber.org/streams') {
var features = featuresNL.item(i);
break;
@ -4461,7 +4454,7 @@ JSJaCHttpBindingConnection.prototype._reInitStreamWait = function(req, cb) {
var bind = features.getElementsByTagName('bind');
for (var i=0, l=bind.length; i<l; i++) {
if (bind.item(i).namespaceURI == 'urn:ietf:params:xml:ns:xmpp-bind' ||
bind.item(i).getAttribute('xmlns') ==
bind.item(i).getAttribute('xmlns') ==
'urn:ietf:params:xml:ns:xmpp-bind') {
bind = bind.item(i);
break;
@ -4471,7 +4464,7 @@ JSJaCHttpBindingConnection.prototype._reInitStreamWait = function(req, cb) {
}
this.oDbg.log(features);
this.oDbg.log(bind);
if (features) {
if (bind) {
cb();
@ -4865,7 +4858,26 @@ JSJaCWebSocketConnection.prototype._parseXml = function(s) {
this.oDbg.log('Parsing: ' + s, 4);
try {
doc = XmlDocument.create('stream', NS_STREAM);
if(s.indexOf('<stream:stream') === -1) {
if(s.trim() == '</stream:stream>') {
// Consider session as closed
this.oDbg.log("session terminated", 1);
clearTimeout(this._timeout); // remove timer
clearInterval(this._interval);
clearInterval(this._inQto);
try {
DataStore.removeDB(MINI_HASH, 'jsjac', 'state');
} catch (e) {}
this._connected = false;
this._handleEvent('onerror',JSJaCError('503','cancel','session-terminate'));
this.oDbg.log("Disconnected.",1);
this._handleEvent('ondisconnect');
return null;
} else if(s.indexOf('<stream:stream') === -1) {
// Wrap every stanza into stream element, so that XML namespaces work properly.
doc.loadXML("<stream:stream xmlns:stream='" + NS_STREAM + "' xmlns='jabber:client'>" + s + "</stream:stream>");
return doc.documentElement.firstChild;
@ -5018,3 +5030,61 @@ JSJaCWebSocketConnection.prototype._sendRaw = function(xml, cb, arg) {
return true;
};
/*exported JSJaCUtils */
/**
* Various utilities put together so that they don't pollute global
* name space.
* @namespace
*/
var JSJaCUtils = {
/**
* XOR two strings of equal length.
* @param {string} s1 first string to XOR.
* @param {string} s2 second string to XOR.
* @return {string} s1 ^ s2.
*/
xor: function(s1, s2) {
/*jshint bitwise: false */
if(!s1) {
return s2;
}
if(!s2) {
return s1;
}
var result = '';
for(var i = 0; i < s1.length; i++) {
result += String.fromCharCode(s1.charCodeAt(i) ^ s2.charCodeAt(i));
}
return result;
},
/**
* Create nonce value of given size.
* @param {int} size size of the nonce that should be generated.
* @return {string} generated nonce.
*/
cnonce: function(size) {
var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var cnonce = '';
for (var i = 0; i < size; i++) {
cnonce += tab.charAt(Math.round(Math.random(new Date().getTime()) * (tab.length - 1)));
}
return cnonce;
},
/**
* Current timestamp.
* @return Seconds since 1.1.1970.
* @type int
*/
now: function() {
if (Date.now && typeof Date.now == 'function') {
return Date.now();
} else {
return new Date().getTime();
}
}
};

View file

@ -1,116 +1,116 @@
// jXHR.js (JSON-P XHR)
// v0.1 (c) Kyle Simpson
// License: MIT
// 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);
// jXHR.js (JSON-P XHR)
// v0.1 (c) Kyle Simpson
// License: MIT
// 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

@ -32,25 +32,33 @@ var Links = (function () {
try {
var target;
// Links style
if(!style)
if(!style) {
style = '';
else
} else {
style = ' style="' + style + '"';
}
// Open in new tabs
if(mode != 'xhtml-im')
if(mode != 'xhtml-im') {
target = ' target="_blank"';
else
} 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');
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>');
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;
} catch(e) {
Console.error('Links.apply', e);

View file

@ -35,6 +35,7 @@ var MAM = (function () {
self.map_reqs = {};
self.map_pending = {};
self.map_states = {};
self.map_messages = {};
self.msg_queue = {};
@ -48,7 +49,7 @@ var MAM = (function () {
try {
// Lock the archiving options
$('#archiving').attr('disabled', true);
// Get the archiving configuration
var iq = new JSJaCIQ();
iq.setType('get');
@ -145,7 +146,7 @@ var MAM = (function () {
for(var c in args) {
if(args[c]) purge.appendChild(iq.buildNode(c, {'xmlns': NS_METRONOME_MAM_PURGE}, args[c]));
}
con.send(iq, function(iq) {
if(iq.getType() == 'result') {
Console.info('Archives purged (MAM).');
@ -252,7 +253,7 @@ var MAM = (function () {
// Create MAM messages target
var target_html = '<div class="mam-chunk" data-start="' + Common.encodeQuotes(start_stamp) + '" data-end="' + Common.encodeQuotes(start_end) + '"></div>';
var target_content_sel = $('#' + hex_md5(res_with) + ' .content');
var target_wait_sel = target_content_sel.find('.wait-mam');
@ -311,11 +312,16 @@ var MAM = (function () {
if(c_message[0]) {
// Re-build a proper JSJaC message stanza
var message = JSJaCPacket.wrapNode(c_message[0]);
var message_node = message.getNode();
// Check message type
var type = message.getType() || 'chat';
if(type == 'chat') {
// Display function
var c_display_fn;
var c_display_msg_bool = false;
// Read message data
var xid = Common.bareXID(Common.getStanzaFrom(message));
var id = message.getID();
@ -331,50 +337,100 @@ var MAM = (function () {
var hash = hex_md5(xid);
var body = message.getBody();
// Read delay (required since we deal w/ a past message!)
var time, stamp;
var delay = c_delay.attr('stamp');
// Content message?
if(body) {
// Read delay (required since we deal w/ a past message!)
var time, stamp;
var delay = c_delay.attr('stamp');
if(delay) {
time = DateUtils.relative(delay);
stamp = DateUtils.extractStamp(Date.jab2date(delay));
}
// Last-minute checks before display
if(time && stamp && body) {
var mam_chunk_path = '#' + hash + ' .mam-chunk';
// No chat auto-scroll?
var no_scroll = Common.exists(mam_chunk_path);
// Select the custom target
var c_target_sel = function() {
return $(mam_chunk_path).filter(function() {
return $(this).attr('data-start') <= stamp && $(this).attr('data-end') >= stamp;
}).filter(':first');
};
// Display the message in that target
var c_msg_display = function() {
Message.display(type, from_xid, hash, b_name.htmlEnc(), body, time, stamp, 'old-message', true, null, mode, null, c_target_sel(), no_scroll);
};
// Hack: do not display the message in case we would duplicate it w/ current session messages
// only used when initiating a new chat, avoids collisions
if(!(xid in self.map_states) && $('#' + hash).find('.one-line.user-message:last').text() == body) {
return;
if(delay) {
time = DateUtils.relative(delay);
stamp = DateUtils.extractStamp(Date.jab2date(delay));
}
if(c_target_sel().size()) {
// Last-minute checks before display
if(time && stamp) {
var mam_chunk_path = '#' + hash + ' .mam-chunk';
// Markable message?
var is_markable = Markers.hasRequestMarker(message_node);
// No chat auto-scroll?
var no_scroll = Common.exists(mam_chunk_path);
// Select the custom target
var c_target_sel = function() {
return $(mam_chunk_path).filter(function() {
return $(this).attr('data-start') <= stamp && $(this).attr('data-end') >= stamp;
}).filter(':first');
};
// Display the message in that target
c_msg_display();
c_display_fn = function() {
// Display message
Message.display(
type,
from_xid,
hash,
b_name.htmlEnc(),
body,
time,
stamp,
'old-message',
true,
null,
mode,
id + '-mam',
c_target_sel(),
no_scroll,
undefined,
undefined,
undefined,
is_markable
);
self.map_messages[id] = 1;
};
c_display_msg_bool = c_target_sel().size() ? true : false;
// Hack: do not display the message in case we would duplicate it w/ current session messages
// only used when initiating a new chat, avoids collisions
if(!(xid in self.map_states) && $('#' + hash).find('.one-line.user-message:last').text() == body) {
return;
}
}
} else if(Markers.hasResponseMarker(message_node)) {
// Marked message? (by other party)
if(mode == 'him') {
var marked_message_id = Markers.getMessageID(message_node);
c_display_fn = function() {
var is_mam_marker = true;
Markers.handle(
from_xid,
message_node,
is_mam_marker
);
};
c_display_msg_bool = (self.map_messages[marked_message_id] === 1) ? true : false;
}
}
// Display message?
if(typeof c_display_fn == 'function') {
if(c_display_msg_bool === true) {
// Display message now
c_display_fn();
} else {
// Delay display (we may not have received the MAM reply ATM)
if(typeof self.msg_queue[xid] != 'object') {
self.msg_queue[xid] = [];
}
self.msg_queue[xid].push(c_msg_display);
self.msg_queue[xid].push(c_display_fn);
}
}
}

View file

@ -0,0 +1,428 @@
/*
Jappix - An open social platform
Implementation of XEP-0333: Chat Markers
-------------------------------------------------
License: AGPL
Author: Valérian Saliou
*/
// Bundle
var Markers = (function () {
/**
* Alias of this
* @private
*/
var self = {};
/* Constants */
self.MARK_TYPE_MARKABLE = 'markable';
self.MARK_TYPE_RECEIVED = 'received';
self.MARK_TYPE_DISPLAYED = 'displayed';
self.MARK_TYPE_ACKNOWLEDGED = 'acknowledged';
self.MARK_TYPES = {};
self.MARK_TYPES[self.MARK_TYPE_MARKABLE] = 1;
self.MARK_TYPES[self.MARK_TYPE_RECEIVED] = 1;
self.MARK_TYPES[self.MARK_TYPE_DISPLAYED] = 1;
self.MARK_TYPES[self.MARK_TYPE_ACKNOWLEDGED] = 1;
/**
* Returns whether entity supports message markers
* @public
* @param {string} xid
* @return {boolean}
*/
self.hasSupport = function(xid) {
var has_support = false;
try {
has_support = true ? $('#' + hex_md5(xid)).attr('data-markers') == 'true' : false;
} catch(e) {
Console.error('Markers.hasSupport', e);
} finally {
return has_support;
}
};
/**
* Returns whether request message is marked or not
* @public
* @param {object} message
* @return {boolean}
*/
self.hasRequestMarker = function(message) {
var has_request_marker = false;
try {
has_request_marker = ($(message).find('markable[xmlns="' + NS_URN_MARKERS + '"]').size() ? true : false);
} catch(e) {
Console.error('Markers.hasRequestMarker', e);
} finally {
return has_request_marker;
}
};
/**
* Returns whether response message is marked or not
* @public
* @param {object} message
* @return {boolean}
*/
self.hasResponseMarker = function(message) {
var has_response_marker = false;
try {
var marker_sel = $(message).find('[xmlns="' + NS_URN_MARKERS + '"]');
if(marker_sel.size()) {
var mark_type = marker_sel.prop('tagName').toLowerCase();
switch(mark_type) {
case self.MARK_TYPE_RECEIVED:
case self.MARK_TYPE_DISPLAYED:
case self.MARK_TYPE_ACKNOWLEDGED:
has_response_marker = true;
break;
}
}
} catch(e) {
Console.error('Markers.hasResponseMarker', e);
} finally {
return has_response_marker;
}
};
/**
* Returns the marked message ID
* @public
* @param {object} message
* @return {boolean}
*/
self.getMessageID = function(message) {
var message_id = null;
try {
message_id = $(message).find('[xmlns="' + NS_URN_MARKERS + '"]').attr('id');
} catch(e) {
Console.error('Markers.getMessageID', e);
} finally {
return message_id;
}
};
/**
* Marks a message
* @public
* @param {object} message
* @return {undefined}
*/
self.mark = function(message) {
try {
message.appendNode('markable', {
'xmlns': NS_URN_MARKERS
});
} catch(e) {
Console.error('Markers.mark', e);
}
};
/**
* Changes received message status (once received or read)
* @public
* @param {string} mark_type
* @param {object} message_id
* @return {undefined}
*/
self.change = function(to, mark_type, message_id, message_sel) {
try {
if(!(mark_type in self.MARK_TYPES)) {
throw 'Marker type (' + mark_type + ') not supported, aborting.';
}
// Store mark state
message_sel.attr('data-mark', mark_type);
var message = new JSJaCMessage();
message.setType('chat');
message.setTo(to);
message.appendNode(mark_type, {
'xmlns': NS_URN_MARKERS,
'id': message_id
});
con.send(message);
Console.debug('Markers.change', 'Changed marker to: ' + mark_type + ' for message with ID: ' + message_id + ' from: ' + to);
} catch(e) {
Console.error('Markers.change', e);
}
};
/**
* Handles marker change coming from Carbons
* @public
* @param {string} message
* @return {undefined}
*/
self.handleCarbonChange = function(message) {
try {
// Check the marker element is existing
var marker_sel = $(message).find('[xmlns="' + NS_URN_MARKERS + '"]');
if(marker_sel.size()) {
var xid = Common.bareXID(message.getTo());
var mark_type = marker_sel.prop('tagName').toLowerCase();
var mark_handle = false;
// Filter allowed markers
switch(mark_type) {
case self.MARK_TYPE_RECEIVED:
case self.MARK_TYPE_DISPLAYED:
case self.MARK_TYPE_ACKNOWLEDGED:
mark_handle = true;
break;
}
if(mark_handle === true) {
var mark_message_id = marker_sel.attr('id');
var message_sel = $('#' + hex_md5(xid) + ' .content .one-line[data-mode="him"][data-markable="true"]').filter(function() {
return ($(this).attr('data-id') + '') === (mark_message_id + '');
}).filter(':last');
if(!message_sel.size()) {
Console.warn('Markers.handleCarbonChange', 'Unknown message marker to keep in sync with Carbons for: ' + xid);
return false;
}
// Store mark state
message_sel.attr('data-mark', mark_type);
Console.debug('Markers.handleCarbonChange', 'Received Carbons chat marker (' + mark_type + ') from another resource for: ' + from);
}
}
} catch(e) {
Console.error('Markers.handleCarbonChange', e);
}
};
/**
* Handles a marked message
* @public
* @param {string} from
* @param {object} message
* @param {boolean} is_mam_marker
* @return {undefined}
*/
self.handle = function(from, message, is_mam_marker, is_groupchat_user) {
try {
var xid = ((is_groupchat_user !== true && Common.bareXID(from)) || from);
var marker_sel = $(message).find('[xmlns="' + NS_URN_MARKERS + '"]');
if(marker_sel.size()) {
var mark_type = marker_sel.prop('tagName').toLowerCase();
var mark_message_id = marker_sel.attr('id');
if(is_mam_marker === true) {
mark_message_id += '-mam';
}
// Filter allowed markers
var mark_valid = false;
switch(mark_type) {
case self.MARK_TYPE_RECEIVED:
case self.MARK_TYPE_DISPLAYED:
case self.MARK_TYPE_ACKNOWLEDGED:
mark_valid = true;
break;
}
if(mark_valid === false) {
Console.warn('Markers.handle', 'Dropping unexpected chat marker (' + mark_type + ') from: ' + from);
return false;
}
// Find marked message target
var message_sel = $('#' + hex_md5(xid) + ' .content .one-line[data-mode="me"]').filter(function() {
return ($(this).attr('data-id') + '') === (mark_message_id + '');
}).filter(':last');
if(!message_sel.size()) {
Console.warn('Markers.handle', 'Dropping chat marker (' + mark_type + ') for inexisting message ID (' + mark_message_id + ') from: ' + from);
return false;
}
Console.debug('Markers.handle', 'Received chat marker (' + mark_type + ') from: ' + from);
// Finally display received marker
self._display(xid, message_sel, mark_type);
return true;
}
return false;
} catch(e) {
Console.error('Markers.handle', e);
return false;
}
};
/**
* Adds the markers input events
* @public
* @param {object} target
* @param {string} xid
* @param {string} hash
* @param {string} type
* @return {undefined}
*/
self.events = function(target, xid, hash, type) {
try {
target.focus(function() {
// Not needed
if(target.is(':disabled')) {
return;
}
// Send displayed message marker?
if(type == 'chat' && self.hasSupport(xid) === true) {
var last_message = $('#' + hash + ' .content .one-line.user-message[data-markable="true"]:last');
if(last_message.attr('data-mark') != self.MARK_TYPE_DISPLAYED) {
var last_message_id = last_message.attr('data-id');
var full_xid = Presence.highestPriority(xid) || xid;
if(last_message_id) {
self.change(
full_xid,
self.MARK_TYPE_DISPLAYED,
last_message_id,
last_message
);
}
}
}
});
} catch(e) {
Console.error('Markers.events', e);
}
};
/**
* Displays a marker
* @private
* @param {string} xid
* @param {object} message_sel
* @param {string} mark_type
* @return {boolean}
*/
self._display = function(xid, message_sel, mark_type) {
try {
// Get marker state translation
var marker_sel = message_sel.find('.message-marker');
var mark_message = null;
var css_classes = 'talk-images message-marker-read';
var marker_category = null;
switch(mark_type) {
case self.MARK_TYPE_RECEIVED:
marker_category = 'delivered';
marker_sel.removeClass(css_classes);
marker_sel.text(
Common._e("Delivered")
);
break;
case self.MARK_TYPE_DISPLAYED:
case self.MARK_TYPE_ACKNOWLEDGED:
marker_category = 'read';
marker_sel.addClass(css_classes);
marker_sel.text(
Common._e("Read")
);
break;
default:
return false;
}
if(marker_category !== null) {
marker_sel.attr('data-category', marker_category);
}
// Reset sending state
message_sel.removeClass('is-sending');
// Toggle marker visibility
message_sel.parents('.content').find('.one-line .message-marker').filter(function() {
var data_category = $(this).attr('data-category');
if(data_category != 'delivered' && data_category != 'read') {
return false;
}
// Leave older "read" checkpoint on screen
if(marker_category == 'delivered') {
return data_category == marker_category;
}
return true;
}).hide();
marker_sel.show();
return true;
} catch(e) {
Console.error('Markers._display', e);
return false;
}
};
/**
* Return class scope
*/
return self;
})();

View file

@ -18,7 +18,7 @@ var Me = (function () {
* @private
*/
var self = {};
/**
* Opens the Me tools
@ -29,32 +29,32 @@ var Me = (function () {
try {
// Popup HTML content
var html =
'<div class="top">' + Common._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">' + Common._e("Your profile anywhere on the Web.") + '</p>' +
'<p>' + Common.printf(Common._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>' + Common._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>' + Common._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 genius improvement!") + '</p>' +
'</div>' +
'<a class="go one-button" href="https://me.jappix.com/new" target="_blank">' + Common._e("Yay, let's create your public profile!") + '</a>' +
'</div>' +
'<div class="bottom">' +
'<a href="#" class="finish">' + Common._e("Close") + '</a>' +
var html =
'<div class="top">' + Common._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">' + Common._e("Your profile anywhere on the Web.") + '</p>' +
'<p>' + Common.printf(Common._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>' + Common._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>' + Common._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 genius improvement!") + '</p>' +
'</div>' +
'<a class="go one-button" href="https://me.jappix.com/new" target="_blank">' + Common._e("Yay, let's create your public profile!") + '</a>' +
'</div>' +
'<div class="bottom">' +
'<a href="#" class="finish">' + Common._e("Close") + '</a>' +
'</div>';
// Create the popup
Popup.create('me', html);
// Associate the events
self.instance();
Console.log('Public profile tool opened.');
} catch(e) {
Console.error('Me.open', e);
@ -73,7 +73,7 @@ var Me = (function () {
try {
// Destroy the popup
Popup.destroy('me');
// We finished
Welcome.is_done = false;
} catch(e) {
@ -93,12 +93,14 @@ var Me = (function () {
self.instance = function() {
try {
var me_sel = $('#me');
// Click events
$('#me .content a.go').click(function() {
me_sel.find('.content a.go').click(function() {
self.close();
});
$('#me .bottom .finish').click(self.close);
me_sel.find('.bottom .finish').click(self.close);
} catch(e) {
Console.error('Me.instance', e);
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -31,41 +31,40 @@ var Mobile = (function () {
try {
// Reset the panels
self.resetPanel();
// Get the values
var xid = aForm.xid.value;
var username, domain;
// A domain is specified
if(xid.indexOf('@') != -1) {
username = self.getXIDNick(xid);
domain = self.getXIDHost(xid);
// Domain is locked and not the same
if((LOCK_HOST == 'on') && (domain != HOST_MAIN)) {
self.showThis('error');
return false;
}
}
// No "@" in the XID, we should add the default domain
else {
} else {
// No "@" in the XID, we should add the default domain
username = xid;
domain = HOST_MAIN;
}
var pwd = aForm.pwd.value;
var reg = false;
if(aForm.reg)
if(aForm.reg) {
reg = aForm.reg.checked;
}
// Enough parameters
if(username && domain && pwd) {
// Show the info notification
self.showThis('info');
if(HOST_WEBSOCKET && typeof window.WebSocket != 'undefined') {
// WebSocket supported & configured
con = new JSJaCWebSocketConnection({
@ -73,16 +72,16 @@ var Mobile = (function () {
});
} else {
var httpbase = (HOST_BOSH_MAIN || HOST_BOSH);
// Check BOSH origin
BOSH_SAME_ORIGIN = Origin.isSame(httpbase);
// We create the new http-binding connection
con = new JSJaCHttpBindingConnection({
httpbase: httpbase
});
}
// And we handle everything that happen
con.registerHandler('message', self.handleMessage);
con.registerHandler('presence', self.handlePresence);
@ -90,7 +89,7 @@ var Mobile = (function () {
con.registerHandler('onconnect', self.handleConnected);
con.registerHandler('onerror', self.handleError);
con.registerHandler('ondisconnect', self.handleDisconnected);
// We retrieve what the user typed in the login inputs
oArgs = {};
oArgs.username = username;
@ -104,11 +103,11 @@ var Mobile = (function () {
if(reg) {
oArgs.register = true;
}
// We connect !
con.connect(oArgs);
}
// Not enough parameters
else {
self.showThis('error');
@ -141,6 +140,30 @@ var Mobile = (function () {
};
/**
* Proceeds client initialization
* @public
* @return {undefined}
*/
self.doInitialize = function() {
try {
if(typeof HTTP_AUTH === 'object' &&
HTTP_AUTH.user && HTTP_AUTH.password && HTTP_AUTH.host) {
var form_sel = document.forms['login-form'];
form_sel.elements.xid.value = (HTTP_AUTH.user + '@' + HTTP_AUTH.host);
form_sel.elements.pwd.value = HTTP_AUTH.password;
self.doLogin(form_sel);
}
} catch(e) {
Console.error('Mobile.doInitialize', e);
}
};
/**
* Shows target element
* @public
@ -195,7 +218,7 @@ var Mobile = (function () {
// Hide the opened panels
self.hideThis('info');
self.hideThis('error');
//Show the target panel
if(id) {
self.showThis(id);
@ -217,7 +240,7 @@ var Mobile = (function () {
try {
// 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'));
@ -296,24 +319,25 @@ var Mobile = (function () {
try {
var type = msg.getType();
if(type == 'chat' || type == 'normal') {
// Get the body
var body = msg.getBody();
if(body) {
// Get the values
var xid = self.cutResource(msg.getFrom());
var hash = hex_md5(xid);
var nick = self.getNick(xid, hash);
// No nickname?
if(!nick)
if(!nick) {
nick = xid;
}
// Create the chat if it does not exist
self.chat(xid, nick);
// Display the message
self.displayMessage(xid, body, nick, hash);
}
@ -339,35 +363,31 @@ var Mobile = (function () {
var hash = hex_md5(xid);
var type = pre.getType();
var show = pre.getShow();
// Online buddy: show it!
// Online buddy
if(!type) {
self.showThis('buddy-' + hash);
// Display the correct presence
switch(show) {
case 'chat':
self.displayPresence(hash, show);
break;
case 'away':
self.displayPresence(hash, show);
break;
case 'xa':
self.displayPresence(hash, show);
break;
case 'dnd':
self.displayPresence(hash, show);
break;
default:
self.displayPresence(hash, 'available');
break;
}
} else {
self.hideThis('buddy-' + hash);
}
} catch(e) {
Console.error('Mobile.handlePresence', e);
@ -391,7 +411,7 @@ var Mobile = (function () {
var iqQueryXMLNS = iq.getQueryXMLNS();
var iqType = iq.getType();
var iqQuery;
// Create the response
var iqResponse = new JSJaCIQ();
@ -400,43 +420,43 @@ var Mobile = (function () {
iqResponse.setTo(iqFrom);
iqResponse.setType('result');
}
// Disco#infos query
if((iqQueryXMLNS == NS_DISCO_INFO) && (iqType == 'get')) {
/* REF: http://xmpp.org/extensions/xep-0030.html */
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(var 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 */
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);
}
} catch(e) {
@ -457,27 +477,27 @@ var Mobile = (function () {
// Reset the elements
self.hideThis('home');
self.resetPanel();
// Create the talk page
document.getElementsByTagName('body')[0].innerHTML +=
'<div id="talk">' +
'<div class="header">' +
'<div class="mobile-images"></div>' +
'<button onclick="Mobile.doLogout();">' + self._e("Disconnect") + '</button>' +
'</div>' +
'<div id="roster"></div>' +
'</div>' +
'<div id="chat">' +
'<div class="header">' +
'<div class="mobile-images"></div>' +
'<button onclick="Mobile.returnToRoster();">' + self._e("Previous") + '</button>' +
'</div>' +
'<div id="chans"></div>' +
'<div id="talk">' +
'<div class="header">' +
'<div class="mobile-images"></div>' +
'<button onclick="Mobile.doLogout();">' + self._e("Disconnect") + '</button>' +
'</div>' +
'<div id="roster"></div>' +
'</div>' +
'<div id="chat">' +
'<div class="header">' +
'<div class="mobile-images"></div>' +
'<button onclick="Mobile.returnToRoster();">' + self._e("Previous") + '</button>' +
'</div>' +
'<div id="chans"></div>' +
'</div>';
// Get the roster items
self.getRoster();
} catch(e) {
@ -514,7 +534,7 @@ var Mobile = (function () {
try {
// Reset the elements
self.resetDOM();
// Show the home page
self.showThis('home');
} catch(e) {
@ -536,15 +556,17 @@ var Mobile = (function () {
// Error: send presence anyway
if(!iq || (iq.getType() != 'result'))
return self.sendPresence('', 'available', 1);
// Define some pre-vars
var current, xid, nick, oneBuddy, oneID, hash;
var current, xid, nick, oneBuddy, oneID, hash, cur_buddy;
var roster_buddies = [];
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
@ -552,22 +574,34 @@ var Mobile = (function () {
xid = current.getAttribute('jid').htmlEnc();
nick = current.getAttribute('name');
hash = hex_md5(xid);
// No defined nick?
if(!nick)
if(!nick) {
nick = self.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 Mobile.chat(\'' + self.encodeOnclick(xid) + '\', \'' + self.encodeOnclick(nick) + '\');');
oneBuddy.innerHTML = nick.htmlEnc();
roster.appendChild(oneBuddy);
}
roster_buddies.push({
'xid': xid,
'hash': hash,
'nick': nick
});
}
// Sort the values
self.sortRoster(roster_buddies);
// Display the values
for(var j = 0; j < roster_buddies.length; j++) {
cur_buddy = roster_buddies[j];
self.displayRoster(
roster,
cur_buddy.xid,
cur_buddy.hash,
cur_buddy.nick
);
}
// Start handling buddies presence
self.sendPresence('', 'available', 1);
} catch(e) {
@ -589,7 +623,7 @@ var Mobile = (function () {
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();
@ -597,10 +631,10 @@ var Mobile = (function () {
aMsg.setType('chat');
aMsg.setBody(body);
con.send(aMsg);
// Clear our input
aForm.body.value = '';
// Display the message we sent
self.displayMessage(xid, body, 'me', hash);
}
@ -626,7 +660,7 @@ var Mobile = (function () {
try {
var presence = new JSJaCPresence();
if(type)
presence.setType(type);
if(show)
@ -635,7 +669,7 @@ var Mobile = (function () {
presence.setPriority(priority);
if(status)
presence.setStatus(status);
con.send(presence);
} catch(e) {
Console.error('Mobile.sendPresence', e);
@ -655,7 +689,7 @@ var Mobile = (function () {
iq = new JSJaCIQ();
iq.setType('get');
iq.setQuery(NS_ROSTER);
con.send(iq, self.handleRoster);
} catch(e) {
Console.error('Mobile.getRoster', e);
@ -692,7 +726,7 @@ var Mobile = (function () {
try {
var path = 'buddy-' + hash;
if(self.exists(path)) {
return document.getElementById(path).innerHTML;
} else {
@ -718,15 +752,16 @@ var Mobile = (function () {
try {
// 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)
if(i === 0) {
toStr = toStr.substr(0, index);
else
} else {
toStr = toStr.substr(index + 1);
}
}
// We return the value
return toStr;
} catch(e) {
@ -798,13 +833,13 @@ var Mobile = (function () {
try {
// Encode in HTML
msg = msg.htmlEnc();
// Highlighted text
msg = msg.replace(/(\s|^)\*(.+)\*(\s|$)/gi,'$1<em>$2</em>$3');
// Links
msg = Links.apply(msg, 'mini');
return msg;
} catch(e) {
Console.error('Mobile.filter', e);
@ -827,19 +862,20 @@ var Mobile = (function () {
try {
// Get the path
var path = 'content-' + hash;
// Display the message
html = '<span><b';
if(nick == 'me')
if(nick == 'me') {
html += ' class="me">' + self._e("You");
else
} else {
html += ' class="him">' + nick;
}
html += '</b> ' + self.filter(body) + '</span>';
document.getElementById(path).innerHTML += html;
// Scroll to the last element
document.getElementById(path).lastChild.scrollIntoView();
} catch(e) {
@ -849,6 +885,61 @@ var Mobile = (function () {
};
/**
* Displays a roster buddy
* @public
* @param {object} roster
* @param {string} xid
* @param {string} hash
* @param {string} nick
* @return {undefined}
*/
self.displayRoster = function(roster, xid, hash, nick) {
try {
oneBuddy = document.createElement('a');
oneID = 'buddy-' + hash;
oneBuddy.setAttribute('href', '#');
oneBuddy.setAttribute('id', oneID);
oneBuddy.setAttribute('class', 'one-buddy');
oneBuddy.setAttribute('onclick', 'return Mobile.chat(\'' + self.encodeOnclick(xid) + '\', \'' + self.encodeOnclick(nick) + '\');');
oneBuddy.innerHTML = nick.htmlEnc();
roster.appendChild(oneBuddy);
} catch(e) {
Console.error('Mobile.displayRoster', e);
}
};
/**
* Sorts the roster buddies by nickname
* @public
* @param {object} roster_buddies
* @return {object}
*/
self.sortRoster = function(roster_buddies) {
try {
var one_nick, two_nick;
roster_buddies.sort(function(one, two) {
one_nick = (one.nick + '').toLowerCase();
two_nick = (two.nick + '').toLowerCase();
return one_nick < two_nick ? -1 : (one_nick > two_nick ? 1 : 0);
});
} catch(e) {
Console.error('Mobile.sortRoster', e);
} finally {
return roster_buddies;
}
};
/**
* Goes back to roster view
* @public
@ -859,7 +950,7 @@ var Mobile = (function () {
try {
// Hide the chats
self.hideThis('chat');
// Show the roster
self.showThis('talk');
} catch(e) {
@ -880,15 +971,16 @@ var Mobile = (function () {
try {
// Hide the roster page
self.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')
if(divs.item(i).getAttribute('class') == 'one-chat') {
divs.item(i).style.display = 'none';
}
}
// Show the chat
self.showThis('chat');
self.showThis(hash);
@ -913,7 +1005,7 @@ var Mobile = (function () {
// 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');
@ -937,17 +1029,18 @@ var Mobile = (function () {
try {
var hash = hex_md5(xid);
// If the chat was not yet opened
if(!self.exists('chat-' + hash)) {
// No nick?
if(!nick)
if(!nick) {
nick = self.getNick(xid, hash);
}
// Create the chat
self.createChat(xid, nick, hash);
}
// Switch to the chat
self.chatSwitch('chat-' + hash);
} catch(e) {
@ -990,6 +1083,7 @@ var Mobile = (function () {
try {
onbeforeunload = self.doLogout;
onload = self.doInitialize;
} catch(e) {
Console.error('Mobile.launch', e);
}

View file

@ -31,129 +31,130 @@ var MUCAdmin = (function () {
try {
// Popup HTML content
var html_full =
'<div class="top">' + Common._e("MUC administration") + '</div>' +
'<div class="content">' +
'<div class="head mucadmin-head">' +
'<div class="head-text mucadmin-head-text">' + Common._e("You administrate this room") + '</div>' +
'<div class="mucadmin-head-jid">' + xid + '</div>' +
'</div>' +
'<div class="mucadmin-forms">' +
'<div class="mucadmin-topic">' +
'<fieldset>' +
'<legend>' + Common._e("Subject") + '</legend>' +
'<label for="topic-text">' + Common._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>' + Common._e("Configuration") + '</legend>' +
'<div class="results mucadmin-results"></div>' +
'</fieldset>' +
'</div>' +
'<div class="mucadmin-aut">' +
'<fieldset>' +
'<legend>' + Common._e("Authorizations") + '</legend>' +
'<label>' + Common._e("Member list") + '</label>' +
'<div class="aut-member aut-group">' +
'<a href="#" class="aut-add" onclick="return MUCAdmin.addInput(\'\', \'member\');">' + Common._e("Add an input") + '</a>' +
'</div>' +
'<label>' + Common._e("Owner list") + '</label>' +
'<div class="aut-owner aut-group">' +
'<a href="#" class="aut-add" onclick="return MUCAdmin.addInput(\'\', \'owner\');">' + Common._e("Add an input") + '</a>' +
'</div>' +
'<label>' + Common._e("Administrator list") + '</label>' +
'<div class="aut-admin aut-group">' +
'<a href="#" class="aut-add" onclick="return MUCAdmin.addInput(\'\', \'admin\');">' + Common._e("Add an input") + '</a>' +
'</div>' +
'<label>' + Common._e("Outcast list") + '</label>' +
'<div class="aut-outcast aut-group">' +
'<a href="#" class="aut-add" onclick="return MUCAdmin.addInput(\'\', \'outcast\');">' + Common._e("Add an input") + '</a>' +
'</div>' +
'</fieldset>' +
'</div>' +
'<div class="mucadmin-others">' +
'<fieldset>' +
'<legend>' + Common._e("Others") + '</legend>' +
'<label>' + Common._e("Destroy this MUC") + '</label>' +
'<a href="#" onclick="return MUCAdmin.destroy();">' + Common._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">' + Common._e("Save") + '</a>' +
'<a href="#" class="finish cancel">' + Common._e("Cancel") + '</a>' +
var html_full =
'<div class="top">' + Common._e("MUC administration") + '</div>' +
'<div class="content">' +
'<div class="head mucadmin-head">' +
'<div class="head-text mucadmin-head-text">' + Common._e("You administrate this room") + '</div>' +
'<div class="mucadmin-head-jid">' + xid + '</div>' +
'</div>' +
'<div class="mucadmin-forms">' +
'<div class="mucadmin-topic">' +
'<fieldset>' +
'<legend>' + Common._e("Subject") + '</legend>' +
'<label for="topic-text">' + Common._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>' + Common._e("Configuration") + '</legend>' +
'<div class="results mucadmin-results"></div>' +
'</fieldset>' +
'</div>' +
'<div class="mucadmin-aut">' +
'<fieldset>' +
'<legend>' + Common._e("Authorizations") + '</legend>' +
'<label>' + Common._e("Member list") + '</label>' +
'<div class="aut-member aut-group">' +
'<a href="#" class="aut-add" onclick="return MUCAdmin.addInput(\'\', \'member\');">' + Common._e("Add an input") + '</a>' +
'</div>' +
'<label>' + Common._e("Owner list") + '</label>' +
'<div class="aut-owner aut-group">' +
'<a href="#" class="aut-add" onclick="return MUCAdmin.addInput(\'\', \'owner\');">' + Common._e("Add an input") + '</a>' +
'</div>' +
'<label>' + Common._e("Administrator list") + '</label>' +
'<div class="aut-admin aut-group">' +
'<a href="#" class="aut-add" onclick="return MUCAdmin.addInput(\'\', \'admin\');">' + Common._e("Add an input") + '</a>' +
'</div>' +
'<label>' + Common._e("Outcast list") + '</label>' +
'<div class="aut-outcast aut-group">' +
'<a href="#" class="aut-add" onclick="return MUCAdmin.addInput(\'\', \'outcast\');">' + Common._e("Add an input") + '</a>' +
'</div>' +
'</fieldset>' +
'</div>' +
'<div class="mucadmin-others">' +
'<fieldset>' +
'<legend>' + Common._e("Others") + '</legend>' +
'<label>' + Common._e("Destroy this MUC") + '</label>' +
'<a href="#" onclick="return MUCAdmin.destroy();">' + Common._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">' + Common._e("Save") + '</a>' +
'<a href="#" class="finish cancel">' + Common._e("Cancel") + '</a>' +
'</div>';
var html_partial =
'<div class="top">' + Common._e("MUC administration") + '</div>' +
'<div class="content">' +
'<div class="head mucadmin-head">' +
'<div class="head-text mucadmin-head-text">' + Common._e("You administrate this room") + '</div>' +
'<div class="mucadmin-head-jid">' + xid + '</div>' +
'</div>' +
'<div class="mucadmin-forms">' +
'<div class="mucadmin-aut">' +
'<fieldset>' +
'<legend>' + Common._e("Authorizations") + '</legend>' +
'<label>' + Common._e("Member list") + '</label>' +
'<div class="aut-member aut-group">' +
'<a href="#" class="aut-add" onclick="return MUCAdmin.addInput(\'\', \'member\');">' + Common._e("Add an input") + '</a>' +
'</div>' +
'<label>' + Common._e("Outcast list") + '</label>' +
'<div class="aut-outcast aut-group">' +
'<a href="#" class="aut-add" onclick="return MUCAdmin.addInput(\'\', \'outcast\');">' + Common._e("Add an input") + '</a>' +
'</div>' +
'</fieldset>' +
'</div>' +
'</div>' +
'</div>' +
'<div class="bottom">' +
'<div class="wait wait-medium"></div>' +
'<a href="#" class="finish save">' + Common._e("Save") + '</a>' +
'<a href="#" class="finish cancel">' + Common._e("Cancel") + '</a>' +
'</div>';
var html_partial =
'<div class="top">' + Common._e("MUC administration") + '</div>' +
'<div class="content">' +
'<div class="head mucadmin-head">' +
'<div class="head-text mucadmin-head-text">' + Common._e("You administrate this room") + '</div>' +
'<div class="mucadmin-head-jid">' + xid + '</div>' +
'</div>' +
'<div class="mucadmin-forms">' +
'<div class="mucadmin-aut">' +
'<fieldset>' +
'<legend>' + Common._e("Authorizations") + '</legend>' +
'<label>' + Common._e("Member list") + '</label>' +
'<div class="aut-member aut-group">' +
'<a href="#" class="aut-add" onclick="return MUCAdmin.addInput(\'\', \'member\');">' + Common._e("Add an input") + '</a>' +
'</div>' +
'<label>' + Common._e("Outcast list") + '</label>' +
'<div class="aut-outcast aut-group">' +
'<a href="#" class="aut-add" onclick="return MUCAdmin.addInput(\'\', \'outcast\');">' + Common._e("Add an input") + '</a>' +
'</div>' +
'</fieldset>' +
'</div>' +
'</div>' +
'</div>' +
'<div class="bottom">' +
'<div class="wait wait-medium"></div>' +
'<a href="#" class="finish save">' + Common._e("Save") + '</a>' +
'<a href="#" class="finish cancel">' + Common._e("Cancel") + '</a>' +
'</div>';
// Create the popup
if(aff == 'owner')
Popup.create('mucadmin', html_full);
if(aff == 'admin')
Popup.create('mucadmin', html_partial);
// Associate the events
self.instance();
// We get the affiliated user's privileges
if(aff == 'owner') {
self.query(xid, 'member');
self.query(xid, 'owner');
self.query(xid, 'admin');
self.query(xid, 'outcast');
// We query the room to edit
DataForm.go(xid, 'muc', '', '', 'mucadmin');
} else if(aff == 'admin') {
@ -196,10 +197,10 @@ var MUCAdmin = (function () {
try {
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');
} catch(e) {
@ -222,20 +223,20 @@ var MUCAdmin = (function () {
try {
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 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 self.removeInput(this);
});
// Focus on the input we added
if(!xid) {
$(document).oneTime(10, function() {
@ -265,14 +266,14 @@ var MUCAdmin = (function () {
// We parse the received xml
var xid = $(this).attr('jid');
var affiliation = $(this).attr('affiliation');
// We create one input for one XID
self.addInput(xid, affiliation);
});
// Hide the wait icon
$('#mucadmin .wait').hide();
Console.log('MUC admin items received: ' + Common.fullXID(Common.getStanzaFrom(iq)));
} catch(e) {
Console.error('MUCAdmin.handleAuth', e);
@ -293,16 +294,16 @@ var MUCAdmin = (function () {
try {
// 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, self.handleAuth);
} catch(e) {
Console.error('MUCAdmin.query', e);
@ -322,7 +323,7 @@ var MUCAdmin = (function () {
try {
// 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();
@ -330,7 +331,7 @@ var MUCAdmin = (function () {
m.setType('groupchat');
m.setSubject(topic);
con.send(m);
Console.info('MUC admin topic sent: ' + topic);
}
} catch(e) {
@ -355,7 +356,7 @@ var MUCAdmin = (function () {
$.each(types, function(i) {
// We get the current type
var tType = types[i];
// We loop for all the elements
$('.mucadmin-aut .aut-' + tType + ' input').each(function() {
// We get the needed values
@ -368,7 +369,7 @@ var MUCAdmin = (function () {
}
});
});
Console.info('MUC admin authorizations form sent: ' + xid);
} catch(e) {
Console.error('MUCAdmin.sendAuth', e);
@ -397,13 +398,13 @@ var MUCAdmin = (function () {
iq.setType('set');
var iqQuery = iq.setQuery(NS_MUC_ADMIN);
var item = iqQuery.appendChild(iq.buildNode('item', {
'jid': user_xid,
'affiliation': affiliation,
'xmlns': NS_MUC_ADMIN
}));
con.send(iq, Errors.handleReply);
} catch(e) {
Console.error('MUCAdmin.setAffiliation', e);
@ -426,20 +427,21 @@ var MUCAdmin = (function () {
var room = Common.fullXID(Common.getStanzaFrom(iq));
var hash = hex_md5(room);
Interface.quitThisChat(room, hash, 'groupchat');
// We close the muc admin popup
self.close();
// We tell the user that all is okay
Board.openThisInfo(5);
// We remove the user's favorite
if(DataStore.existDB('favorites', room))
if(DataStore.existDB(Connection.desktop_hash, 'favorites', room)) {
Favorites.removeThis(room, Common.explodeThis('@', room, 0));
}
Console.info('MUC admin destroyed: ' + room);
}
// We hide the wait icon
$('#mucadmin .wait').hide();
} catch(e) {
@ -460,14 +462,14 @@ var MUCAdmin = (function () {
try {
// 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, self.handleDestroyIQ);
Console.info('MUC admin destroy sent: ' + xid);
} catch(e) {
Console.error('MUCAdmin.destroyIQ', e);
@ -488,10 +490,10 @@ var MUCAdmin = (function () {
try {
// 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
self.destroyIQ(xid);
} catch(e) {
@ -511,10 +513,10 @@ var MUCAdmin = (function () {
try {
// We get the XID of the current room
var xid = $('#mucadmin .mucadmin-head-jid').text();
// We change the room topic
self.sendTopic(xid);
// We send the needed queries
DataForm.send('x', 'submit', 'submit', $('#mucadmin .mucadmin-results').attr('data-session'), xid, '', '', 'mucadmin');
self.sendAuth(xid);
@ -535,7 +537,7 @@ var MUCAdmin = (function () {
try {
// We send the new options
self.send();
// And we quit the popup
return self.close();
} catch(e) {
@ -555,10 +557,13 @@ var MUCAdmin = (function () {
try {
// Click events
$('#mucadmin .bottom .finish').click(function() {
if($(this).is('.cancel'))
if($(this).is('.cancel')) {
return self.close();
if($(this).is('.save'))
}
if($(this).is('.save')) {
return self.save();
}
});
} catch(e) {
Console.error('MUCAdmin.instance', e);

File diff suppressed because it is too large Load diff

View file

@ -29,10 +29,10 @@ var Music = (function () {
try {
var path = '.music-content';
// Show the music bubble
Bubble.show(path);
$(document).oneTime(10, function() {
$(path + ' input').focus();
});
@ -58,71 +58,70 @@ var Music = (function () {
var path = '.music-content ';
var content = path + '.list';
var path_type = content + ' .' + type;
// Create the result container
if(!Common.exists(path_type)) {
var code = '<div class="' + type + '"></div>';
if(type == 'local')
if(type == 'local') {
$(content).prepend(code);
else
} 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';
var this_sel = $(this);
var id = this_sel.find('id').text() || hex_md5(uri);
var title = this_sel.find('name').text();
var artist = this_sel.find('artist').text();
var source = this_sel.find('source').text();
var duration = this_sel.find('duration').text();
var uri = this_sel.find('url').text();
var mime = this_sel.find('type').text() || 'audio/ogg';
// Local URL?
if(type == 'local')
if(type == 'local') {
uri = Utils.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(Common.exists('.music-audio[data-id="' + id + '"]'))
if(Common.exists('.music-audio[data-id="' + id + '"]')) {
current_song.addClass('playing');
}
// Click event
current_song.click(function() {
return self.add(id, title, artist, source, duration, uri, mime, type);
});
});
// The search is finished
if(Common.exists(content + ' .jamendo') && Common.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)
if(!jamendo && !local) {
$(path + '.no-results').show();
}
// We must put a separator between the categories
if(jamendo && local)
if(jamendo && local) {
$(content + ' .local').addClass('special');
}
}
} catch(e) {
Console.error('Music.parse', e);
@ -140,24 +139,27 @@ var Music = (function () {
try {
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('./server/music-search.php', {searchquery: string, location: 'jamendo'}, function(data) {
self.parse(data, 'jamendo');
});
// Get the local results
$.get('./server/music-search.php', {searchquery: string, location: JAPPIX_LOCATION}, function(data) {
$.get('./server/music-search.php', {
searchquery: string,
location: JAPPIX_LOCATION
}, function(data) {
self.parse(data, 'local');
});
} catch(e) {
@ -177,35 +179,37 @@ var Music = (function () {
try {
// Initialize
var playThis = document.getElementById('top-content').getElementsByTagName('audio')[0];
var audio_sel = document.getElementById('top-content').getElementsByTagName('audio')[0];
// Nothing to play, exit
if(!playThis)
if(!audio_sel) {
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() {
audio_sel.load();
audio_sel.play();
audio_sel.addEventListener('ended', function() {
self.action('stop');
}, true);
}, true);
Console.log('Music is now playing.');
}
// User stop the song or the song came to its end
else if(action == 'stop') {
} else if(action == 'stop') {
// User stop the song / end of song
stopButton.hide();
playThis.pause();
audio_sel.pause();
$('#top-content .music').removeClass('actived');
$('.music-content .list a').removeClass('playing');
$('.music-audio').remove();
self.publish();
Console.log('Music is now stopped.');
}
} catch(e) {
@ -236,42 +240,39 @@ var Music = (function () {
if(Features.enabledPEP()) {
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
);
var music_data = {
'title': title,
'artist': artist,
'source': source,
'length': length,
'uri': uri
};
// Create the children nodes
for(var i in nodes) {
if(values[i]) {
tune.appendChild(iq.buildNode(nodes[i], {'xmlns': NS_TUNE}, values[i]));
var cur_value;
for(var cur_name in music_data) {
cur_value = music_data[cur_name];
if(cur_value) {
tune.appendChild(iq.buildNode(cur_name, {
'xmlns': NS_TUNE
}, cur_value));
}
}
}
con.send(iq);
Console.info('New tune sent: ' + title);
}
} catch(e) {
@ -298,27 +299,29 @@ var Music = (function () {
try {
var path = '.music-content ';
var music_audio_sel = $('.music-audio');
// We remove & create a new audio tag
$('.music-audio').remove();
music_audio_sel.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);
if(type == 'jamendo') {
music_audio_sel.attr('src', 'http://api.jamendo.com/get2/stream/track/redirect/?id=' + id + '&streamencoding=ogg2');
} else {
music_audio_sel.attr('src', uri);
}
// We play the target sound
self.action('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
self.publish(title, artist, source, duration, uri);
} catch(e) {
@ -345,7 +348,7 @@ var Music = (function () {
if(e.keyCode == 13 && $(this).val()) {
self.search();
}
// Escape : quit
if(e.keyCode == 27) {
Bubble.close();

View file

@ -32,9 +32,9 @@ var Name = (function () {
var iq = new JSJaCIQ();
iq.setType('get');
iq.setTo(xid);
iq.appendNode('vCard', {'xmlns': NS_VCARD});
con.send(iq, self.handleAddUser);
} catch(e) {
Console.error('Name.getAddUser', e);
@ -53,18 +53,20 @@ var Name = (function () {
try {
// Was it an obsolete request?
if(!Common.exists('.add-contact-name-get[data-for="' + escape(Common.bareXID(Common.getStanzaFrom(iq))) + '"]'))
if(!Common.exists('.add-contact-name-get[data-for="' + escape(Common.bareXID(Common.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 = self.generateBuddy(iq)[0];
if(full_name)
if(full_name) {
$('.add-contact-name').val(full_name);
}
}
} catch(e) {
Console.error('Name.handleAddUser', e);
@ -85,29 +87,30 @@ var Name = (function () {
try {
// Get the IQ content
var xml = $(iq.getNode()).find('vCard');
var vcard_sel = $(iq.getNode()).find('vCard');
// Get the full name & the nickname
var pFull = xml.find('FN:first').text();
var pNick = xml.find('NICKNAME:first').text();
var pFull = vcard_sel.find('FN:first').text();
var pNick = vcard_sel.find('NICKNAME:first').text();
// No full name?
if(!pFull) {
// Get the given name
var pN = xml.find('N:first');
var pN = vcard_sel.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)
if(pFamily) {
pFull += ' ' + pFamily;
}
}
}
return [pFull, pNick];
} catch(e) {
Console.error('Name.generateBuddy', e);
@ -127,29 +130,29 @@ var Name = (function () {
try {
// Initialize
var cname, bname;
// Cut the XID resource
xid = Common.bareXID(xid);
// This is me?
if(Utils.isAnonymous() && !xid)
if(Utils.isAnonymous() && !xid) {
bname = Common._e("You");
else if(xid == Common.getXID())
} else if(xid == Common.getXID()) {
bname = self.get();
}
// Not me!
else {
cname = $('#roster .buddy[data-xid="' + escape(xid) + '"]:first .buddy-name').html();
// If the complete name exists
if(cname)
// Complete name exists?
if(cname) {
bname = cname.revertHtmlEnc();
// Else, we just get the nickname of the buddy
else
} else {
bname = Common.getXIDNick(xid);
}
}
return bname;
} catch(e) {
Console.error('Name.getBuddy', e);
@ -168,11 +171,12 @@ var Name = (function () {
try {
// Try to read the user nickname
var nick = DataStore.getDB(Connection.desktop_hash, 'profile', 'nick');
// No nick?
if(!nick)
if(!nick) {
nick = con.username;
}
return nick;
} catch(e) {
Console.error('Name.getNick', e);
@ -191,11 +195,12 @@ var Name = (function () {
try {
// Try to read the user name
var name = DataStore.getDB(Connection.desktop_hash, 'profile', 'name');
// No name? Use the nickname instead!
if(!name)
// No name? Use the nickname instead
if(!name) {
name = self.getNick();
}
return name;
} catch(e) {
Console.error('Name.get', e);

View file

@ -50,29 +50,26 @@ var Notification = (function () {
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 {
} else {
$(empty).hide();
$(nothing).show();
// Purge the social inbox node
self.purge();
}
// Update the page title
Interface.updateTitle();
} catch(e) {
@ -96,142 +93,144 @@ var Notification = (function () {
self.create = function(type, from, data, body, id, inverse) {
try {
if(!type || !from)
if(!type || !from) {
return;
}
// Generate an ID hash
if(!id) {
id = hex_md5(type + from);
}
// Generate the text to be displayed
var text, action, code;
var yes_path = 'href="#"';
// User things
from = Common.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> ' + Common._e("would like to add you as a friend.") + ' ' + Common._e("Do you accept?");
break;
case 'invite_room':
text = '<b>' + Name.getBuddy(from).htmlEnc() + '</b> ' + Common._e("would like you to join this chatroom:") + ' <em>' + data[0].htmlEnc() + '</em> ' + Common._e("Do you accept?");
break;
case 'request':
text = '<b>' + from.htmlEnc() + '</b> ' + Common._e("would like to get authorization.") + ' ' + Common._e("Do you accept?");
break;
case 'send':
yes_path = 'href="' + Common.encodeQuotes(data[1]) + '" target="_blank"';
text = '<b>' + Name.getBuddy(from).htmlEnc() + '</b> ' + Common.printf(Common._e("would like to send you a file: “%s”.").htmlEnc(), '<em>' + Utils.truncate(body, 25).htmlEnc() + '</em>') + ' ' + Common._e("Do you accept?");
break;
case 'send_pending':
text = '<b>' + Name.getBuddy(from).htmlEnc() + '</b> ' + Common.printf(Common._e("has received a file exchange request: “%s”.").htmlEnc(), '<em>' + Utils.truncate(body, 25).htmlEnc() + '</em>');
break;
case 'send_accept':
text = '<b>' + Name.getBuddy(from).htmlEnc() + '</b> ' + Common.printf(Common._e("has accepted to receive your file: “%s”.").htmlEnc(), '<em>' + Utils.truncate(body, 25).htmlEnc() + '</em>');
break;
case 'send_reject':
text = '<b>' + Name.getBuddy(from).htmlEnc() + '</b> ' + Common.printf(Common._e("has rejected to receive your file: “%s”.").htmlEnc(), '<em>' + Utils.truncate(body, 25).htmlEnc() + '</em>');
break;
case 'send_fail':
text = '<b>' + Name.getBuddy(from).htmlEnc() + '</b> ' + Common.printf(Common._e("could not receive your file: “%s”.").htmlEnc(), '<em>' + Utils.truncate(body, 25).htmlEnc() + '</em>');
break;
case 'rosterx':
text = Common.printf(Common._e("Do you want to see the friends %s suggests you?").htmlEnc(), '<b>' + Name.getBuddy(from).htmlEnc() + '</b>');
break;
case 'comment':
text = '<b>' + data[0].htmlEnc() + '</b> ' + Common.printf(Common._e("commented an item you follow: “%s”.").htmlEnc(), '<em>' + Utils.truncate(body, 25).htmlEnc() + '</em>');
break;
case 'like':
text = '<b>' + data[0].htmlEnc() + '</b> ' + Common.printf(Common._e("liked your post: “%s”.").htmlEnc(), '<em>' + Utils.truncate(body, 25).htmlEnc() + '</em>');
break;
case 'quote':
text = '<b>' + data[0].htmlEnc() + '</b> ' + Common.printf(Common._e("quoted you somewhere: “%s”.").htmlEnc(), '<em>' + Utils.truncate(body, 25).htmlEnc() + '</em>');
break;
case 'wall':
text = '<b>' + data[0].htmlEnc() + '</b> ' + Common.printf(Common._e("published on your wall: “%s”.").htmlEnc(), '<em>' + Utils.truncate(body, 25).htmlEnc() + '</em>');
break;
case 'photo':
text = '<b>' + data[0].htmlEnc() + '</b> ' + Common.printf(Common._e("tagged you in a photo (%s).").htmlEnc(), '<em>' + Utils.truncate(body, 25).htmlEnc() + '</em>');
break;
case 'video':
text = '<b>' + data[0].htmlEnc() + '</b> ' + Common.printf(Common._e("tagged you in a video (%s).").htmlEnc(), '<em>' + Utils.truncate(body, 25).htmlEnc() + '</em>');
break;
case 'me_profile_new_success':
yes_path = 'href="' + Common.encodeQuotes(data[1]) + '" target="_blank"';
text = '<b>' + data[0].htmlEnc() + '</b> ' + Common._e("validated your account. Your public profile will be available in a few moments.").htmlEnc();
break;
case 'me_profile_remove_success':
yes_path = 'href="' + Common.encodeQuotes(data[1]) + '" target="_blank"';
text = '<b>' + data[0].htmlEnc() + '</b> ' + Common._e("has removed your public profile after your request. We will miss you!").htmlEnc();
break;
case 'me_profile_update_success':
yes_path = 'href="' + Common.encodeQuotes(data[1]) + '" target="_blank"';
text = '<b>' + data[0].htmlEnc() + '</b> ' + Common._e("has saved your new public profile settings. They will be applied in a few moments.").htmlEnc();
break;
case 'me_profile_check_error':
yes_path = 'href="' + Common.encodeQuotes(data[1]) + '" target="_blank"';
text = '<b>' + data[0].htmlEnc() + '</b> ' + Common._e("could not validate your account to create or update your public profile. Check your credentials.").htmlEnc();
break;
default:
break;
}
// No text?
if(!text)
if(!text) {
return;
}
// Action links?
switch(type) {
// Hide/Show actions
@ -248,8 +247,9 @@ var Notification = (function () {
action = '<a href="#" class="no">' + Common._e("Hide") + '</a>';
// Any parent link?
if((type == 'comment') && data[2])
if((type == 'comment') && data[2]) {
action = '<a href="#" class="yes">' + Common._e("Show") + '</a>' + action;
}
break;
@ -266,53 +266,55 @@ var Notification = (function () {
default:
action = '<a ' + yes_path + ' class="yes">' + Common._e("Yes") + '</a><a href="#" class="no">' + Common._e("No") + '</a>';
}
if(text) {
// We display the notification
if(!Common.exists('.notifications-content .' + id)) {
// We create the html markup depending of the notification type
code = '<div class="one-notification ' + id + ' ' + hash + '" title="' + Common.encodeQuotes(body) + ' - ' + Common._e("This notification is only informative, maybe the data it links to have been removed.") + '" data-type="' + Common.encodeQuotes(type) + '">' +
'<div class="avatar-container">' +
'<img class="avatar" src="' + './images/others/default-avatar.png' + '" alt="" />' +
'</div>' +
'<p class="notification-text">' + text + '</p>' +
'<p class="notification-actions">' +
'<span class="talk-images" />' +
action +
'</p>' +
code = '<div class="one-notification ' + id + ' ' + hash + '" title="' + Common.encodeQuotes(body) + ' - ' + Common._e("This notification is only informative, maybe the data it links to have been removed.") + '" data-type="' + Common.encodeQuotes(type) + '">' +
'<div class="avatar-container">' +
'<img class="avatar" src="' + './images/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)
if(inverse) {
$('.notifications-content .nothing').before(code);
else
} else {
$('.notifications-content .empty').after(code);
}
// Play a sound to alert the user
Audio.play('notification');
// The yes click function
$('.' + id + ' a.yes').click(function() {
self.action(type, data, 'yes', id);
if(($(this).attr('href') == '#') && ($(this).attr('target') != '_blank'))
if(($(this).attr('href') == '#') && ($(this).attr('target') != '_blank')) {
return false;
}
});
// The no click function
$('.' + id + ' a.no').click(function() {
return self.action(type, data, 'no', id);
});
// Get the user avatar
Avatar.get(from, 'cache', 'true', 'forget');
}
}
// We tell the user he has a new pending notification
self.check();
Console.info('New notification: ' + from);
} catch(e) {
Console.error('Notification.new', e);
@ -334,42 +336,37 @@ var Notification = (function () {
try {
// We launch a function depending of the type
if((type == 'subscribe') && (value == 'yes'))
if((type == 'subscribe') && (value == 'yes')) {
Presence.acceptSubscribe(data[0], data[1]);
else if((type == 'subscribe') && (value == 'no'))
} else if((type == 'subscribe') && (value == 'no')) {
Presence.sendSubscribe(data[0], 'unsubscribed');
else if((type == 'invite_room') && (value == 'yes'))
} else if((type == 'invite_room') && (value == 'yes')) {
Chat.checkCreate(data[0], 'groupchat');
else if(type == 'request')
} else if(type == 'request') {
HTTPReply.go(value, data[0]);
if((type == 'send') && (value == 'yes'))
}
if((type == 'send') && (value == 'yes')) {
OOB.reply(data[0], data[3], 'accept', data[2], data[4]);
else if((type == 'send') && (value == 'no'))
} else if((type == 'send') && (value == 'no')) {
OOB.reply(data[0], data[3], 'reject', data[2], data[4]);
else if((type == 'rosterx') && (value == 'yes'))
} else if((type == 'rosterx') && (value == 'yes')) {
RosterX.open(data[0]);
else if((type == 'comment') || (type == 'like') || (type == 'quote') || (type == 'wall') || (type == 'photo') || (type == 'video')) {
} else if((type == 'comment') || (type == 'like') || (type == 'quote') || (type == 'wall') || (type == 'photo') || (type == 'video')) {
if(value == 'yes') {
// Get the microblog item
Microblog.fromInfos(data[2]);
// Append the marker
$('#channel .top.individual').append('<input type="hidden" name="comments" value="' + Common.encodeQuotes(data[1]) + '" />');
}
self.remove(data[3]);
}
// We remove the notification
$('.notifications-content .' + id).remove();
// We check if there's any other pending notification
self.closeEmpty();
self.check();
@ -392,7 +389,7 @@ var Notification = (function () {
try {
// Remove notifications
$('.one-notification').remove();
// Refresh
self.closeEmpty();
self.check();
@ -415,12 +412,12 @@ var Notification = (function () {
try {
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, self.handle);
Console.log('Getting social notifications...');
} catch(e) {
Console.error('Notification.get', e);
@ -442,40 +439,44 @@ var Notification = (function () {
if((stanza.getType() == 'error') && $(stanza.getNode()).find('item-not-found').size()) {
// The node may not exist, create it!
Pubsub.setup('', NS_URN_INBOX, '1', '1000000', 'whitelist', 'open', true);
Console.warn('Error while getting social notifications, trying to reconfigure the Pubsub node!');
}
// Selector
var items = $(stanza.getNode()).find('item');
// Should we inverse?
var inverse = true;
if(items.size() == 1)
if(items.size() == 1) {
inverse = false;
}
// Parse notifications
items.each(function() {
var this_sel = $(this);
// 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 = Common.explodeThis(':', $(this).find('author uri').text(), 1);
var current_name = $(this).find('author name').text();
var current_text = $(this).find('content[type="text"]:first').text();
var current_item = this_sel.attr('id');
var current_type = this_sel.find('link[rel="via"]:first').attr('title');
var current_href = this_sel.find('link[rel="via"]:first').attr('href');
var current_parent_href = this_sel.find('link[rel="related"]:first').attr('href');
var current_xid = Common.explodeThis(':', this_sel.find('author uri').text(), 1);
var current_name = this_sel.find('author name').text();
var current_text = this_sel.find('content[type="text"]:first').text();
var current_bname = Name.getBuddy(current_xid);
var current_id = hex_md5(current_type + current_xid + current_href + current_text);
// Choose the good name!
if(!current_name || (current_bname != Common.getXIDNick(current_xid)))
if(!current_name || (current_bname != Common.getXIDNick(current_xid))) {
current_name = current_bname;
}
// Create it!
self.create(current_type, current_xid, [current_name, current_href, current_parent_href, current_item], current_text, current_id, inverse);
});
Console.info(items.size() + ' social notification(s) got!');
} catch(e) {
Console.error('Notification.handle', e);
@ -499,38 +500,38 @@ var Notification = (function () {
try {
// Notification ID
var id = hex_md5(xid + text + DateUtils.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 author = entry.appendChild(iq.buildNode('author', {'xmlns': NS_ATOM}));
author.appendChild(iq.buildNode('name', {'xmlns': NS_ATOM}, Name.get()));
author.appendChild(iq.buildNode('uri', {'xmlns': NS_ATOM}, 'xmpp:' + Common.getXID()));
// Notification content
entry.appendChild(iq.buildNode('published', {'xmlns': NS_ATOM}, DateUtils.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);
Console.log('Sending a social notification to ' + xid + ' (type: ' + type + ')...');
} catch(e) {
Console.error('Notification.send', e);
@ -550,11 +551,11 @@ var Notification = (function () {
try {
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);
} catch(e) {
Console.error('Notification.remove', e);
@ -574,10 +575,10 @@ var Notification = (function () {
try {
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);
} catch(e) {
Console.error('Notification.purge', e);
@ -598,12 +599,12 @@ var Notification = (function () {
try {
// 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);
} catch(e) {

View file

@ -37,41 +37,42 @@ var OOB = (function () {
// Get some values
var id = hex_md5(genID() + to + url + desc);
to = Caps.getFeatureResource(to, NS_IQOOB);
// IQs cannot be sent to offline users
if(!to)
if(!to) {
return;
}
// Register the ID
DataStore.setDB(Connection.desktop_hash, 'send/url', id, url);
DataStore.setDB(Connection.desktop_hash, 'send/desc', id, desc);
var aIQ = new JSJaCIQ();
aIQ.setTo(Common.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(Common.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);
}
Console.log('Sent OOB request to: ' + to + ' (' + desc + ')');
} catch(e) {
Console.error('OOB.send', e);
@ -92,29 +93,25 @@ var OOB = (function () {
self.handle = function(from, id, type, node) {
try {
var xid = '';
var url = '';
var desc = '';
// IQ stanza?
var xid = '', url = '', desc = '';
if(type == 'iq') {
// IQ stanza
xid = Common.fullXID(from);
url = $(node).find('url').text();
desc = $(node).find('desc').text();
}
// Message stanza?
else {
} else {
// Message stanza
xid = Common.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) {
Notification.create('send', xid, [xid, url, type, id, node], desc, hex_md5(xid + url + desc + id));
@ -140,36 +137,43 @@ var OOB = (function () {
try {
// Not IQ type?
if(type != 'iq')
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');
Console.info('Accepted file request from: ' + to);
}
// OOB request rejected
else {
aIQ.setType('error');
// Append stanza content
for(var i = 0; i < node.childNodes.length; i++)
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'});
var aError = aIQ.appendNode('error', {
'xmlns': NS_CLIENT,
'code': '406',
'type': 'modify'
});
aError.appendChild(aIQ.buildNode('not-acceptable', {'xmlns': NS_STANZAS}));
Console.info('Rejected file request from: ' + to);
}
con.send(aIQ);
} catch(e) {
Console.error('OOB.reply', e);
@ -187,11 +191,16 @@ var OOB = (function () {
try {
// 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>');
var chat_tools_file_sel = page_engine_sel.find('.chat-tools-file:not(.mini)');
var subitem_sel = chat_tools_file_sel.find('.tooltip-subitem');
subitem_sel.find('*').hide();
subitem_sel.append(
'<div class="wait wait-medium"></div>'
);
// Lock the bubble
$('#page-engine .chat-tools-file:not(.mini)').addClass('mini');
chat_tools_file_sel.addClass('mini');
} catch(e) {
Console.error('OOB.waitUpload', e);
}
@ -208,54 +217,55 @@ var OOB = (function () {
self.handleUpload = function(responseXML) {
try {
var page_engine_sel = $('#page-engine');
// 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)
if(!fID) {
oob_has = ':has(.wait)';
else
} 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')) {
Board.openThisError(4);
// Remove the file we sent
if(fURL)
$.get(fURL + '&action=remove');
}
var xid = page_engine_sel.find('.page-engine-chan' + oob_has).attr('data-xid');
var oob_type = page_engine_sel.find('.chat-tools-file' + oob_has).attr('data-oob');
// Reset the file send tool
page_engine_sel.find('.chat-tools-file' + oob_has).removeClass('mini');
page_engine_sel.find('.bubble-file' + oob_has).remove();
// Not available?
if(page_engine_sel.find('.chat-tools-file' + oob_has).is(':hidden') && (oob_type == 'iq')) {
Board.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
self.send(xid, oob_type, fURL, fDesc);
// Notify the sender
Notification.create('send_pending', xid, [xid, fURL, oob_type, '', ''], fDesc, hex_md5(fURL + fDesc + fID));
Console.info('File request sent.');
}
// Upload error?
else {
} else {
Board.openThisError(4);
Console.error('Error while sending the file', dData.find('error').text());
}
} catch(e) {

View file

@ -29,191 +29,191 @@ var Options = (function () {
try {
// Popup HTML content
var html =
'<div class="top">' + Common._e("Edit options") + '</div>' +
'<div class="tab">' +
'<a href="#" class="tab-general tab-active" data-key="1">' + Common._e("General") + '</a>' +
'<a href="#" class="tab-channel pubsub-hidable pubsub-hidable-cn" data-key="2">' + Common._e("Channel") + '</a>' +
'<a href="#" class="tab-account" data-key="3">' + Common._e("Account") + '</a>' +
'</div>' +
'<div class="content">' +
'<div id="conf1" class="lap-active one-lap forms">' +
'<fieldset class="privacy">' +
'<legend>' + Common._e("Privacy") + '</legend>' +
var html =
'<div class="top">' + Common._e("Edit options") + '</div>' +
'<div class="tab">' +
'<a href="#" class="tab-general tab-active" data-key="1">' + Common._e("General") + '</a>' +
'<a href="#" class="tab-channel pubsub-hidable pubsub-hidable-cn" data-key="2">' + Common._e("Channel") + '</a>' +
'<a href="#" class="tab-account" data-key="3">' + Common._e("Account") + '</a>' +
'</div>' +
'<div class="content">' +
'<div id="conf1" class="lap-active one-lap forms">' +
'<fieldset class="privacy">' +
'<legend>' + Common._e("Privacy") + '</legend>' +
'<div class="geolocation">' +
'<label for="geolocation" class="pep-hidable">' + Common._e("Geolocation") + '</label>' +
'<input id="geolocation" type="checkbox" class="pep-hidable" />' +
'<label for="geolocation" class="pep-hidable">' + Common._e("Geolocation") + '</label>' +
'<input id="geolocation" type="checkbox" class="pep-hidable" />' +
'</div>' +
'<div class="archiving">' +
'<label for="archiving" class="mam-hidable">' + Common._e("Message archiving") + '</label>' +
'<select id="archiving" class="mam-hidable">' +
'<option value="never">' + Common._e("Disabled") + '</option>' +
'<option value="roster">' + Common._e("Store friend chats") + '</option>' +
'<option value="always">' + Common._e("Store all chats") + '</option>' +
'</select>' +
'<a href="#" class="linked empty-archives mam-purge-hidable">' + Common._e("Remove all archives") + '</a>' +
'<label for="archiving" class="mam-hidable">' + Common._e("Message archiving") + '</label>' +
'<select id="archiving" class="mam-hidable">' +
'<option value="never">' + Common._e("Disabled") + '</option>' +
'<option value="roster">' + Common._e("Store friend chats") + '</option>' +
'<option value="always">' + Common._e("Store all chats") + '</option>' +
'</select>' +
'<a href="#" class="linked empty-archives mam-purge-hidable">' + Common._e("Remove all archives") + '</a>' +
'</div>' +
'</fieldset>' +
'<fieldset class="application">' +
'<legend>' + Common._e("Application") + '</legend>' +
'</fieldset>' +
'<fieldset class="application">' +
'<legend>' + Common._e("Application") + '</legend>' +
'<div class="sounds">' +
'<label for="sounds">' + Common._e("Sounds") + '</label>' +
'<input id="sounds" type="checkbox" />' +
'<label for="sounds">' + Common._e("Sounds") + '</label>' +
'<input id="sounds" type="checkbox" />' +
'</div>' +
'<div class="showall">' +
'<label for="showall">' + Common._e("Show all friends") + '</label>' +
'<input id="showall" type="checkbox" />' +
'<label for="showall">' + Common._e("Show all friends") + '</label>' +
'<input id="showall" type="checkbox" />' +
'</div>' +
'<div class="groupchatpresence">' +
'<label for="groupchatpresence">' + Common._e("Groupchat presence messages") + '</label>' +
'<input id="groupchatpresence" type="checkbox" />' +
'<label for="groupchatpresence">' + Common._e("Groupchat presence messages") + '</label>' +
'<input id="groupchatpresence" type="checkbox" />' +
'</div>' +
'<div class="noxhtmlimg">' +
'<label for="noxhtmlimg">' + Common._e("No chat images auto-load") + '</label>' +
'<input id="noxhtmlimg" type="checkbox" />' +
'<label for="noxhtmlimg">' + Common._e("No chat images auto-load") + '</label>' +
'<input id="noxhtmlimg" type="checkbox" />' +
'</div>' +
'<div class="integratemedias">' +
'<label for="integratemedias">' + Common._e("Media integration") + '</label>' +
'<input id="integratemedias" type="checkbox" />' +
'<label for="integratemedias">' + Common._e("Media integration") + '</label>' +
'<input id="integratemedias" type="checkbox" />' +
'</div>' +
'<div class="localarchives mam-showable">' +
'<label for="localarchives">' + Common._e("Keep local chat archives") + '</label>' +
'<input id="localarchives" type="checkbox" />' +
'<label for="localarchives">' + Common._e("Keep local chat archives") + '</label>' +
'<input id="localarchives" type="checkbox" />' +
'</div>' +
'<div class="xmpplinks">' +
'<label class="xmpplinks-hidable">' + Common._e("XMPP links") + '</label>' +
'<a href="#" class="linked xmpp-links xmpplinks-hidable">' + Common._e("Open XMPP links with Jappix") + '</a>' +
'<label class="xmpplinks-hidable">' + Common._e("XMPP links") + '</label>' +
'<a href="#" class="linked xmpp-links xmpplinks-hidable">' + Common._e("Open XMPP links with Jappix") + '</a>' +
'</div>' +
'</fieldset>' +
'</fieldset>' +
'<div class="sub-ask sub-ask-mam sub-ask-element">' +
'<div class="sub-ask-top">' +
'<div class="sub-ask-title">' + Common._e("Remove all archives") + '</div>' +
'<a href="#" class="sub-ask-close">X</a>' +
'</div>' +
'<div class="sub-ask-content">' +
'<label>' + Common._e("Password") + '</label>' +
'<input type="password" class="purge-archives check-mam" required="" />' +
'</div>' +
'<a href="#" class="sub-ask-bottom">' + Common._e("Remove") + ' &raquo;</a>' +
'</div>' +
'</div>' +
'<div id="conf2" class="one-lap forms">' +
'<fieldset class="channel">' +
'<legend>' + Common._e("Channel") + '</legend>' +
'<div class="sub-ask sub-ask-mam sub-ask-element">' +
'<div class="sub-ask-top">' +
'<div class="sub-ask-title">' + Common._e("Remove all archives") + '</div>' +
'<a href="#" class="sub-ask-close">X</a>' +
'</div>' +
'<div class="sub-ask-content">' +
'<label>' + Common._e("Password") + '</label>' +
'<input type="password" class="purge-archives check-mam" required="" />' +
'</div>' +
'<a href="#" class="sub-ask-bottom">' + Common._e("Remove") + ' &raquo;</a>' +
'</div>' +
'</div>' +
'<div id="conf2" class="one-lap forms">' +
'<fieldset class="channel">' +
'<legend>' + Common._e("Channel") + '</legend>' +
'<div class="empty-channel">' +
'<label>' + Common._e("Empty") + '</label>' +
'<a href="#" class="linked empty-channel">' + Common._e("Empty channel") + '</a>' +
'</div>' +
'<div class="persistent">' +
'<label>' + Common._e("Persistent") + '</label>' +
'<input id="persistent" type="checkbox" />' +
'</div>' +
'<div class="maxnotices">' +
'<label>' + Common._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>' +
'<label>' + Common._e("Empty") + '</label>' +
'<a href="#" class="linked empty-channel">' + Common._e("Empty channel") + '</a>' +
'</div>' +
'</fieldset>' +
'<div class="sub-ask sub-ask-empty sub-ask-element">' +
'<div class="sub-ask-top">' +
'<div class="sub-ask-title">' + Common._e("Empty channel") + '</div>' +
'<a href="#" class="sub-ask-close">X</a>' +
'</div>' +
'<div class="sub-ask-content">' +
'<label>' + Common._e("Password") + '</label>' +
'<input type="password" class="purge-microblog check-empty" required="" />' +
'</div>' +
'<a href="#" class="sub-ask-bottom">' + Common._e("Empty") + ' &raquo;</a>' +
'</div>' +
'</div>' +
'<div id="conf3" class="one-lap forms">' +
'<fieldset>' +
'<legend>' + Common._e("Account") + '</legend>' +
'<label>' + Common._e("Password") + '</label>' +
'<a href="#" class="linked change-password">' + Common._e("Change password") + '</a>' +
'<label>' + Common._e("Delete") + '</label>' +
'<a href="#" class="linked delete-account">' + Common._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">' + Common._e("Change password") + '</div>' +
'<a href="#" class="sub-ask-close">X</a>' +
'</div>' +
'<div class="sub-ask-content">' +
'<label>' + Common._e("Old") + '</label>' +
'<input type="password" class="password-change old" required="" />' +
'<label>' + Common._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">' + Common._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">' + Common._e("Delete account") + '</div>' +
'<a href="#" class="sub-ask-close">X</a>' +
'</div>' +
'<div class="sub-ask-content">' +
'<label>' + Common._e("Password") + '</label>' +
'<input type="password" class="delete-account check-password" required="" />' +
'</div>' +
'<a href="#" class="sub-ask-bottom">' + Common._e("Delete") + ' &raquo;</a>' +
'</div>' +
'</div>' +
'</div>' +
'<div class="bottom">' +
'<div class="wait wait-medium"></div>' +
'<a href="#" class="finish save">' + Common._e("Save") + '</a>' +
'<a href="#" class="finish cancel">' + Common._e("Cancel") + '</a>' +
'<div class="persistent">' +
'<label>' + Common._e("Persistent") + '</label>' +
'<input id="persistent" type="checkbox" />' +
'</div>' +
'<div class="maxnotices">' +
'<label>' + Common._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>' +
'</div>' +
'</fieldset>' +
'<div class="sub-ask sub-ask-empty sub-ask-element">' +
'<div class="sub-ask-top">' +
'<div class="sub-ask-title">' + Common._e("Empty channel") + '</div>' +
'<a href="#" class="sub-ask-close">X</a>' +
'</div>' +
'<div class="sub-ask-content">' +
'<label>' + Common._e("Password") + '</label>' +
'<input type="password" class="purge-microblog check-empty" required="" />' +
'</div>' +
'<a href="#" class="sub-ask-bottom">' + Common._e("Empty") + ' &raquo;</a>' +
'</div>' +
'</div>' +
'<div id="conf3" class="one-lap forms">' +
'<fieldset>' +
'<legend>' + Common._e("Account") + '</legend>' +
'<label>' + Common._e("Password") + '</label>' +
'<a href="#" class="linked change-password">' + Common._e("Change password") + '</a>' +
'<label>' + Common._e("Delete") + '</label>' +
'<a href="#" class="linked delete-account">' + Common._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">' + Common._e("Change password") + '</div>' +
'<a href="#" class="sub-ask-close">X</a>' +
'</div>' +
'<div class="sub-ask-content">' +
'<label>' + Common._e("Old") + '</label>' +
'<input type="password" class="password-change old" required="" />' +
'<label>' + Common._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">' + Common._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">' + Common._e("Delete account") + '</div>' +
'<a href="#" class="sub-ask-close">X</a>' +
'</div>' +
'<div class="sub-ask-content">' +
'<label>' + Common._e("Password") + '</label>' +
'<input type="password" class="delete-account check-password" required="" />' +
'</div>' +
'<a href="#" class="sub-ask-bottom">' + Common._e("Delete") + ' &raquo;</a>' +
'</div>' +
'</div>' +
'</div>' +
'<div class="bottom">' +
'<div class="wait wait-medium"></div>' +
'<a href="#" class="finish save">' + Common._e("Save") + '</a>' +
'<a href="#" class="finish cancel">' + Common._e("Cancel") + '</a>' +
'</div>';
// Create the popup
Popup.create('options', html);
// Apply the features
Features.apply('options');
// Associate the events
self.instance();
} catch(e) {
@ -275,11 +275,13 @@ var Options = (function () {
self.switchTab = function(id) {
try {
$('#options .one-lap').hide();
$('#options #conf' + id).show();
$('#options .tab a').removeClass('tab-active');
$('#options .tab a[data-key="' + id + '"]').addClass('tab-active');
$('#options .sub-ask .sub-ask-close').click();
var options_sel = $('#options');
options_sel.find('.one-lap').hide();
options_sel.find('#conf' + id).show();
options_sel.find('.tab a').removeClass('tab-active');
options_sel.find('.tab a[data-key="' + id + '"]').addClass('tab-active');
options_sel.find('.sub-ask .sub-ask-close').click();
} catch(e) {
Console.error('Options.switchTab', e);
} finally {
@ -298,15 +300,16 @@ var Options = (function () {
self.wait = function(id) {
try {
var sOptions = $('#options .content');
var options_sel = $('#options');
var content_sel = options_sel.find('.content');
// Remove the current item class
sOptions.removeClass(id);
content_sel.removeClass(id);
// Hide the waiting items if all was received
if(!sOptions.hasClass('microblog') && !sOptions.hasClass('mam')) {
$('#options .wait').hide();
$('#options .finish:first').removeClass('disabled');
if(!content_sel.hasClass('microblog') && !content_sel.hasClass('mam')) {
options_sel.find('.wait').hide();
options_sel.find('.finish:first').removeClass('disabled');
}
} catch(e) {
Console.error('Options.wait', e);
@ -332,25 +335,25 @@ var Options = (function () {
var integratemedias = DataStore.getDB(Connection.desktop_hash, 'options', 'integratemedias');
var localarchives = DataStore.getDB(Connection.desktop_hash, 'options', 'localarchives');
var status = DataStore.getDB(Connection.desktop_hash, 'options', 'presence-status');
// Create an array to be looped
var oType = ['sounds', 'geolocation', 'roster-showall', 'no-xhtml-images', 'groupchatpresence', 'integratemedias', 'localarchives', 'presence-status'];
var oContent = [sounds, geolocation, showall, noxhtmlimg, groupchatpresence, integratemedias, localarchives, 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(var i in oType) {
storage.appendChild(iq.buildNode('option', {'type': oType[i], 'xmlns': NS_OPTIONS}, oContent[i]));
}
con.send(iq, self.handleStore);
Console.info('Storing options...');
} catch(e) {
Console.error('Options.store', e);
@ -390,27 +393,27 @@ var Options = (function () {
try {
// We apply the sounds
var sounds = '0';
if($('#sounds').filter(':checked').size()) {
sounds = '1';
}
DataStore.setDB(Connection.desktop_hash, 'options', 'sounds', sounds);
// We apply the geolocation
if($('#geolocation').filter(':checked').size()) {
DataStore.setDB(Connection.desktop_hash, 'options', 'geolocation', '1');
// We geolocate the user on the go
PEP.geolocate();
} else {
DataStore.setDB(Connection.desktop_hash, 'options', 'geolocation', '0');
// We delete the geolocation informations
PEP.sendPosition();
DataStore.removeDB(Connection.desktop_hash, 'geolocation', 'now');
}
// We apply the roster show all
if($('#showall').filter(':checked').size()) {
DataStore.setDB(Connection.desktop_hash, 'options', 'roster-showall', '1');
@ -419,11 +422,11 @@ var Options = (function () {
DataStore.setDB(Connection.desktop_hash, 'options', 'roster-showall', '0');
Interface.showOnlineBuddies('options');
}
// We apply the XHTML-IM images filter
var noxhtmlimg = '1' ? $('#noxhtmlimg').filter(':checked').size() : '0';
DataStore.setDB(Connection.desktop_hash, 'options', 'no-xhtml-images', noxhtmlimg);
// We apply the groupchat presence messages configuration
var groupchatpresence = '1' ? $('#groupchatpresence').filter(':checked').size() : '0';
DataStore.setDB(Connection.desktop_hash, 'options', 'groupchatpresence', groupchatpresence);
@ -440,23 +443,23 @@ var Options = (function () {
if(localarchives === '0') {
Message.flushLocalArchive();
}
// We apply the message archiving
if(Features.enabledMAM()) {
MAM.setConfig($('#archiving').val() || 'never');
}
// We apply the microblog configuration
var persist = '1' ? $('#persist').filter(':checked').size() : '0';
var maximum = $('#maxnotices').val();
if(Features.enabledPEP() && (Features.enabledPubSub() || Features.enabledPubSubCN())) {
Pubsub.setup('', NS_URN_MBLOG, persist, maximum, '', '', false);
}
// We send the options to the database
self.store();
// Close the options
self.close();
} catch(e) {
@ -479,13 +482,13 @@ var Options = (function () {
try {
// Remove the general wait item
Interface.removeGeneralWait();
// If no errors
if(!Errors.handleReply(iq)) {
Connection.clearLastSession();
Connection.quit();
Board.openThisInfo(1);
Console.info('Password changed.');
} else {
Console.warn('Password not changed.');
@ -510,45 +513,49 @@ var Options = (function () {
var password0 = $('#options .old').val();
var password1 = $('#options .new1').val();
var password2 = $('#options .new2').val();
if ((password1 == password2) && (password0 == Utils.getPassword())) {
// We show the waiting image
Interface.showGeneralWait();
// We send the IQ
var iq = new JSJaCIQ();
iq.setTo(Utils.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, self.handlePwdChange);
Console.info('Password change sent.');
} else {
$('.sub-ask-pass input').each(function() {
var select = $(this);
if(!select.val())
if(!select.val()) {
$(document).oneTime(10, function() {
select.addClass('please-complete').focus();
});
else
select.removeClass('please-complete');
} else {
select.removeClass('please-complete');
}
});
if(password0 != Utils.getPassword())
if(password0 != Utils.getPassword()) {
$(document).oneTime(10, function() {
$('#options .old').addClass('please-complete').focus();
});
if(password1 != password2)
}
if(password1 != password2) {
$(document).oneTime(10, function() {
$('#options .new1, #options .new2').addClass('please-complete').focus();
});
}
}
} catch(e) {
Console.error('Options.sendNewPassword', e);
@ -570,14 +577,14 @@ var Options = (function () {
try {
// Remove the general wait item
Interface.removeGeneralWait();
// If no errors
if(!Errors.handleReply(iq)) {
Connection.clearLastSession();
Talk.destroy();
Board.openThisInfo(2);
Connection.logout();
Console.info('Account deleted.');
} else {
Console.warn('Account not deleted.');
@ -599,7 +606,7 @@ var Options = (function () {
try {
var pwd_input_sel = $('#options .check-mam');
var password = pwd_input_sel.val();
if(password == Utils.getPassword()) {
MAM.purgeArchives();
@ -611,13 +618,14 @@ var Options = (function () {
$('#options .sub-ask-mam .sub-ask-close').click();
} else {
var selector = $('#options .check-mam');
if(password != Utils.getPassword())
if(password != Utils.getPassword()) {
$(document).oneTime(10, function() {
selector.addClass('please-complete').focus();
});
else
} else {
selector.removeClass('please-complete');
}
}
} catch(e) {
Console.error('Options.purgeMyArchives', e);
@ -640,31 +648,32 @@ var Options = (function () {
try {
var pwd_input_sel = $('#options .check-empty');
var password = pwd_input_sel.val();
if(password == Utils.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, self.handleMicroblogPurge);
// Hide the tool
pwd_input_sel.val('');
$('#options .sub-ask-empty .sub-ask-close').click();
Console.info('Microblog purge sent.');
} else {
var selector = $('#options .check-empty');
if(password != Utils.getPassword())
if(password != Utils.getPassword()) {
$(document).oneTime(10, function() {
selector.addClass('please-complete').focus();
});
else
} else {
selector.removeClass('please-complete');
}
}
} catch(e) {
Console.error('Options.purgeMyMicroblog', e);
@ -688,7 +697,7 @@ var Options = (function () {
if(!Errors.handleReply(iq)) {
// Remove the microblog items
$('.one-update.update_' + hex_md5(Common.getXID())).remove();
Console.info('Microblog purged.');
} else {
Console.warn('Microblog not purged.');
@ -711,32 +720,31 @@ var Options = (function () {
try {
var password = $('#options .check-password').val();
if(password == Utils.getPassword()) {
// We show the waiting image
Interface.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, self.handleAccDeletion);
Console.info('Delete account sent.');
}
else {
} else {
var selector = $('#options .check-password');
if(password != Utils.getPassword())
if(password != Utils.getPassword()) {
$(document).oneTime(10, function() {
selector.addClass('please-complete').focus();
});
else
} else {
selector.removeClass('please-complete');
}
}
} catch(e) {
Console.error('Options.deleteMyAccount', e);
@ -761,70 +769,78 @@ var Options = (function () {
var enabled_pubsub_cn = Features.enabledPubSubCN();
var enabled_pep = Features.enabledPEP();
var sWait = $('#options .content');
// Show the waiting items if necessary
if(enabled_mam || (enabled_pep && (enabled_pubsub || enabled_pubsub_cn))) {
$('#options .wait').show();
$('#options .finish:first').addClass('disabled');
}
// We get the archiving configuration
if(enabled_mam) {
sWait.addClass('mam');
MAM.getConfig();
}
// We get the microblog configuration
if((enabled_pubsub || enabled_pubsub_cn) && enabled_pep) {
sWait.addClass('microblog');
Microblog.getConfig();
}
// We show the "privacy" form if something is visible into it
if(enabled_mam || enabled_pep)
if(enabled_mam || enabled_pep) {
$('#options fieldset.privacy').show();
}
// We get the values of the forms for the sounds
if(DataStore.getDB(Connection.desktop_hash, 'options', 'sounds') == '0')
if(DataStore.getDB(Connection.desktop_hash, 'options', 'sounds') == '0') {
$('#sounds').attr('checked', false);
else
} else {
$('#sounds').attr('checked', true);
}
// We get the values of the forms for the geolocation
if(DataStore.getDB(Connection.desktop_hash, 'options', 'geolocation') == '1')
if(DataStore.getDB(Connection.desktop_hash, 'options', 'geolocation') == '1') {
$('#geolocation').attr('checked', true);
else
} else {
$('#geolocation').attr('checked', false);
}
// We get the values of the forms for the roster show all
if(DataStore.getDB(Connection.desktop_hash, 'options', 'roster-showall') == '1')
if(DataStore.getDB(Connection.desktop_hash, 'options', 'roster-showall') == '1') {
$('#showall').attr('checked', true);
else
} else {
$('#showall').attr('checked', false);
}
// We get the values of the forms for the XHTML-IM images filter
if(DataStore.getDB(Connection.desktop_hash, 'options', 'no-xhtml-images') == '1')
if(DataStore.getDB(Connection.desktop_hash, 'options', 'no-xhtml-images') == '1') {
$('#noxhtmlimg').attr('checked', true);
else
} else {
$('#noxhtmlimg').attr('checked', false);
}
// We get the values of the forms for the integratemedias
if(DataStore.getDB(Connection.desktop_hash, 'options', 'integratemedias') == '0')
if(DataStore.getDB(Connection.desktop_hash, 'options', 'integratemedias') == '0') {
$('#integratemedias').attr('checked', false);
else
} else {
$('#integratemedias').attr('checked', true);
}
// We get the values of the forms for the groupchatpresence
if(DataStore.getDB(Connection.desktop_hash, 'options', 'groupchatpresence') == '0')
if(DataStore.getDB(Connection.desktop_hash, 'options', 'groupchatpresence') == '0') {
$('#groupchatpresence').attr('checked', false);
else
} else {
$('#groupchatpresence').attr('checked', true);
}
// We get the values of the forms for the localarchives
if(DataStore.getDB(Connection.desktop_hash, 'options', 'localarchives') == '0')
if(DataStore.getDB(Connection.desktop_hash, 'options', 'localarchives') == '0') {
$('#localarchives').attr('checked', false);
else
} else {
$('#localarchives').attr('checked', true);
}
} catch(e) {
Console.error('Options.load', e);
}
@ -845,80 +861,80 @@ var Options = (function () {
// Yet active?
if($(this).hasClass('tab-active'))
return false;
// Switch to the good tab
var key = parseInt($(this).attr('data-key'));
return self.switchTab(key);
});
$('#options .linked').click(function() {
$('#options .sub-ask').hide();
$('#options .forms').removeClass('in_background');
});
$('#options .xmpp-links').click(function() {
Utils.xmppLinksHandler();
return false;
});
$('#options .empty-archives').click(function() {
var selector = '#options .sub-ask-mam';
$(selector).show();
$('#options .forms').addClass('in_background');
$(document).oneTime(10, function() {
$(selector + ' input').focus();
});
return false;
});
$('#options .empty-channel').click(function() {
var selector = '#options .sub-ask-empty';
$(selector).show();
$('#options .forms').addClass('in_background');
$(document).oneTime(10, function() {
$(selector + ' input').focus();
});
return false;
});
$('#options .change-password').click(function() {
var selector = '#options .sub-ask-pass';
$(selector).show();
$('#options .forms').addClass('in_background');
$(document).oneTime(10, function() {
$(selector + ' input:first').focus();
});
return false;
});
$('#options .delete-account').click(function() {
var selector = '#options .sub-ask-delete';
$(selector).show();
$('#options .forms').addClass('in_background');
$(document).oneTime(10, function() {
$(selector + ' input').focus();
});
return false;
});
$('#options .sub-ask-pass .sub-ask-bottom').click(function() {
return self.sendNewPassword();
});
$('#options .sub-ask-mam .sub-ask-bottom').click(function() {
return self.purgeMyArchives();
});
@ -926,48 +942,55 @@ var Options = (function () {
$('#options .sub-ask-empty .sub-ask-bottom').click(function() {
return self.purgeMyMicroblog();
});
$('#options .sub-ask-delete .sub-ask-bottom').click(function() {
return self.deleteMyAccount();
});
$('#options .sub-ask-close').click(function() {
$('#options .sub-ask').hide();
$('#options .forms').removeClass('in_background');
return false;
});
$('#options .bottom .finish').click(function() {
if($(this).is('.save') && !$(this).hasClass('disabled'))
if($(this).is('.save') && !$(this).hasClass('disabled')) {
return self.save();
if($(this).is('.cancel'))
}
if($(this).is('.cancel')) {
return self.close();
}
return false;
});
// The keyup events
$('#options .sub-ask input').keyup(function(e) {
if(e.keyCode == 13) {
// Archives purge
if($(this).is('.purge-archives'))
if($(this).is('.purge-archives')) {
return self.purgeMyArchives();
}
// Microblog purge
else if($(this).is('.purge-microblog'))
else if($(this).is('.purge-microblog')) {
return self.purgeMyMicroblog();
}
// Password change
else if($(this).is('.password-change'))
else if($(this).is('.password-change')) {
return self.sendNewPassword();
}
// Account deletion
else if($(this).is('.delete-account'))
else if($(this).is('.delete-account')) {
return self.deleteMyAccount();
}
}
});
// Load the options
self.load();
} catch(e) {

File diff suppressed because it is too large Load diff

View file

@ -34,27 +34,27 @@ var Popup = (function () {
if(Common.exists('#' + id)) {
return false;
}
// Popop on top of another one?
var top_of = Common.exists('div.lock:has(div.popup)');
// Append the popup code
$('body').append(
'<div id="' + id + '" class="lock removable">' +
'<div class="popup">' +
content +
'</div>' +
'<div id="' + id + '" class="lock removable">' +
'<div class="popup">' +
content +
'</div>' +
'</div>'
);
// Avoids darker popup background (if on top of another popup)
if(top_of) {
$('#' + id).css('background', 'transparent');
}
// Attach popup events
self.instance(id);
return true;
} catch(e) {
Console.error('Popup.create', e);
@ -74,10 +74,10 @@ var Popup = (function () {
try {
// Stop the popup timers
$('#' + id + ' *').stopTime();
// Remove the popup
$('#' + id).remove();
// Manage input focus
Interface.inputFocus();
} catch(e) {
@ -102,7 +102,7 @@ var Popup = (function () {
if($(evt.target).is('.lock:not(.unavoidable)')) {
// Destroy the popup
self.destroy(id);
return false;
}
});

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -40,12 +40,12 @@ var Pubsub = (function () {
// Create the PubSub node
var iq = new JSJaCIQ();
iq.setType('set');
// Any external entity?
if(entity) {
iq.setTo(entity);
}
// Create it?
var pubsub;
@ -55,38 +55,38 @@ var Pubsub = (function () {
} else {
pubsub = iq.appendNode('pubsub', {'xmlns': NS_PUBSUB_OWNER});
}
// Configure it!
var configure = pubsub.appendChild(iq.buildNode('configure', {'node': node, 'xmlns': NS_PUBSUB}));
var x = configure.appendChild(iq.buildNode('x', {'xmlns': NS_XDATA, 'type': 'submit'}));
var field1 = x.appendChild(iq.buildNode('field', {'var': 'FORM_TYPE', 'type': 'hidden', 'xmlns': NS_XDATA}));
field1.appendChild(iq.buildNode('value', {'xmlns': NS_XDATA}, NS_PUBSUB_NC));
// Persist items?
if(persist) {
var field2 = x.appendChild(iq.buildNode('field', {'var': 'pubsub#persist_items', 'xmlns': NS_XDATA}));
field2.appendChild(iq.buildNode('value', {'xmlns': NS_XDATA}, persist));
}
// Maximum items?
if(maximum) {
var field3 = x.appendChild(iq.buildNode('field', {'var': 'pubsub#max_items', 'xmlns': NS_XDATA}));
field3.appendChild(iq.buildNode('value', {'xmlns': NS_XDATA}, maximum));
}
// Access rights?
if(access) {
var field4 = x.appendChild(iq.buildNode('field', {'var': 'pubsub#access_model', 'xmlns': NS_XDATA}));
field4.appendChild(iq.buildNode('value', {'xmlns': NS_XDATA}, access));
}
// Publish rights?
if(publish) {
var field5 = x.appendChild(iq.buildNode('field', {'var': 'pubsub#publish_model', 'xmlns': NS_XDATA}));
field5.appendChild(iq.buildNode('value', {'xmlns': NS_XDATA}, publish));
}
con.send(iq);
} catch(e) {
Console.error('Pubsub.setup', e);

View file

@ -106,16 +106,17 @@ var Receipts = (function () {
var aMsg = new JSJaCMessage();
aMsg.setTo(to);
aMsg.setID(id);
// Any type?
if(type)
if(type) {
aMsg.setType(type);
}
// Append the received node
aMsg.appendNode('received', {'xmlns': NS_URN_RECEIPTS, 'id': id});
con.send(aMsg);
Console.log('Sent received to: ' + to);
} catch(e) {
Console.error('Receipts.sendReceived', e);
@ -136,18 +137,18 @@ var Receipts = (function () {
try {
// 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');
.removeAttr('title');
}
} catch(e) {
Console.error('Receipts.messageReceived', e);
@ -170,14 +171,19 @@ var Receipts = (function () {
try {
// Fire a check 10 seconds later
$('#' + hash + ' .one-line[data-id="' + id + '"]').oneTime('10s', function() {
var this_sel = $(this);
// Not received?
if($(this).attr('data-received') != 'true') {
if(this_sel.attr('data-received') != 'true') {
// Add a "lost" marker
$(this).attr('data-lost', 'true');
this_sel.attr('data-lost', 'true');
// Add a warn on the buddy-name
$(this).parent().find('b.name').addClass('talk-images')
.attr('title', Common._e("Your friend seems not to have received your message(s)!"));
this_sel.parent().find('b.name').addClass('talk-images')
.attr(
'title',
Common._e("Your friend seems not to have received your message(s)!")
);
}
});
} catch(e) {

File diff suppressed because it is too large Load diff

View file

@ -18,7 +18,7 @@ var RosterX = (function () {
* @private
*/
var self = {};
/**
* Opens the rosterx tools
@ -30,32 +30,32 @@ var RosterX = (function () {
try {
// Popup HTML content
var html =
'<div class="top">' + Common._e("Suggested friends") + '</div>' +
'<div class="content">' +
'<div class="rosterx-head">' +
'<a href="#" class="uncheck">' + Common._e("Uncheck all") + '</a>' +
'<a href="#" class="check">' + Common._e("Check all") + '</a>' +
'</div>' +
'<div class="results"></div>' +
'</div>' +
'<div class="bottom">' +
'<a href="#" class="finish save">' + Common._e("Save") + '</a>' +
'<a href="#" class="finish cancel">' + Common._e("Cancel") + '</a>' +
var html =
'<div class="top">' + Common._e("Suggested friends") + '</div>' +
'<div class="content">' +
'<div class="rosterx-head">' +
'<a href="#" class="uncheck">' + Common._e("Uncheck all") + '</a>' +
'<a href="#" class="check">' + Common._e("Check all") + '</a>' +
'</div>' +
'<div class="results"></div>' +
'</div>' +
'<div class="bottom">' +
'<a href="#" class="finish save">' + Common._e("Save") + '</a>' +
'<a href="#" class="finish cancel">' + Common._e("Cancel") + '</a>' +
'</div>';
// Create the popup
Popup.create('rosterx', html);
// Associate the events
self.instance();
// Parse the data
self.parse(data);
Console.log('Roster Item Exchange popup opened.');
} catch(e) {
Console.error('RosterX.open', e);
@ -94,37 +94,47 @@ var RosterX = (function () {
try {
// Main selector
var x = $(data).find('x[xmlns="' + NS_ROSTERX + '"]:first');
// Parse data
x.find('item').each(function() {
var this_sel = $(this);
// Generate group XML
var group = '';
$(this).find('group').each(function() {
group += '<group>' + $(this).text().htmlEnc() + '</group>';
this_sel.find('group').each(function() {
group += '<group>' + this_sel.text().htmlEnc() + '</group>';
});
if(group)
if(group) {
group = '<groups>' + group + '</groups>';
}
// Display it!
self.display($(this).attr('jid'), $(this).attr('name'), group, $(this).attr('action'));
self.display(
this_sel.attr('jid'),
this_sel.attr('name'),
group,
this_sel.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"]'))
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())
if(checkbox.filter(':checked').size()) {
checkbox.removeAttr('checked');
else
} else {
checkbox.attr('checked', true);
}
});
} catch(e) {
Console.error('RosterX.parse', e);
@ -146,24 +156,27 @@ var RosterX = (function () {
try {
// End if no XID
if(!xid)
if(!xid) {
return false;
}
// Set up a default action if no one
if(!action || (action != 'modify') || (action != 'delete'))
if(!action || (action != 'modify') || (action != 'delete')) {
action = 'add';
}
// Override "undefined" for nickname
if(!nick)
if(!nick) {
nick = '';
}
// Display it
$('#rosterx .results').append(
'<div class="oneresult">' +
'<input type="checkbox" checked="" data-name="' + Common.encodeQuotes(nick) + '" data-xid="' + Common.encodeQuotes(xid) + '" data-action="' + Common.encodeQuotes(action) + '" data-group="' + Common.encodeQuotes(group) + '" />' +
'<span class="name">' + nick.htmlEnc() + '</span>' +
'<span class="xid">' + xid.htmlEnc() + '</span>' +
'<span class="action ' + action + ' talk-images"></span>' +
'<div class="oneresult">' +
'<input type="checkbox" checked="" data-name="' + Common.encodeQuotes(nick) + '" data-xid="' + Common.encodeQuotes(xid) + '" data-action="' + Common.encodeQuotes(action) + '" data-group="' + Common.encodeQuotes(group) + '" />' +
'<span class="name">' + nick.htmlEnc() + '</span>' +
'<span class="xid">' + xid.htmlEnc() + '</span>' +
'<span class="action ' + action + ' talk-images"></span>' +
'</div>'
);
@ -178,31 +191,33 @@ var RosterX = (function () {
/**
* Saves the rosterx settings
* @public
* @return {undefined}
* @return {boolean}
*/
self.save = function() {
try {
// Send the requests
$('#rosterx .results input[type="checkbox"]').filter(':checked').each(function() {
var this_sel = $(this);
// 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');
var nick = this_sel.attr('data-name');
var xid = this_sel.attr('data-xid');
var action = this_sel.attr('data-action');
var group = this_sel.attr('data-group');
// Parse groups XML
var group_arr = [];
if(group) {
$(group).find('group').each(function() {
group_arr.push($(this).text().revertHtmlEnc());
group_arr.push(this_sel.text().revertHtmlEnc());
});
}
// Process the asked action
var roster_item = $('#roster .' + hex_md5(xid));
switch(action) {
// Buddy add
case 'add':
@ -210,29 +225,31 @@ var RosterX = (function () {
Presence.sendSubscribe(xid, 'subscribe');
Roster.send(xid, '', nick, group_arr);
}
break;
// Buddy edit
case 'modify':
if(Common.exists(roster_item))
Roster.send(xid, '', nick, group_arr);
break;
// Buddy delete
case 'delete':
if(Common.exists(roster_item))
Roster.send(xid, 'remove');
break;
}
});
// Close the popup
self.close();
} catch(e) {
Console.error('RosterX.save', e);
} finally {
return false;
}
};
@ -248,18 +265,26 @@ var RosterX = (function () {
try {
// Click events
$('#rosterx .bottom .finish').click(function() {
if($(this).is('.save'))
var this_sel = $(this);
if(this_sel.is('.save')) {
return self.save();
if($(this).is('.cancel'))
}
if(this_sel.is('.cancel')) {
return self.close();
}
});
$('#rosterx .rosterx-head a').click(function() {
if($(this).is('.check'))
var this_sel = $(this);
if(this_sel.is('.check')) {
$('#rosterx .results input[type="checkbox"]').attr('checked', true);
else if($(this).is('.uncheck'))
} else if(this_sel.is('.uncheck')) {
$('#rosterx .results input[type="checkbox"]').removeAttr('checked');
}
return false;
});
} catch(e) {

View file

@ -37,34 +37,34 @@ var Search = (function () {
if(!query) {
return;
}
// Wildcard (*) submitted
if(query == '*') {
query = '';
}
// Replace forbidden characters in regex
query = Common.escapeRegex(query);
// Create an empty array
var results = [];
// Search regex
var regex = new RegExp('((^)|( ))' + query, 'gi');
// Search in the roster
var buddies = Roster.getAllBuddies();
for(var i in buddies) {
var xid = buddies[i];
var nick = Name.getBuddy(xid);
// Buddy match our search, and not yet in the array
if(nick.match(regex) && !Utils.existArrayValue(results, xid)) {
results.push(xid);
}
}
// Return the results array
return results;
} catch(e) {
@ -104,17 +104,18 @@ var Search = (function () {
try {
// Remove the search tool
self.resetBuddy(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+)$/))
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();
@ -139,56 +140,57 @@ var Search = (function () {
try {
// Reset the search engine
self.resetBuddy(destination);
// Get the entered value
var value = $(destination + ' input').val();
// Separation with a comma?
if(value.match(/^(.+)((,)(\s)?)(\w+)$/))
if(value.match(/^(.+)((,)(\s)?)(\w+)$/)) {
value = RegExp.$5;
}
// Get the result array
var entered = self.processBuddy(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
// Append each found buddy in the container
var regex = new RegExp('((^)|( ))' + value, 'gi');
// Initialize the code generation
var code = '<ul>';
for(var b in entered) {
// Get some values from the XID
var current = Name.getBuddy(entered[b]).htmlEnc();
current = current.replace(regex, '<b>$&</b>');
// Add the current element to the global code
code += '<li onclick="return Search.addBuddy(\'' + Utils.encodeOnclick(destination) + '\', \'' + Utils.encodeOnclick(entered[b]) + '\');" data-xid="' + Common.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');
});
@ -212,52 +214,53 @@ var Search = (function () {
try {
// Down arrow: 40
// Up arrown: 38
// Initialize
var code = evt.keyCode;
// Not the key we want here
if((code != 40) && (code != 38))
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(Common.exists(path + '.hovered')) {
var index = $(path).attr('data-hovered');
if(index)
if(index) {
i = parseInt(index);
if(code == 40)
}
if(code == 40) {
i++;
else
} else {
i--;
}
} else if(code == 38) {
i = pSize - 1;
}
else if(code == 38)
i = pSize - 1;
// We must not override the maximum i limit
if(i >= pSize)
if(i >= pSize) {
i = 0;
// We must not have negative i
else if(i < 0)
} 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);
} catch(e) {
@ -280,20 +283,22 @@ var Search = (function () {
try {
// Put a marker
self.search_filtered = true;
// Show the buddies that match the search string
var rFilter = self.processBuddy(vFilter);
// Hide all the buddies
$('#roster .buddy').hide();
// Only show the buddies which match the search
if(!Roster.blist_all) {
for(var i in rFilter)
for(var i in rFilter) {
$('#roster .buddy[data-xid="' + escape(rFilter[i]) + '"]:not(.hidden-buddy)').show();
}
} else {
for(var j in rFilter)
for(var j in rFilter) {
$('#roster .buddy[data-xid="' + escape(rFilter[j]) + '"]').show();
}
}
} catch(e) {
Console.error('Search.goFilterBuddy', e);
@ -312,14 +317,15 @@ var Search = (function () {
try {
// Remove the marker
self.search_filtered = false;
// Show all the buddies
$('#roster .buddy').show();
// Only show available buddies
if(!Roster.blist_all)
if(!Roster.blist_all) {
$('#roster .buddy.hidden-buddy').hide();
}
// Update the groups
Roster.updateGroups();
} catch(e) {
@ -342,26 +348,24 @@ var Search = (function () {
var input = $('#roster .filter input');
var cancel = $('#roster .filter a');
var value = input.val();
// Security: reset all the groups, empty or not, deployed or not
$('#roster .one-group, #roster .group-buddies').show();
$('#roster .group span').text('-');
// Nothing is entered, or escape pressed
if(!value || (keycode == 27)) {
if(keycode == 27)
if(keycode == 27) {
input.val('');
}
self.resetFilterBuddy();
cancel.hide();
}
// Process the filtering
else {
} else {
cancel.show();
self.goFilterBuddy(value);
}
// Update the groups
Roster.updateGroups();
} catch(e) {
@ -384,25 +388,25 @@ var Search = (function () {
var 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;
} catch(e) {
Console.error('Search.sortElementByStamp', e);

View file

@ -20,6 +20,51 @@ var Smileys = (function () {
var self = {};
/* Constants */
self.emote_list = {
'biggrin': ':-D',
'devil': ']:->',
'coolglasses': '8-)',
'tongue': ':-P',
'smile': ':-)',
'wink': ';-)',
'blush': ':-$',
'stare': ':-|',
'frowning': ':-/',
'oh': '=-O',
'unhappy': ':-(',
'cry': ':\'-(',
'angry': ':-@',
'puke': ':-!',
'hugright': '({)',
'hugleft': '(})',
'lion': ':3',
'pussy': '(@)',
'bat': ':-[',
'kiss': ':-{}',
'heart': '<3',
'brheart': '</3',
'flower': '@}->--',
'brflower': '(W)',
'thumbup': '(Y)',
'thumbdown': '(N)',
'lamp': '(I)',
'coffee': '(C)',
'drink': '(D)',
'beer': '(B)',
'boy': '(Z)',
'girl': '(X)',
'photo': '(P)',
'phone': '(T)',
'music': '(8)',
'cuffs': '(%)',
'mail': '(E)',
'rainbow': '(R)',
'star': '(*)',
'moon': '(S)'
};
/**
* Generates the correct HTML code for an emoticon insertion tool
* @public
@ -43,103 +88,21 @@ var Smileys = (function () {
* Emoticon links arrays
* @public
* @param {string} hash
* @return {object}
* @return {string}
*/
self.links = function(hash) {
try {
var links = '';
var sArray = [
':-D',
']:->',
'8-)',
':-P',
':-)',
';-)',
':-$',
':-|',
':-/',
'=-O',
':-(',
':\'-(',
':-@',
':-!',
'({)',
'(})',
':3',
'(@)',
':-[',
':-{}',
'<3',
'</3',
'@}->--',
'(W)',
'(Y)',
'(N)',
'(I)',
'(C)',
'(D)',
'(B)',
'(Z)',
'(X)',
'(P)',
'(T)',
'(8)',
'(%)',
'(E)',
'(R)',
'(*)',
'(S)'
];
var cArray = [
'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(var i in sArray) {
links += self.emoteLink(sArray[i], cArray[i], hash);
for(var cur_emote in self.emote_list) {
links += self.emoteLink(
self.emote_list[cur_emote],
cur_emote,
hash
);
}
return links;
} catch(e) {
Console.error('Smileys.links', e);

View file

@ -33,10 +33,10 @@ var Storage = (function () {
try {
var iq = new JSJaCIQ();
iq.setType('get');
var iqQuery = iq.setQuery(NS_PRIVATE);
iqQuery.appendChild(iq.buildNode('storage', {'xmlns': type}));
con.send(iq, self.handle);
} catch(e) {
Console.error('Storage.get', e);
@ -56,111 +56,126 @@ var Storage = (function () {
try {
var handleXML = iq.getQuery();
var handleFrom = Common.fullXID(Common.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')) {
Welcome.open();
}
// Parse the options xml
options.find('option').each(function() {
var this_sel = $(this);
// We retrieve the informations
var type = $(this).attr('type');
var value = $(this).text();
var type = this_sel.attr('type');
var value = this_sel.text();
// We display the storage
DataStore.setDB(Connection.desktop_hash, 'options', type, value);
// If this is the buddy list show status
if((type == 'roster-showall') && (value == '1'))
if((type == 'roster-showall') && (value == '1')) {
Interface.showAllBuddies('storage');
}
});
// Parse the inbox xml
inbox.find('message').each(function() {
var this_sel = $(this);
Inbox.storeMessage(
$(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')
]
);
this_sel.attr('from'),
this_sel.attr('subject'),
this_sel.text(),
this_sel.attr('status'),
this_sel.attr('id'),
this_sel.attr('date'),
[
this_sel.attr('file_title'),
this_sel.attr('file_href'),
this_sel.attr('file_type'),
this_sel.attr('file_length')
]
);
});
// Parse the bookmarks xml
bookmarks.find('conference').each(function() {
var this_sel = $(this);
// 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();
var xid = this_sel.attr('jid');
var name = this_sel.attr('name');
var autojoin = this_sel.attr('autojoin');
var password = this_sel.find('password').text();
var nick = this_sel.find('nick').text();
// Filter autojoin (compatibility)
autojoin = ((autojoin == 'true') || (autojoin == '1')) ? 'true' : 'false';
// We display the storage
Favorites.display(xid, name, nick, autojoin, password);
// Join the chat if autojoin is enabled
if(autojoin == 'true')
if(autojoin == 'true') {
Chat.checkCreate(xid, 'groupchat', nick, password, name);
}
});
// Parse the roster notes xml
rosternotes.find('note').each(function() {
DataStore.setDB(Connection.desktop_hash, 'rosternotes', $(this).attr('jid'), $(this).text());
var this_sel = $(this);
DataStore.setDB(
Connection.desktop_hash,
'rosternotes',
this_sel.attr('jid'),
this_sel.text()
);
});
// Options received
if(options.size()) {
Console.log('Options received.');
// Now, get the inbox
self.get(NS_INBOX);
// Geolocate the user
PEP.geolocate();
$('.options-hidable').show();
}
// Inbox received
else if(inbox.size()) {
Console.log('Inbox received.');
// Send the first presence!
Presence.sendFirst(DataStore.getDB(Connection.desktop_hash, 'checksum', 1));
// Check we have new messages (play a sound if any unread messages)
if(Inbox.checkMessages()) {
Audio.play('notification');
}
$('.inbox-hidable').show();
}
// Bookmarks received
else if(bookmarks.size()) {
// Join the groupchats the admin defined (if any)
Groupchat.joinConf();
Console.log('Bookmarks received.');
}
// Roster notes received (for logger)
else if(rosternotes.size()) {
Console.log('Roster notes received.');

View file

@ -29,17 +29,21 @@ var System = (function () {
try {
var url = window.location.href;
// If the URL has variables, remove them
if(url.indexOf('?') != -1)
if(url.indexOf('?') != -1) {
url = url.split('?')[0];
if(url.indexOf('#') != -1)
}
if(url.indexOf('#') != -1) {
url = url.split('#')[0];
}
// No "/" at the end
if(!url.match(/(.+)\/$/))
if(!url.match(/(.+)\/$/)) {
url += '/';
}
return url;
} catch(e) {
Console.error('System.location', e);

View file

@ -51,236 +51,241 @@ var Talk = (function () {
try {
// Talkpage exists?
if(Common.exists('#talk'))
if(Common.exists('#talk')) {
return false;
}
// Anonymous detector
var anonymous = Utils.isAnonymous();
// Generate the HTML code
var html =
'<div id="talk" class="removable">' +
'<div id="top-content">' +
'<div class="tools tools-logo talk-images"></div>' +
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 Inbox.open();" class="inbox-hidable">' + Common._e("Messages") + '</a>' +
'<a href="#" onclick="return vCard.open();" class="vcard">' + Common._e("Profile") + '</a>' +
'<a href="#" onclick="return Options.open();" class="options-hidable">' + Common._e("Options") + '</a>' +
if(!anonymous) html +=
'<a href="#" onclick="return Inbox.open();" class="inbox-hidable">' + Common._e("Messages") + '</a>' +
'<a href="#" onclick="return vCard.open();" class="vcard">' + Common._e("Profile") + '</a>' +
'<a href="#" onclick="return Options.open();" class="options-hidable">' + Common._e("Options") + '</a>' +
'<a href="#" onclick="return Connection.normalQuit();" class="quit">' + Common._e("Disconnect") + '</a>';
else html +=
'<a href="./">' + Common._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 Music.open();"></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 Music.action(\'stop\');"></a>' +
'</div>' +
'<div class="list">' +
'<p class="no-results">' + Common._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 Bubble.show(\'.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 Notification.clear();">' + Common._e("Empty") + '</a>' +
'<p class="nothing">' + Common._e("No notifications.") + '</p>' +
'</div>' +
'</div>' +
if(!anonymous && document.createElement('audio').canPlayType) html +=
'<div class="tools-all ibubble">' +
'<div class="tools music talk-images" onclick="return Music.open();"></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 Music.action(\'stop\');"></a>' +
'</div>' +
'<div class="list">' +
'<p class="no-results">' + Common._e("No result!") + '</p>' +
'</div>' +
'<div class="search">' +
'<input type="text" />' +
'</div>' +
'</div>' +
'</div>' +
'</div>';
if(!anonymous) html +=
'<div class="tools-all">' +
'<div class="tools jingle talk-images" onclick="return Jingle.open();">' +
'<span class="streaming-items">' +
'<span class="counter" data-default="00:00:00">00:00:00</span>' +
'<a class="stop" href="#" onclick="return Jingle.stop();">' + Common._e("Stop") + '</a>' +
'</span>' +
'</div>' +
if(!anonymous) html +=
'<div class="tools-all ibubble">' +
'<div class="tools notifications talk-images" onclick="return Bubble.show(\'.notifications-content\');"></div>' +
'<div class="jingle-content tools-content">' +
'<div class="tools-content-subarrow talk-images"></div>' +
'<div class="tools-content-subitem"></div>' +
'</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 Notification.clear();">' + Common._e("Empty") + '</a>' +
'<p class="nothing">' + Common._e("No notifications.") + '</p>' +
'</div>' +
'</div>' +
'</div>';
if(!anonymous) html +=
'<div class="tools-all">' +
'<div class="tools call talk-images" onclick="return Call.open();">' +
'<span class="streaming-items">' +
'<span class="counter" data-default="00:00:00">00:00:00</span>' +
'<a class="stop" href="#" onclick="return Call.stop();">' + Common._e("Stop") + '</a>' +
'</span>' +
'</div>' +
'<div class="call-content tools-content">' +
'<div class="tools-content-subarrow talk-images"></div>' +
'<div class="tools-content-subitem"></div>' +
'</div>' +
'</div>';
html +=
'</div>' +
'<div id="main-content">' +
'</div>' +
'<div id="main-content">' +
'<div id="left-content">';
if(!anonymous) html +=
'<div id="roster">' +
'<div class="content"></div>' +
'<div class="filter">' +
'<input type="text" placeholder="' + Common._e("Filter") + '" />' +
'<a href="#">x</a>' +
'</div>' +
'<div class="foot ibubble">' +
'<div class="roster-add roster-icon">' +
'<a href="#" class="add talk-images" title="' + Common._e("Add a friend") + '"></a>' +
'</div>' +
'<div class="roster-join roster-icon">' +
'<a href="#" class="join talk-images" title="' + Common._e("Join a chat") + '"></a>' +
'</div>' +
'<div class="roster-groupchat roster-icon">' +
'<a href="#" class="groupchat talk-images" title="' + Common._e("Your groupchats") + '"></a>' +
'</div>' +
'<div class="roster-more roster-icon">' +
'<a href="#" class="more talk-images" title="' + Common._e("More stuff") + '"></a>' +
'</div>' +
'<div style="clear: both;"></div>' +
'</div>' +
if(!anonymous) html +=
'<div id="roster">' +
'<div class="content"></div>' +
'<div class="filter">' +
'<input type="text" placeholder="' + Common._e("Filter") + '" />' +
'<a href="#">x</a>' +
'</div>' +
'<div class="foot ibubble">' +
'<div class="roster-add roster-icon">' +
'<a href="#" class="add talk-images" title="' + Common._e("Add a friend") + '"></a>' +
'</div>' +
'<div class="roster-join roster-icon">' +
'<a href="#" class="join talk-images" title="' + Common._e("Join a chat") + '"></a>' +
'</div>' +
'<div class="roster-groupchat roster-icon">' +
'<a href="#" class="groupchat talk-images" title="' + Common._e("Your groupchats") + '"></a>' +
'</div>' +
'<div class="roster-muji roster-icon muji-hidable">' +
'<a href="#" class="muji talk-images" title="' + Common._e("Audio/video conference") + '"></a>' +
'</div>' +
'<div class="roster-more roster-icon">' +
'<a href="#" class="more talk-images" title="' + Common._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="' + Common._e("Status") + '" disabled="" />' +
'<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="' + Common._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="' + Common._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="' + Common._e("Activity") + '" />' +
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="' + Common._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="' + Common._e("Activity") + '" />' +
'</div>';
html +=
'</div>' +
'</div>' +
'</div>' +
'<div id="right-content">' +
'<div id="page-switch">' +
'</div>' +
'</div>' +
'</div>' +
'<div id="right-content">' +
'<div id="page-switch">' +
'<div class="chans">';
if(!anonymous) html +=
'<div class="channel switcher activechan" onclick="return Interface.switchChan(\'channel\');">' +
'<div class="icon talk-images"></div>' +
'<div class="name">' + Common._e("Channel") + '</div>' +
if(!anonymous) html +=
'<div class="channel switcher activechan" onclick="return Interface.switchChan(\'channel\');">' +
'<div class="icon talk-images"></div>' +
'<div class="name">' + Common._e("Channel") + '</div>' +
'</div>';
html +=
'</div>';
if(anonymous) html +=
'<div class="join ibubble">' +
'<div class="join-button talk-images" onclick="return Interface.loadJoinGroupchat();" title="' + Common._e("Join groupchat") + '"></div>' +
'<div class="join ibubble">' +
'<div class="join-button talk-images" onclick="return Interface.loadJoinGroupchat();" title="' + Common._e("Join groupchat") + '"></div>' +
'</div>';
html +=
'<div class="more ibubble">' +
'<div class="more-button talk-images" onclick="return Interface.loadChatSwitch();" title="' + Common._e("All tabs") + '"></div>' +
'</div>' +
'</div>' +
'<div class="more ibubble">' +
'<div class="more-button talk-images" onclick="return Interface.loadChatSwitch();" title="' + Common._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(Common.getXID()) + '">' +
'<div class="avatar-container">' +
'<img class="avatar" src="' + './images/others/default-avatar.png' + '" alt="" />' +
'</div>' +
'<div class="update">' +
'<p>' + Common._e("What\'s up with you?") + '</p>' +
'<div class="microblog-body">' +
'<input class="focusable" type="text" name="microblog_body" placeholder="' + Common._e("Type something you want to share with your friends...") + '" disabled="" />' +
'</div>' +
'<div class="one-microblog-icon ibubble">' +
'<a href="#" onclick="return Bubble.show(\'#attach\');" title="' + Common._e("Attach a file") + '" class="postit attach talk-images"></a>' +
'<form id="attach" class="bubble hidable" action="./server/file-share.php" method="post" enctype="multipart/form-data">' +
'<div class="attach-subarrow talk-images"></div>' +
'<div class="attach-subitem">' +
'<p class="attach-p">' + Common._e("Attach a file") + '</p>' +
Interface.generateFileShare() +
'</div>' +
'</form>' +
'</div>' +
'</div>' +
'</div>' +
'<div class="content mixed"></div>' +
'<div class="footer">' +
'<div class="sync talk-images">' + Common._e("You are synchronized with your network.") + '</div>' +
'<div class="unsync talk-images">' + Common._e("Cannot send anything: you can only receive notices!") + '</div>' +
'<div class="fetch wait-small">' + Common._e("Fetching the social channel...") + '</div>' +
'</div>' +
if(!anonymous) html +=
'<div id="channel" class="page-engine-chan" style="display: block;">' +
'<div class="top mixed ' + hex_md5(Common.getXID()) + '">' +
'<div class="avatar-container">' +
'<img class="avatar" src="' + './images/others/default-avatar.png' + '" alt="" />' +
'</div>' +
'<div class="update">' +
'<p>' + Common._e("What\'s up with you?") + '</p>' +
'<div class="microblog-body">' +
'<input class="focusable" type="text" name="microblog_body" placeholder="' + Common._e("Type something you want to share with your friends...") + '" disabled="" />' +
'</div>' +
'<div class="one-microblog-icon ibubble">' +
'<a href="#" onclick="return Bubble.show(\'#attach\');" title="' + Common._e("Attach a file") + '" class="postit attach talk-images"></a>' +
'<form id="attach" class="bubble hidable" action="./server/file-share.php" method="post" enctype="multipart/form-data">' +
'<div class="attach-subarrow talk-images"></div>' +
'<div class="attach-subitem">' +
'<p class="attach-p">' + Common._e("Attach a file") + '</p>' +
Interface.generateFileShare() +
'</div>' +
'</form>' +
'</div>' +
'</div>' +
'</div>' +
'<div class="content mixed"></div>' +
'<div class="footer">' +
'<div class="sync talk-images">' + Common._e("You are synchronized with your network.") + '</div>' +
'<div class="unsync talk-images">' + Common._e("Cannot send anything: you can only receive notices!") + '</div>' +
'<div class="fetch wait-small">' + Common._e("Fetching the social channel...") + '</div>' +
'</div>' +
'</div>';
html +=
'</div>' +
'</div>' +
'</div>' +
'</div>' +
'</div>' +
'</div>' +
'</div>';
// Create the HTML code
$('body').prepend(html);
// Adapt the roster size
Roster.adapt();
// Create JS events
self.events();
// Start the auto idle functions
Presence.liveIdle();
return true;
} catch(e) {
Console.error('Talk.create', e);
@ -299,25 +304,25 @@ var Talk = (function () {
try {
// Reset our database
DataStore.resetDB();
// Reset some vars
STANZA_ID = 1;
Roster.blist_all = false;
Presence.first_sent = false;
Search.search_filtered = false;
Avatar.pending = [];
JOIN_SUGGEST = [];
Groupchat.join_suggest = [];
// Kill all timers, exept the board ones
$('*:not(#board .one-board)').stopTime();
// Kill the auto idle functions
Presence.dieIdle();
// We renitalise the html markup as its initiale look
$('.removable').remove();
Interface.title('home');
// Finally we show the homepage
$('#home').show();
} catch(e) {

View file

@ -35,27 +35,28 @@ var Tooltip = (function () {
var path = '#' + hash;
var path_tooltip = path + ' .chat-tools-' + type;
var path_bubble = path_tooltip + ' .bubble-' + type;
// Yet exists?
if(Common.exists(path_bubble))
if(Common.exists(path_bubble)) {
return false;
}
// Generates special tooltip HTML code
var title = '';
var content = '';
switch(type) {
// Smileys
case 'smileys':
title = Common._e("Smiley insertion");
content = Smileys.links(hash);
break;
// Style
case 'style':
title = Common._e("Change style");
// Generate fonts list
var fonts = {
'arial': 'Arial, Helvetica, sans-serif',
@ -80,106 +81,106 @@ var Tooltip = (function () {
'webdings': 'Webdings, sans-serif',
'wingdings': 'Wingdings, \'Zapf Dingbats\', sans-serif'
};
var fonts_html = '<div class="font-list">';
// No fonts
fonts_html += '<a href="#">' + Common._e("None") + '</a>';
// Available fonts
$.each(fonts, function(id_name, full_name) {
// Generate short name
var short_name = full_name;
if(short_name.match(/,/)) {
var name_split = short_name.split(',');
short_name = $.trim(name_split[0]);
}
short_name = short_name.replace(/([^a-z0-9\s]+)/gi, '');
// Add this to the HTML
fonts_html += '<a href="#" data-value="' + Common.encodeQuotes(id_name) + '" data-font="' + Common.encodeQuotes(full_name) + '" style="font-family: ' + Common.encodeQuotes(full_name) + ';">' + short_name.htmlEnc() + '</a>';
});
fonts_html += '</div>';
content =
'<label class="font">' +
'<div class="font-icon talk-images"></div>' +
'<div class="fontsize-change">' +
'<a class="fontsize-current" href="#">12</a>' +
'<div class="fontsize-list">' +
'<a href="#" class="reset talk-images"></a>' +
'<a href="#" data-value="10" style="font-size: 10px;">10</a>' +
'<a href="#" data-value="12" style="font-size: 12px;">12</a>' +
'<a href="#" data-value="14" style="font-size: 14px;">14</a>' +
'<a href="#" data-value="16" style="font-size: 16px;">16</a>' +
'<a href="#" data-value="18" style="font-size: 18px;">18</a>' +
'</div>' +
'</div>' +
'<div class="font-change">' +
'<a class="font-current" href="#">' + Common._e("None") + '</a>' +
fonts_html +
'</div>' +
'</label>' +
'<label class="bold"><input type="checkbox" class="bold" />' + Common._e("Text in bold") + '</label>' +
'<label class="italic"><input type="checkbox" class="italic" />' + Common._e("Text in italic") + '</label>' +
'<label class="underline"><input type="checkbox" class="underline" />' + Common._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>' +
'<div class="color-picker">' +
'<a href="#" class="color-more talk-images"></a>' +
'<div class="color-hex">' +
'<span class="hex-begin">#</span>' +
'<input class="hex-value" type="text" maxlength="6" placeholder="e1e1e1" />' +
'</div>' +
content =
'<label class="font">' +
'<div class="font-icon talk-images"></div>' +
'<div class="fontsize-change">' +
'<a class="fontsize-current" href="#">12</a>' +
'<div class="fontsize-list">' +
'<a href="#" class="reset talk-images"></a>' +
'<a href="#" data-value="10" style="font-size: 10px;">10</a>' +
'<a href="#" data-value="12" style="font-size: 12px;">12</a>' +
'<a href="#" data-value="14" style="font-size: 14px;">14</a>' +
'<a href="#" data-value="16" style="font-size: 16px;">16</a>' +
'<a href="#" data-value="18" style="font-size: 18px;">18</a>' +
'</div>' +
'</div>' +
'<div class="font-change">' +
'<a class="font-current" href="#">' + Common._e("None") + '</a>' +
fonts_html +
'</div>' +
'</label>' +
'<label class="bold"><input type="checkbox" class="bold" />' + Common._e("Text in bold") + '</label>' +
'<label class="italic"><input type="checkbox" class="italic" />' + Common._e("Text in italic") + '</label>' +
'<label class="underline"><input type="checkbox" class="underline" />' + Common._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>' +
'<div class="color-picker">' +
'<a href="#" class="color-more talk-images"></a>' +
'<div class="color-hex">' +
'<span class="hex-begin">#</span>' +
'<input class="hex-value" type="text" maxlength="6" placeholder="e1e1e1" />' +
'</div>' +
'</div>';
break;
// File send
case 'file':
title = Common._e("Send a file");
content = '<p style="margin-bottom: 8px;">' + Common._e("Once uploaded, your friend will be prompted to download the file you sent.") + '</p>';
content += '<form id="oob-upload" action="./server/send.php" method="post" enctype="multipart/form-data">' + Interface.generateFileShare() + '</form>';
break;
// Chat log
case 'save':
title = Common._e("Save chat");
content = '<p style="margin-bottom: 8px;">' + Common._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">' + Common._e("Generate file!") + '</a>';
else
content += '<span class="tooltip-nolog">' + Common._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>' +
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
@ -188,9 +189,9 @@ var Tooltip = (function () {
$(path_tooltip + ' a.emoticon').click(function() {
return Interface.insertSmiley($(this).attr('data-smiley'), hash);
});
break;
// Style
case 'style':
// Paths to items
@ -207,198 +208,219 @@ var Tooltip = (function () {
var color = bubble_style + ' div.color-picker';
var color_more = color + ' a.color-more';
var color_hex = color + ' div.color-hex';
// Click event on style bubble
$(bubble_style).click(function() {
// Hide font selector if opened
if($(font_list).is(':visible'))
if($(font_list).is(':visible')) {
$(font_current).click();
}
// Hide font-size selector if opened
if($(fontsize_list).is(':visible'))
if($(fontsize_list).is(':visible')) {
$(fontsize_current).click();
}
// Hide color selector if opened
if($(color_hex).is(':visible'))
if($(color_hex).is(':visible')) {
$(color_more).click();
}
});
// Click event on font picker
$(font_current).click(function() {
var this_sel = $(this);
// The clicked color is yet selected
if($(font_list).is(':visible'))
$(this).parent().removeClass('listed');
else
$(this).parent().addClass('listed');
if($(font_list).is(':visible')) {
this_sel.parent().removeClass('listed');
} else {
this_sel.parent().addClass('listed');
}
return false;
});
// Click event on a new font in the picker
$(font_select).click(function() {
var this_sel = $(this);
// No font selected
if(!$(this).attr('data-value')) {
if(!this_sel.attr('data-value')) {
$(font_current).removeAttr('data-font')
.removeAttr('data-value')
.text(Common._e("None"));
$(message_area).removeAttr('data-font');
} else {
$(font_current).attr('data-font', this_sel.attr('data-font'))
.attr('data-value', this_sel.attr('data-value'))
.text($(font_list).find('a[data-value="' + this_sel.attr('data-value') + '"]').text());
$(message_area).attr('data-font', this_sel.attr('data-value'));
}
// A font is defined
else {
$(font_current).attr('data-font', $(this).attr('data-font'))
.attr('data-value', $(this).attr('data-value'))
.text($(font_list).find('a[data-value="' + $(this).attr('data-value') + '"]').text());
$(message_area).attr('data-font', $(this).attr('data-value'));
}
return false;
});
// Click event on font-size picker
$(fontsize_current).click(function() {
var this_sel = $(this);
// The clicked color is yet selected
if($(fontsize_list).is(':visible'))
$(this).parent().removeClass('listed');
else
$(this).parent().addClass('listed');
if($(fontsize_list).is(':visible')) {
this_sel.parent().removeClass('listed');
} else {
this_sel.parent().addClass('listed');
}
return false;
});
// Click event on a new font-size in the picker
$(fontsize_select).click(function() {
var this_sel = $(this);
// No font-size selected
if(!$(this).attr('data-value')) {
if(!this_sel.attr('data-value')) {
$(fontsize_current).removeAttr('data-value').text(Common._e("16"));
$(message_area).removeAttr('data-fontsize');
}
// A font-size is defined
else {
$(fontsize_current).attr('data-value', $(this).attr('data-value'))
.text($(this).attr('data-value'));
$(message_area).attr('data-fontsize', $(this).attr('data-value'));
$(fontsize_current).attr('data-value', this_sel.attr('data-value'))
.text(this_sel.attr('data-value'));
$(message_area).attr('data-fontsize', this_sel.attr('data-value'));
}
return false;
});
// Click event on color picker
$(colors).click(function() {
var this_sel = $(this);
// Reset the manual picker
$(color_hex).find('input').val('');
// The clicked color is yet selected
if($(this).hasClass('selected')) {
if(this_sel.hasClass('selected')) {
$(message_area).removeAttr('data-color');
$(this).removeClass('selected');
this_sel.removeClass('selected');
}
else {
$(message_area).attr('data-color', $(this).attr('data-color'));
$(message_area).attr('data-color', this_sel.attr('data-color'));
$(colors).removeClass('selected');
$(this).addClass('selected');
this_sel.addClass('selected');
}
return false;
});
// Click event on color picker
$(color_more).click(function() {
var this_sel = $(this);
// The clicked color is yet selected
if($(color_hex).is(':visible'))
$(this).parent().removeClass('opened');
else {
$(this).parent().addClass('opened');
if($(color_hex).is(':visible')) {
this_sel.parent().removeClass('opened');
} else {
this_sel.parent().addClass('opened');
// Focus
$(document).oneTime(10, function() {
$(color_hex).find('input').focus();
});
}
return false;
});
// Click event on color hex
$(color_hex).click(function() {
return false;
});
// Keyup event on color picker
$(color_hex).find('input').keyup(function(e) {
var this_sel = $(this);
// Submit
if(e.keyCode == 13) {
if($(color_hex).is(':visible')) {
$(color_more).click();
// Focus again on the message textarea
$(document).oneTime(10, function() {
$(message_area).focus();
});
}
return false;
}
// Reset current color
$(message_area).removeAttr('data-color');
$(colors).removeClass('selected');
// Change value
var new_value = $(this).val().replace(/([^a-z0-9]+)/gi, '');
$(this).val(new_value);
if(new_value)
var new_value = this_sel.val().replace(/([^a-z0-9]+)/gi, '');
this_sel.val(new_value);
if(new_value) {
$(message_area).attr('data-color', new_value);
}
// Regenerate style
var style = Message.generateStyle(hash);
// Any style to apply?
if(style)
if(style) {
$(message_area).attr('style', style);
else
} else {
$(message_area).removeAttr('style');
}
}).placeholder();
// Change event on text style checkboxes
$(style).change(function() {
var this_sel = $(this);
// Get current type
var style_data = 'data-' + $(this).attr('class');
var style_data = 'data-' + this_sel.attr('class');
// Checked checkbox?
if($(this).filter(':checked').size())
if(this_sel.filter(':checked').size()) {
$(message_area).attr(style_data, true);
else
} else {
$(message_area).removeAttr(style_data);
}
});
// Update the textarea style when it is changed
$(style + ', ' + colors + ', ' + font_select + ', ' + fontsize_select).click(function() {
var style = Message.generateStyle(hash);
// Any style to apply?
if(style)
if(style) {
$(message_area).attr('style', style);
else
} else {
$(message_area).removeAttr('style');
}
// Focus again on the message textarea
$(document).oneTime(10, function() {
$(message_area).focus();
});
});
// Load current style
self.loadStyleSelector(hash);
break;
// File send
case 'file':
// File upload vars
@ -407,34 +429,41 @@ var Tooltip = (function () {
beforeSubmit: OOB.waitUpload,
success: OOB.handleUpload
};
// Upload form submit event
$(path_tooltip + ' #oob-upload').submit(function() {
if($(path_tooltip + ' #oob-upload input[type="file"]').val())
$(this).ajaxSubmit(oob_upload_options);
var this_sel = $(this);
if($(path_tooltip + ' #oob-upload input[type="file"]').val()) {
this_sel.ajaxSubmit(oob_upload_options);
}
return false;
});
// Upload input change event
$(path_tooltip + ' #oob-upload input[type="file"]').change(function() {
if($(this).val())
var this_sel = $(this);
if(this_sel.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(Common.exists(path_tooltip + ' #oob-upload input[type="reset"]'))
if(Common.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="' + Common._e("Cancel") + '" />');
// Cancel button click event
$(path_tooltip + ' #oob-upload input[type="reset"]').click(function() {
// Remove the bubble
@ -442,24 +471,24 @@ var Tooltip = (function () {
self.destroy(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">' + Common._e("Please wait...") + '</span>');
Interface.generateChatLog(xid, hash);
return false;
});
break;
}
return true;
} catch(e) {
Console.error('Tooltip.create', e);
@ -524,7 +553,7 @@ var Tooltip = (function () {
self.hover(xid, hash, 'style');
self.hover(xid, hash, 'file');
self.hover(xid, hash, 'save');
// Click events
$('#' + hash + ' a.chat-tools-content, #' + hash + ' .chat-tools-content a').click(function() {
return false;
@ -553,33 +582,37 @@ var Tooltip = (function () {
var font_select = $(bubble_style + ' div.font-list').find('a[data-value="' + font + '"]');
var fontsize = message_area.attr('data-fontsize');
var color = message_area.attr('data-color');
// Apply message font
if(font) {
$(bubble_style + ' a.font-current').attr('data-value', font)
.attr('data-font', font_select.attr('data-font'))
.text(font_select.text());
}
// Apply message font-size
if(fontsize) {
$(bubble_style + ' a.fontsize-current').attr('data-value', fontsize)
.text(fontsize);
}
// Apply the options to the style selector
$(bubble_style + ' input[type="checkbox"]').each(function() {
var this_sel = $(this);
// Current input enabled?
if(message_area.attr('data-' + $(this).attr('class')))
$(this).attr('checked', true);
if(message_area.attr('data-' + this_sel.attr('class'))) {
this_sel.attr('checked', true);
}
});
// Apply message color
if(color) {
if($(bubble_style + ' a.color[data-color="' + color + '"]').size())
if($(bubble_style + ' a.color[data-color="' + color + '"]').size()) {
$(bubble_style + ' a.color[data-color="' + color + '"]').addClass('selected');
else
} else {
$(bubble_style + ' div.color-hex input.hex-value').val(color);
}
}
} catch(e) {
Console.error('Tooltip.loadStyleSelector', e);

View file

@ -31,91 +31,91 @@ var UserInfos = (function () {
try {
// Can show shortcuts?
var shortcuts = '';
if(xid != Common.getXID()) {
shortcuts = '<div class="shortcuts">' +
'<a href="#" class="message talk-images" title="' + Common._e("Send him/her a message") + '" onclick="UserInfos.close(); return Inbox.composeMessage(\'' + Utils.encodeOnclick(xid) + '\');"></a>' +
'<a href="#" class="chat talk-images" title="' + Common._e("Start a chat with him/her") + '" onclick="UserInfos.close(); return Chat.checkCreate(\'' + Utils.encodeOnclick(xid) + '\', \'chat\');"></a>' +
'<a href="#" class="command talk-images" title="' + Common._e("Command") + '" onclick="UserInfos.close(); return AdHoc.retrieve(\'' + Utils.encodeOnclick(xid) + '\');"></a>' +
shortcuts = '<div class="shortcuts">' +
'<a href="#" class="message talk-images" title="' + Common._e("Send him/her a message") + '" onclick="UserInfos.close(); return Inbox.composeMessage(\'' + Utils.encodeOnclick(xid) + '\');"></a>' +
'<a href="#" class="chat talk-images" title="' + Common._e("Start a chat with him/her") + '" onclick="UserInfos.close(); return Chat.checkCreate(\'' + Utils.encodeOnclick(xid) + '\', \'chat\');"></a>' +
'<a href="#" class="command talk-images" title="' + Common._e("Command") + '" onclick="UserInfos.close(); return AdHoc.retrieve(\'' + Utils.encodeOnclick(xid) + '\');"></a>' +
'</div>';
}
// Popup HTML content
var html =
'<div class="top">' + Common._e("User profile") + '</div>' +
'<div class="tab">' +
'<a href="#" class="tab-active" data-key="1">' + Common._e("General") + '</a>' +
'<a href="#" data-key="2">' + Common._e("Advanced") + '</a>' +
'<a href="#" data-key="3">' + Common._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="' + './images/others/default-avatar.png' + '" alt="" />' +
'</div>' +
'<h1 id="BUDDY-FN" class="reset-info">' + Common._e("unknown") + '</h1>' +
'<h2 class="buddy-xid" class="reset-info">' + Common._e("unknown") + '</h2>' +
'<h3 class="buddy-last" class="reset-info">' + Common._e("unknown") + '</h3>' +
shortcuts +
'</div>' +
'<div class="block-infos">' +
'<div class="one-line"><b class="line-label">' + Common._e("Date of birth") + '</b><span id="BUDDY-BDAY" class="reset-info">' + Common._e("unknown") + '</span></div>' +
'<div class="one-line"><b class="line-label">' + Common._e("E-mail") + '</b><span id="BUDDY-EMAIL-USERID" class="reset-info">' + Common._e("unknown") + '</span></div>' +
'<div class="one-line"><b class="line-label">' + Common._e("Phone") + '</b><span id="BUDDY-TEL-NUMBER" class="reset-info">' + Common._e("unknown") + '</span></div>' +
'<div class="one-line"><b class="line-label">' + Common._e("Website") + '</b><span id="BUDDY-URL" class="reset-info">' + Common._e("unknown") + '</span></div>' +
'</div>' +
'<div class="block-infos">' +
'<div class="one-line"><b class="line-label">' + Common._e("Client") + '</b><span id="BUDDY-CLIENT" class="reset-info">' + Common._e("unknown") + '</span></div>' +
'<div class="one-line"><b class="line-label">' + Common._e("System") + '</b><span id="BUDDY-SYSTEM" class="reset-info">' + Common._e("unknown") + '</span></div>' +
'<div class="one-line"><b class="line-label">' + Common._e("Local time") + '</b><span id="BUDDY-TIME" class="reset-info">' + Common._e("unknown") + '</span></div>' +
'</div>' +
'</div>' +
'<div class="one-lap info2">' +
'<div class="block-infos">' +
'<div class="one-line"><b class="line-label">' + Common._e("Street") + '</b><span id="BUDDY-ADR-STREET" class="reset-info">' + Common._e("unknown") + '</span></div>' +
'<div class="one-line"><b class="line-label">' + Common._e("City") + '</b><span id="BUDDY-ADR-LOCALITY" class="reset-info">' + Common._e("unknown") + '</span></div>' +
'<div class="one-line"><b class="line-label">' + Common._e("Postal code") + '</b><span id="BUDDY-ADR-PCODE" class="reset-info">' + Common._e("unknown") + '</span></div>' +
'<div class="one-line"><b class="line-label">' + Common._e("Country") + '</b><span id="BUDDY-ADR-CTRY" class="reset-info">' + Common._e("unknown") + '</span></div>' +
'</div>' +
'<div class="block-infos">' +
'<div class="one-line"><b class="line-label">' + Common._e("Biography") + '</b><span id="BUDDY-DESC" class="reset-info">' + Common._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">' + Common._e("Close") + '</a>' +
var html =
'<div class="top">' + Common._e("User profile") + '</div>' +
'<div class="tab">' +
'<a href="#" class="tab-active" data-key="1">' + Common._e("General") + '</a>' +
'<a href="#" data-key="2">' + Common._e("Advanced") + '</a>' +
'<a href="#" data-key="3">' + Common._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="' + './images/others/default-avatar.png' + '" alt="" />' +
'</div>' +
'<h1 id="BUDDY-FN" class="reset-info">' + Common._e("unknown") + '</h1>' +
'<h2 class="buddy-xid" class="reset-info">' + Common._e("unknown") + '</h2>' +
'<h3 class="buddy-last" class="reset-info">' + Common._e("unknown") + '</h3>' +
shortcuts +
'</div>' +
'<div class="block-infos">' +
'<div class="one-line"><b class="line-label">' + Common._e("Date of birth") + '</b><span id="BUDDY-BDAY" class="reset-info">' + Common._e("unknown") + '</span></div>' +
'<div class="one-line"><b class="line-label">' + Common._e("E-mail") + '</b><span id="BUDDY-EMAIL-USERID" class="reset-info">' + Common._e("unknown") + '</span></div>' +
'<div class="one-line"><b class="line-label">' + Common._e("Phone") + '</b><span id="BUDDY-TEL-NUMBER" class="reset-info">' + Common._e("unknown") + '</span></div>' +
'<div class="one-line"><b class="line-label">' + Common._e("Website") + '</b><span id="BUDDY-URL" class="reset-info">' + Common._e("unknown") + '</span></div>' +
'</div>' +
'<div class="block-infos">' +
'<div class="one-line"><b class="line-label">' + Common._e("Client") + '</b><span id="BUDDY-CLIENT" class="reset-info">' + Common._e("unknown") + '</span></div>' +
'<div class="one-line"><b class="line-label">' + Common._e("System") + '</b><span id="BUDDY-SYSTEM" class="reset-info">' + Common._e("unknown") + '</span></div>' +
'<div class="one-line"><b class="line-label">' + Common._e("Local time") + '</b><span id="BUDDY-TIME" class="reset-info">' + Common._e("unknown") + '</span></div>' +
'</div>' +
'</div>' +
'<div class="one-lap info2">' +
'<div class="block-infos">' +
'<div class="one-line"><b class="line-label">' + Common._e("Street") + '</b><span id="BUDDY-ADR-STREET" class="reset-info">' + Common._e("unknown") + '</span></div>' +
'<div class="one-line"><b class="line-label">' + Common._e("City") + '</b><span id="BUDDY-ADR-LOCALITY" class="reset-info">' + Common._e("unknown") + '</span></div>' +
'<div class="one-line"><b class="line-label">' + Common._e("Postal code") + '</b><span id="BUDDY-ADR-PCODE" class="reset-info">' + Common._e("unknown") + '</span></div>' +
'<div class="one-line"><b class="line-label">' + Common._e("Country") + '</b><span id="BUDDY-ADR-CTRY" class="reset-info">' + Common._e("unknown") + '</span></div>' +
'</div>' +
'<div class="block-infos">' +
'<div class="one-line"><b class="line-label">' + Common._e("Biography") + '</b><span id="BUDDY-DESC" class="reset-info">' + Common._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">' + Common._e("Close") + '</a>' +
'</div>';
// Create the popup
Popup.create('userinfos', html);
// Associate the events
UserInfos.instance();
// We retrieve the user's vcard
self.retrieve(xid);
} catch(e) {
@ -137,7 +137,7 @@ var UserInfos = (function () {
try {
// Send the buddy comments
self.sendBuddyComments();
// Destroy the popup
Popup.destroy('userinfos');
} catch(e) {
@ -160,38 +160,38 @@ var UserInfos = (function () {
try {
// We setup the waiting indicator
markers = 'vcard last';
// We put the user's XID
$('#userinfos .buddy-xid').text(xid);
// We get the vCard
vCard.get(xid, 'buddy');
// Get the highest resource for this XID
var cXID = Presence.highestPriority(xid);
var pXID = xid;
// If the user is logged in
if(cXID) {
// Change the XID
pXID = cXID;
// We request the user's system infos
self.query(cXID, 'version');
// We request the user's local time
self.query(cXID, 'time');
// Add these to the markers
markers += ' version time';
}
// We request the user's last activity
self.query(pXID, 'last');
// Add the markers
$('#userinfos .content').addClass(markers);
// We request all the user's comments
self.displayBuddyComments(xid);
} catch(e) {
@ -214,26 +214,26 @@ var UserInfos = (function () {
// 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, self.lastActivityUserInfos);
}
// Time query
else if(mode == 'time') {
iq.appendNode('time', {'xmlns': NS_URN_TIME});
con.send(iq, self.localTime);
}
// Version query
else if(mode == 'version') {
iq.setQuery(NS_VERSION);
@ -273,7 +273,7 @@ var UserInfos = (function () {
try {
var value = DataStore.getDB(Connection.desktop_hash, 'rosternotes', xid);
if(value) {
$('#userinfos .rosternotes').val(value);
}
@ -296,26 +296,28 @@ var UserInfos = (function () {
// Extract the request ID
var id = iq.getID();
var path = '#userinfos[data-last="' + id + '"]';
// End if session does not exist
if(!Common.exists(path))
if(!Common.exists(path)) {
return;
}
if(iq && (iq.getType() == 'result')) {
// Get the values
var from = Common.fullXID(Common.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)
if(seconds <= 60) {
last = Common._e("User currently active");
}
// Inactive user
else {
// Parse the date
@ -323,23 +325,25 @@ var UserInfos = (function () {
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)
if(from.indexOf('/') == -1) {
last = Common.printf(Common._e("Last seen: %s"), date);
}
// Online user
else
else {
last = Common.printf(Common._e("Inactive since: %s"), date);
}
}
// Append this text
$('#userinfos .buddy-last').text(last);
}
Console.log('Last activity received: ' + from);
}
$('#userinfos .content').removeClass('last');
self.wait();
} catch(e) {
@ -361,11 +365,12 @@ var UserInfos = (function () {
// Extract the request ID
var id = iq.getID();
var path = '#userinfos[data-version="' + id + '"]';
// End if session does not exist
if(!Common.exists(path))
if(!Common.exists(path)) {
return;
}
// Extract the reply data
if(iq && (iq.getType() == 'result')) {
// Get the values
@ -373,20 +378,24 @@ var UserInfos = (function () {
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)
if(name && version) {
name = name + ' ' + version;
}
// Display the values
if(name)
if(name) {
$(path + ' #BUDDY-CLIENT').text(name);
if(os)
}
if(os) {
$(path + ' #BUDDY-SYSTEM').text(os);
}
Console.log('Software version received: ' + Common.fullXID(Common.getStanzaFrom(iq)));
}
$('#userinfos .content').removeClass('version');
self.wait();
} catch(e) {
@ -408,33 +417,35 @@ var UserInfos = (function () {
// Extract the request ID
var id = iq.getID();
var path = '#userinfos[data-time="' + id + '"]';
// End if session does not exist
if(!Common.exists(path))
if(!Common.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$/))
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);
}
Console.log('Local time received: ' + Common.fullXID(Common.getStanzaFrom(iq)));
}
$('#userinfos .content').removeClass('time');
self.wait();
} catch(e) {
@ -453,9 +464,10 @@ var UserInfos = (function () {
try {
var selector = $('#userinfos .content');
if(!selector.hasClass('vcard') && !selector.hasClass('last') && !selector.hasClass('version') && !selector.hasClass('time'))
if(!selector.hasClass('vcard') && !selector.hasClass('last') && !selector.hasClass('version') && !selector.hasClass('time')) {
$('#userinfos .wait').hide();
}
} catch(e) {
Console.error('UserInfos.wait', e);
}
@ -474,41 +486,43 @@ var UserInfos = (function () {
// Update the current value
var value = $('#userinfos .rosternotes').val();
var xid = $('#userinfos .buddy-xid').text();
// Necessary to update?
var old_value = DataStore.getDB(Connection.desktop_hash, 'rosternotes', xid);
if((old_value == value) || (!old_value && !value))
if((old_value == value) || (!old_value && !value)) {
return false;
}
// Update the database
DataStore.setDB(Connection.desktop_hash, '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
var db_regex = new RegExp(('^' + Connection.desktop_hash + '_') + 'rosternotes' + ('_(.+)'));
for(var i = 0; i < DataStore.storageDB.length; i++) {
// Get the pointer values
var current = DataStore.storageDB.key(i);
// If the pointer is on a stored rosternote
if(current.match(db_regex)) {
var cur_xid = RegExp.$1;
var cur_value = DataStore.storageDB.getItem(current);
if(cur_xid && cur_value)
if(cur_xid && cur_value) {
storage.appendChild(iq.buildNode('note', {'jid': cur_xid, 'xmlns': NS_ROSTERNOTES}, cur_value));
}
}
}
con.send(iq);
return false;
} catch(e) {
Console.error('UserInfos.sendBuddyComments', e);
@ -526,10 +540,15 @@ var UserInfos = (function () {
self.switchTab = function(id) {
try {
$('#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');
var userinfos_sel = $('#userinfos');
var content_sel = userinfos_sel.find('.content');
var tab_link_sel = userinfos_sel.find('.tab a');
content_sel.find('.one-lap').hide();
content_sel.find('.info' + id).show();
tab_link_sel.removeClass('tab-active');
tab_link_sel.filter('[data-key="' + id + '"]').addClass('tab-active');
} catch(e) {
Console.error('UserInfos.switchTab', e);
} finally {
@ -558,11 +577,11 @@ var UserInfos = (function () {
$('#' + hash + ' .top .name .bc-name').text(nick);
$('#page-switch .' + hash + ' .name').text(nick);
}
// Get the buddy PEP informations
PEP.displayAll(xid);
}
// Display the buddy presence
Presence.funnel(xid, hash);
} catch(e) {
@ -582,16 +601,19 @@ var UserInfos = (function () {
try {
// Click events
$('#userinfos .tab a').click(function() {
var this_sel = $(this);
// Yet active?
if($(this).hasClass('tab-active'))
if(this_sel.hasClass('tab-active')) {
return false;
}
// Switch to the good tab
var key = parseInt($(this).attr('data-key'));
var key = parseInt(this_sel.attr('data-key'));
return self.switchTab(key);
});
$('#userinfos .bottom .finish').click(function() {
return self.close();
});

View file

@ -52,9 +52,10 @@ var Utils = (function () {
try {
// HTTPS not allowed
if((HTTPS_STORAGE != 'on') && url.match(/^https(.+)/))
if((HTTPS_STORAGE != 'on') && url.match(/^https(.+)/)) {
url = 'http' + RegExp.$1;
}
return url;
} catch(e) {
Console.error('Utils.generateURL', e);
@ -76,7 +77,7 @@ var Utils = (function () {
if(value == condition) {
return ' disabled=""';
}
return '';
} catch(e) {
Console.error('Utils.disableInput', e);
@ -99,7 +100,7 @@ var Utils = (function () {
if(string.length > limit) {
string = string.substr(0, limit) + '...';
}
return string;
} catch(e) {
Console.error('Utils.truncate', e);
@ -215,31 +216,37 @@ var Utils = (function () {
// Get browser name & version
var browser_name = BrowserDetect.browser;
var browser_version = BrowserDetect.version;
// No DOM storage
if(!DataStore.hasDB() || !DataStore.hasPersistent())
if(!DataStore.hasDB() || !DataStore.hasPersistent()) {
return true;
}
// Obsolete IE
if((browser_name == 'Explorer') && (browser_version < 8))
if((browser_name == 'Explorer') && (browser_version < 8)) {
return true;
}
// Obsolete Chrome
if((browser_name == 'Chrome') && (browser_version < 7))
if((browser_name == 'Chrome') && (browser_version < 7)) {
return true;
}
// Obsolete Safari
if((browser_name == 'Safari') && (browser_version < 4))
if((browser_name == 'Safari') && (browser_version < 4)) {
return true;
}
// Obsolete Firefox
if((browser_name == 'Firefox') && (browser_version < 3.5))
if((browser_name == 'Firefox') && (browser_version < 3.5)) {
return true;
}
// Obsolete Opera
if((browser_name == 'Opera') && (browser_version < 9))
if((browser_name == 'Opera') && (browser_version < 9)) {
return true;
}
return false;
} catch(e) {
Console.error('Utils.isObsolete', e);
@ -341,7 +348,7 @@ var Utils = (function () {
} catch(e) {
Console.error('Utils.quoteMyNick', e);
}
};
@ -355,7 +362,7 @@ var Utils = (function () {
try {
var cat;
switch(ext) {
// Images
case 'jpg':
@ -371,9 +378,9 @@ var Utils = (function () {
case 'psb':
case 'xcf':
cat = 'image';
break;
// Videos
case 'ogv':
case 'ogg':
@ -395,9 +402,9 @@ var Utils = (function () {
case '3gp':
case 'avc':
cat = 'video';
break;
// Sounds
case 'oga':
case 'mka':
@ -422,9 +429,9 @@ var Utils = (function () {
case 'snd':
case 'voc':
cat = 'audio';
break;
// Documents
case 'pdf':
case 'odt':
@ -463,9 +470,9 @@ var Utils = (function () {
case 'dhtml':
case 'mshtml':
cat = 'document';
break;
// Packages
case 'tgz':
case 'gz':
@ -490,16 +497,16 @@ var Utils = (function () {
case 'arj':
case 'msi':
cat = 'package';
break;
// Others
default:
cat = 'other';
break;
}
return cat;
} catch(e) {
Console.error('Utils.fileCategory', e);
@ -517,7 +524,7 @@ var Utils = (function () {
try {
navigator.registerProtocolHandler('xmpp', JAPPIX_LOCATION + '?x=%s', SERVICE_NAME);
return true;
} catch(e) {
Console.error('Utils.xmppLinksHandler', e);
@ -585,6 +592,33 @@ var Utils = (function () {
};
/**
* Removes duplicate values from array
* @public
* @param {object} arr
* @return {object}
*/
self.uniqueArrayValues = function(arr) {
try {
var a = arr.concat();
for(var i = 0; i < a.length; ++i) {
for(var j = i + 1; j < a.length; ++j) {
if(a[i] === a[j]) {
a.splice(j--, 1);
}
}
}
return a;
} catch(e) {
Console.error('Utils.uniqueArrayValues', e);
}
};
/**
* Converts a string to an array
* @public
@ -595,26 +629,27 @@ var Utils = (function () {
try {
var array = [];
// Any string to convert?
if(string) {
// More than one item
if(string.match(/,/gi)) {
var string_split = string.split(',');
for(var i in string_split) {
if(string_split[i])
if(string_split[i]) {
array.push(string_split[i]);
else
} else {
array.push('');
}
}
}
// Only one item
else
array.push(string);
}
return array;
} catch(e) {
Console.error('Utils.stringToArray', e);
@ -634,20 +669,21 @@ var Utils = (function () {
try {
// Nothing?
if(!array || !array.length)
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;
} catch(e) {
Console.error('Utils.indexArrayValue', e);

View file

@ -30,122 +30,122 @@ var vCard = (function () {
try {
// Popup HTML content
var html =
'<div class="top">' + Common._e("Your profile") + '</div>' +
'<div class="tab">' +
'<a href="#" class="tab-active" data-key="1">' + Common._e("Identity") + '</a>' +
'<a href="#" data-key="2">' + Common._e("Profile image") + '</a>' +
'<a href="#" data-key="3">' + Common._e("Others") + '</a>' +
'</div>' +
'<div class="content">' +
'<div id="lap1" class="lap-active one-lap forms">' +
'<fieldset>' +
'<legend>' + Common._e("Personal") + '</legend>' +
'<label for="USER-FN">' + Common._e("Complete name") + '</label>' +
'<input type="text" id="USER-FN" data-vcard4="fn-text" class="vcard-item" placeholder="John Locke" />' +
'<label for="USER-NICKNAME">' + Common._e("Nickname") + '</label>' +
'<input type="text" id="USER-NICKNAME" data-vcard4="nickname-text" class="vcard-item" placeholder="Jo" />' +
'<label for="USER-N-GIVEN">' + Common._e("First name") + '</label>' +
'<input type="text" id="USER-N-GIVEN" data-vcard4="n-given" class="vcard-item" placeholder="John" />' +
'<label for="USER-N-FAMILY">' + Common._e("Last name") + '</label>' +
'<input type="text" id="USER-N-FAMILY" data-vcard4="n-surname" class="vcard-item" placeholder="Locke" />' +
'<label for="USER-BDAY">' + Common._e("Date of birth") + '</label>' +
'<input type="text" id="USER-BDAY" data-vcard4="bday-date" class="vcard-item" pattern="^[0-9]{2}-[0-9]{2}-[0-9]{4}$" placeholder="16-02-1974" />' +
'</fieldset>' +
'<fieldset>' +
'<legend>' + Common._e("Contact") + '</legend>' +
'<label for="USER-EMAIL-USERID">' + Common._e("E-mail") + '</label>' +
'<input type="text" id="USER-EMAIL-USERID" data-vcard4="email-text" class="vcard-item" placeholder="john@locke.fam" />' +
'<label for="USER-TEL-NUMBER">' + Common._e("Phone") + '</label>' +
'<input type="text" id="USER-TEL-NUMBER" data-vcard4="tel-uri" class="vcard-item" placeholder="John" placeholder="+1-292-321-0812" />' +
'<label for="USER-URL">' + Common._e("Website") + '</label>' +
'<input type="text" id="USER-URL" data-vcard4="url-uri" class="vcard-item" placeholder="john.locke.fam" />' +
'</fieldset>' +
'</div>' +
'<div id="lap2" class="one-lap forms">' +
'<fieldset>' +
'<legend>' + Common._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="./server/avatar-upload.php" method="post" enctype="multipart/form-data">' +
Interface.generateFileShare() +
'</form>' +
'</fieldset>' +
'<fieldset>' +
'<legend>' + Common._e("Current") + '</legend>' +
'<div class="avatar-container"></div>' +
'<a href="#" class="one-button avatar-delete talk-images">' + Common._e("Delete") + '</a>' +
'<div class="no-avatar">' + Common._e("What a pity! You have no profile image defined in your identity card!") + '</div>' +
'</fieldset>' +
'<div class="avatar-wait avatar-info">' + Common._e("Please wait while your avatar is uploaded...") + '</div>' +
'<div class="avatar-ok avatar-info">' + Common._e("Here it is! A new beautiful profile image!") + '</div>' +
'<div class="avatar-error avatar-info">' + Common._e("The image file is not supported or has a bad size.") + '</div>' +
'</div>' +
'<div id="lap3" class="one-lap forms">' +
'<fieldset>' +
'<legend>' + Common._e("Address") + '</legend>' +
'<label for="USER-ADR-STREET">' + Common._e("Street") + '</label>' +
'<input type="text" id="USER-ADR-STREET" data-vcard4="adr-street" class="vcard-item" placeholder="Manhattan" />' +
'<label for="USER-ADR-LOCALITY">' + Common._e("City") + '</label>' +
'<input type="text" id="USER-ADR-LOCALITY" data-vcard4="adr-locality" class="vcard-item" placeholder="New-York" />' +
'<label for="USER-ADR-PCODE">' + Common._e("Postal code") + '</label>' +
'<input type="text" id="USER-ADR-PCODE" data-vcard4="adr-code" class="vcard-item" placeholder="10002" />' +
'<label for="USER-ADR-CTRY">' + Common._e("Country") + '</label>' +
'<input type="text" id="USER-ADR-CTRY" data-vcard4="adr-country" class="vcard-item" placeholder="USA" />' +
'</fieldset>' +
'<fieldset>' +
'<legend>' + Common._e("Biography") + '</legend>' +
'<textarea id="USER-DESC" data-vcard4="note-text" rows="8" cols="60" class="vcard-item"></textarea>' +
'</fieldset>' +
'</div>' +
'<div class="infos">' +
'<p class="infos-title">' + Common._e("Important notice") + '</p>' +
'<p>' + Common._e("Be careful with the information you store into your profile, because it might be accessible by everyone (even someone you don't want to).") + '</p>' +
'<p>' + Common._e("Not everything is private on XMPP; this is one of those things, your public profile (vCard).") + '</p>' +
'<p>' + Common.printf(Common._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><b><a href="https://me.jappix.com/new" target="_blank">' + Common._e("Enable my public profile") + ' »</a></b></p>' +
'</div>' +
'</div>' +
'<div class="bottom">' +
'<div class="wait wait-medium"></div>' +
'<a href="#" class="finish save disabled">' + Common._e("Save") + '</a>' +
'<a href="#" class="finish cancel">' + Common._e("Cancel") + '</a>' +
'<div class="top">' + Common._e("Your profile") + '</div>' +
'<div class="tab">' +
'<a href="#" class="tab-active" data-key="1">' + Common._e("Identity") + '</a>' +
'<a href="#" data-key="2">' + Common._e("Profile image") + '</a>' +
'<a href="#" data-key="3">' + Common._e("Others") + '</a>' +
'</div>' +
'<div class="content">' +
'<div id="lap1" class="lap-active one-lap forms">' +
'<fieldset>' +
'<legend>' + Common._e("Personal") + '</legend>' +
'<label for="USER-FN">' + Common._e("Complete name") + '</label>' +
'<input type="text" id="USER-FN" data-vcard4="fn-text" class="vcard-item" placeholder="John Locke" />' +
'<label for="USER-NICKNAME">' + Common._e("Nickname") + '</label>' +
'<input type="text" id="USER-NICKNAME" data-vcard4="nickname-text" class="vcard-item" placeholder="Jo" />' +
'<label for="USER-N-GIVEN">' + Common._e("First name") + '</label>' +
'<input type="text" id="USER-N-GIVEN" data-vcard4="n-given" class="vcard-item" placeholder="John" />' +
'<label for="USER-N-FAMILY">' + Common._e("Last name") + '</label>' +
'<input type="text" id="USER-N-FAMILY" data-vcard4="n-surname" class="vcard-item" placeholder="Locke" />' +
'<label for="USER-BDAY">' + Common._e("Date of birth") + '</label>' +
'<input type="text" id="USER-BDAY" data-vcard4="bday-date" class="vcard-item" pattern="^[0-9]{2}-[0-9]{2}-[0-9]{4}$" placeholder="16-02-1974" />' +
'</fieldset>' +
'<fieldset>' +
'<legend>' + Common._e("Contact") + '</legend>' +
'<label for="USER-EMAIL-USERID">' + Common._e("E-mail") + '</label>' +
'<input type="text" id="USER-EMAIL-USERID" data-vcard4="email-text" class="vcard-item" placeholder="john@locke.fam" />' +
'<label for="USER-TEL-NUMBER">' + Common._e("Phone") + '</label>' +
'<input type="text" id="USER-TEL-NUMBER" data-vcard4="tel-uri" class="vcard-item" placeholder="John" placeholder="+1-292-321-0812" />' +
'<label for="USER-URL">' + Common._e("Website") + '</label>' +
'<input type="text" id="USER-URL" data-vcard4="url-uri" class="vcard-item" placeholder="john.locke.fam" />' +
'</fieldset>' +
'</div>' +
'<div id="lap2" class="one-lap forms">' +
'<fieldset>' +
'<legend>' + Common._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="./server/avatar-upload.php" method="post" enctype="multipart/form-data">' +
Interface.generateFileShare() +
'</form>' +
'</fieldset>' +
'<fieldset>' +
'<legend>' + Common._e("Current") + '</legend>' +
'<div class="avatar-container"></div>' +
'<a href="#" class="one-button avatar-delete talk-images">' + Common._e("Delete") + '</a>' +
'<div class="no-avatar">' + Common._e("What a pity! You have no profile image defined in your identity card!") + '</div>' +
'</fieldset>' +
'<div class="avatar-wait avatar-info">' + Common._e("Please wait while your avatar is uploaded...") + '</div>' +
'<div class="avatar-ok avatar-info">' + Common._e("Here it is! A new beautiful profile image!") + '</div>' +
'<div class="avatar-error avatar-info">' + Common._e("The image file is not supported or has a bad size.") + '</div>' +
'</div>' +
'<div id="lap3" class="one-lap forms">' +
'<fieldset>' +
'<legend>' + Common._e("Address") + '</legend>' +
'<label for="USER-ADR-STREET">' + Common._e("Street") + '</label>' +
'<input type="text" id="USER-ADR-STREET" data-vcard4="adr-street" class="vcard-item" placeholder="Manhattan" />' +
'<label for="USER-ADR-LOCALITY">' + Common._e("City") + '</label>' +
'<input type="text" id="USER-ADR-LOCALITY" data-vcard4="adr-locality" class="vcard-item" placeholder="New-York" />' +
'<label for="USER-ADR-PCODE">' + Common._e("Postal code") + '</label>' +
'<input type="text" id="USER-ADR-PCODE" data-vcard4="adr-code" class="vcard-item" placeholder="10002" />' +
'<label for="USER-ADR-CTRY">' + Common._e("Country") + '</label>' +
'<input type="text" id="USER-ADR-CTRY" data-vcard4="adr-country" class="vcard-item" placeholder="USA" />' +
'</fieldset>' +
'<fieldset>' +
'<legend>' + Common._e("Biography") + '</legend>' +
'<textarea id="USER-DESC" data-vcard4="note-text" rows="8" cols="60" class="vcard-item"></textarea>' +
'</fieldset>' +
'</div>' +
'<div class="infos">' +
'<p class="infos-title">' + Common._e("Important notice") + '</p>' +
'<p>' + Common._e("Be careful with the information you store into your profile, because it might be accessible by everyone (even someone you don't want to).") + '</p>' +
'<p>' + Common._e("Not everything is private on XMPP; this is one of those things, your public profile (vCard).") + '</p>' +
'<p>' + Common.printf(Common._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><b><a href="https://me.jappix.com/new" target="_blank">' + Common._e("Enable my public profile") + ' »</a></b></p>' +
'</div>' +
'</div>' +
'<div class="bottom">' +
'<div class="wait wait-medium"></div>' +
'<a href="#" class="finish save disabled">' + Common._e("Save") + '</a>' +
'<a href="#" class="finish cancel">' + Common._e("Cancel") + '</a>' +
'</div>';
// Create the popup
Popup.create('vcard', html);
// Associate the events
self.instance();
// We get the VCard informations
self.get(Common.getXID(), 'user');
} catch(e) {
@ -167,12 +167,12 @@ var vCard = (function () {
try {
// Destroy the popup
Popup.destroy('vcard');
// Create the welcome end popup?
if(Welcome.is_done) {
// Open popup
Me.open();
// Unavoidable popup
$('#me').addClass('unavoidable');
}
@ -217,7 +217,7 @@ var vCard = (function () {
try {
// Reset the avatar info
$('#vcard .avatar-info').hide().stopTime();
// Show the wait info
$('#vcard .avatar-wait').show();
} catch(e) {
@ -238,53 +238,53 @@ var vCard = (function () {
try {
// 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 !
// 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();
});
Console.error('Error while uploading the avatar', dData.find('error').text());
}
} catch(e) {
@ -306,10 +306,10 @@ var vCard = (function () {
$('#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();
} catch(e) {
@ -333,7 +333,7 @@ var vCard = (function () {
try {
// Generate the new ID
id = 'USER-' + id;
// Can append the content
if((type == 'user') && !Common.exists('#vcard #' + id)) {
$('#vcard .content').append('<input id="' + id + '" class="vcard-item" type="hidden" />');
@ -357,32 +357,30 @@ var vCard = (function () {
try {
// 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, self.handleUser);
}
else {
} 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, self.handleBuddy);
@ -446,7 +444,7 @@ var vCard = (function () {
// 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') && !Common.exists(path_vcard)) || ((type == 'buddy') && !Common.exists(path_userInfos))) {
return;
@ -454,80 +452,85 @@ var vCard = (function () {
// We retrieve main values
var values_yet = [];
$(iqNode).find('vCard').children().each(function() {
var this_sel = $(this);
// Read the current parent node name
var tokenname = (this).nodeName.toUpperCase();
// Node with a parent
if($(this).children().size()) {
$(this).children().each(function() {
if(this_sel.children().size()) {
this_sel.children().each(function() {
// Get the node values
var currentID = tokenname + '-' + (this).nodeName.toUpperCase();
var currentText = $(this).text();
// Not yet added?
if(!Utils.existArrayValue(values_yet, currentID)) {
// Create an input if it does not exist
self.createInput(values_yet, type);
// Userinfos viewer popup
if((type == 'buddy') && currentText) {
if(currentID == 'EMAIL-USERID')
if(currentID == 'EMAIL-USERID') {
$(path_userInfos + ' #BUDDY-' + currentID).html('<a href="mailto:' + currentText.htmlEnc() + '" target="_blank">' + currentText.htmlEnc() + '</a>');
else
} 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(!Utils.existArrayValue(values_yet, tokenname)) {
// Create an input if it does not exist
self.createInput(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?:\/\/(.+)/))
if(!currentText.match(/^https?:\/\/(.+)/)) {
currentText = 'http://' + currentText;
}
currentText = '<a href="' + currentText + '" target="_blank">' + currentText.htmlEnc() + '</a>';
}
// Description modification
else if(tokenname == 'DESC') {
currentText = Filter.message(currentText, Name.getBuddy(iqFrom).htmlEnc(), true);
}
// Other stuffs
else {
currentText = currentText.htmlEnc();
}
$(path_userInfos + ' #BUDDY-' + tokenname).html(currentText);
}
// Profile editor popup
else if(type == 'user')
else if(type == 'user') {
$(path_vcard + ' #USER-' + tokenname).val(currentText);
}
// Avoid duplicating the value
values_yet.push(tokenname);
}
@ -538,27 +541,25 @@ var vCard = (function () {
if(type == 'buddy') {
// Get the avatar XML
var xml = DataStore.getPersistent('global', 'avatar', iqFrom);
// If there were no stored avatar previously
if($(Common.XMLFromString(xml)).find('type').text() == 'none') {
xml = xml.replace(/<forced>false<\/forced>/gi, '<forced>true</forced>');
DataStore.setPersistent(Common.getXID(), 'avatar', iqFrom, xml);
}
// Handle the user avatar
Avatar.handle(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 {
} else {
aBinval = $(iqNode).find('BINVAL:first').text();
aType = $(iqNode).find('TYPE:first').text();
aContainer = path_userInfos + ' .avatar-container';
@ -570,18 +571,20 @@ var vCard = (function () {
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();
}
var avatar_src = ('data:' + aType + ';base64,' + aBinval);
// We display the avatar we have just received
$(aContainer).replaceWith('<div class="avatar-container"><img class="avatar" src="data:' + aType + ';base64,' + aBinval + '" alt="" /></div>');
$(aContainer).replaceWith('<div class="avatar-container"><img class="avatar" src="' + avatar_src + '" alt="" /></div>');
}
else if(type == 'buddy') {
$(aContainer).replaceWith('<div class="avatar-container"><img class="avatar" src="' + './images/others/default-avatar.png' + '" alt="" /></div>');
}
@ -593,7 +596,7 @@ var vCard = (function () {
} else {
UserInfos.vCard();
}
Console.log('vCard received: ' + iqFrom);
} catch(e) {
Console.error('vCard.handle', e);
@ -613,18 +616,18 @@ var vCard = (function () {
// Send both vcard-temp + vCard4
self._sendLegacy();
self._sendForward();
// Send the user nickname & avatar over PEP
if(Features.enabledPEP()) {
self._sendPubsub();
}
// Close the vCard stuffs
self.close();
// Get our new avatar
Avatar.get(Common.getXID(), 'force', 'true', 'forget');
Console.log('vCard sent.');
} catch(e) {
Console.error('vCard.send', e);
@ -668,11 +671,12 @@ var vCard = (function () {
var tagname = Common.explodeThis('-', item_id, 0);
var cur_node;
if(node.getElementsByTagName(tagname).length > 0)
if(node.getElementsByTagName(tagname).length > 0) {
cur_node = node.getElementsByTagName(tagname).item(0);
else
} else {
cur_node = node.appendChild(stanza.buildNode(tagname, {'xmlns': namespace}));
}
cur_node.appendChild(
stanza.buildNode(
Common.explodeThis('-', item_id, 1),
@ -723,13 +727,13 @@ var vCard = (function () {
try {
var iq = new JSJaCIQ();
iq.setType('set');
var vCard = iq.appendNode('vCard', {
'xmlns': NS_VCARD
});
self._generateTree(NS_VCARD, iq, vCard);
con.send(iq);
} catch(e) {
Console.error('vCard._sendLegacy', e);
@ -748,7 +752,7 @@ var vCard = (function () {
try {
var iq = new JSJaCIQ();
iq.setType('set');
// Build Pubsub headers
var pubsub = iq.appendNode('pubsub', {'xmlns': NS_PUBSUB});
@ -766,9 +770,9 @@ var vCard = (function () {
var vcard = item.appendChild(iq.buildNode('vcard', {
'xmlns': NS_IETF_VCARD4
}));
self._generateTree(NS_IETF_VCARD4, iq, vcard);
con.send(iq);
// Make it publicly-viewable
@ -791,7 +795,7 @@ var vCard = (function () {
// Generate some values
var photo_bin = $('#USER-PHOTO-BINVAL').val();
var photo_data = Base64.decode(photo_bin) || '';
// Data to be sent
var send_data = {};
send_data[NS_NICK] = $('#USER-NICKNAME').val();
@ -801,12 +805,12 @@ var vCard = (function () {
'id': (hex_sha1(photo_data) || ''),
'bytes': (photo_data.length || '')
};
// Generate the XML
$.each(send_data, function(namespace, data) {
var iq = new JSJaCIQ();
iq.setType('set');
var pubsub = iq.appendNode('pubsub', {'xmlns': NS_PUBSUB});
var publish = pubsub.appendChild(iq.buildNode('publish', {'node': namespace, 'xmlns': NS_PUBSUB}));
@ -815,26 +819,26 @@ var vCard = (function () {
if(namespace === NS_NICK) {
item = publish.appendChild(iq.buildNode('item', {'xmlns': NS_PUBSUB}));
// Nickname element
item.appendChild(iq.buildNode('nick', {'xmlns': NS_NICK}, data));
} else if(namespace === NS_URN_ADATA || namespace === NS_URN_AMETA) {
item = publish.appendChild(iq.buildNode('item', {'xmlns': NS_PUBSUB}));
// Apply the SHA-1 hash
if(send_data[NS_URN_AMETA].id) {
item.setAttribute('id', send_data[NS_URN_AMETA].id);
}
// Append XML nodes depending on namespace
if(namespace === NS_URN_ADATA) {
item.appendChild(iq.buildNode('data', {'xmlns': NS_URN_ADATA}, data));
} else if(namespace === NS_URN_AMETA) {
var metadata = item.appendChild(iq.buildNode('metadata', {'xmlns': NS_URN_AMETA}));
if(data) {
var meta_info = metadata.appendChild(iq.buildNode('info', {'xmlns': NS_URN_AMETA}));
if(data.type)
meta_info.setAttribute('type', data.type);
if(data.id)
@ -870,62 +874,77 @@ var vCard = (function () {
$(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'))
if((e.keyCode == 13) && !$('#vcard .finish.save').hasClass('disabled')) {
return self.send();
}
});
// Click events
$('#vcard .tab a').click(function() {
var this_sel = $(this);
// Yet active?
if($(this).hasClass('tab-active'))
if(this_sel.hasClass('tab-active')) {
return false;
}
// Switch to the good tab
var key = parseInt($(this).attr('data-key'));
var key = parseInt(this_sel.attr('data-key'));
return self.switchTab(key);
});
$('#vcard .avatar-delete').click(function() {
return self.deleteAvatar();
});
$('#vcard .bottom .finish').click(function() {
if($(this).is('.cancel'))
var this_sel = $(this);
if(this_sel.is('.cancel')) {
return self.close();
if($(this).is('.save') && !$(this).hasClass('disabled'))
}
if(this_sel.is('.save') && !this_sel.hasClass('disabled')) {
return self.send();
}
return false;
});
// Avatar upload vars
var avatar_options = {
dataType: 'xml',
beforeSubmit: self.waitAvatarUpload,
success: self.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())
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())
if($('#vcard .wait').is(':hidden') &&
$('#vcard .avatar-info.avatar-wait').is(':hidden') &&
$(this).val()) {
$('#vcard-avatar').ajaxSubmit(avatar_options);
}
return false;
});
// Placeholders
$('#vcard-avatar input[type="text"]').placeholder();
} catch(e) {

View file

@ -23,7 +23,7 @@ var Welcome = (function () {
/* Variables */
self.is_done = false;
/**
* Opens the welcome tools
* @public
@ -34,125 +34,125 @@ var Welcome = (function () {
try {
// Share message
var share_msg = Common.printf(Common._e("Using Jappix, an open social platform. I am %s!"), Common.getXID());
// Popup HTML content
var html =
'<div class="top">' + Common._e("Welcome!") + '</div>' +
'<div class="tab">' +
'<a href="#" class="tab-active" data-step="1">' + Common._e("Options") + '</a>' +
'<a href="#" class="tab-missing" data-step="2">' + Common._e("Friends") + '</a>' +
'<a href="#" class="tab-missing" data-step="3">' + Common._e("Share") + '</a>' +
'</div>' +
'<div class="content">' +
'<div class="lap-active one-lap welcome1">' +
'<div class="infos">' +
'<p class="infos-title">' + Common._e("Welcome on Jappix, your own social cloud!") + '</p>' +
'<p>' + Common._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="' + Common._e("Click to disable") + '">' +
'<span class="option">' + Common._e("Sounds") + '</span>' +
'<span class="description">' + Common._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="' + Common._e("Click to disable") + '">' +
'<span class="option">' + Common._e("Geolocation") + '</span>' +
'<span class="description">' + Common._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="' + Common._e("Click to enable") + '">' +
'<span class="option">' + Common._e("XMPP links") + '</span>' +
'<span class="description">' + Common._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 mam-hidable pref" title="' + Common._e("Click to enable") + '">' +
'<span class="option">' + Common._e("Message archiving") + '</span>' +
'<span class="description">' + Common._e("Store a history of your chats") + '</span>' +
'<span class="image mam talk-images"></span>' +
'<span class="tick talk-images"></span>' +
'</a>' +
'<a href="#" class="box" title="' + Common._e("Click to enable") + '">' +
'<span class="option">' + Common._e("Offline friends") + '</span>' +
'<span class="description">' + Common._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">' + Common._e("Friends") + '</p>' +
'<p>' + Common._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">' + Common._e("Share") + '</p>' +
'<p>' + Common._e("Good job! Now, you can share Jappix with your friends!") + '</p>' +
'<p>' + Common._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=' + Common.encodeQuotes(Utils.generateURL(JAPPIX_LOCATION)) + '" target="_blank">' +
'<span class="logo facebook welcome-images"></span>' +
'<span class="name">Facebook</span>' +
'<span class="description">' + Common.printf(Common._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=' + Common.encodeQuotes(share_msg) + '&amp;url=' + Common.encodeQuotes(Utils.generateURL(JAPPIX_LOCATION)) + '" target="_blank">' +
'<span class="logo twitter welcome-images"></span>' +
'<span class="name">Twitter</span>' +
'<span class="description">' + Common.printf(Common._e("Share Jappix on %s"), 'Twitter') + '</span>' +
'<span class="go talk-images"></span>' +
'</a>' +
'<a class="box share" href="https://plus.google.com/share?url=' + Common.encodeQuotes(Utils.generateURL(JAPPIX_LOCATION)) + '" target="_blank">' +
'<span class="logo plus welcome-images"></span>' +
'<span class="name">Google+</span>' +
'<span class="description">' + Common.printf(Common._e("Share Jappix on %s"), 'Google+') + '</span>' +
'<span class="go talk-images"></span>' +
'</a>' +
'<a class="box share" href="https://waaave.com/spot/jappix/" target="_blank">' +
'<span class="logo waaave welcome-images"></span>' +
'<span class="name">Waaave</span>' +
'<span class="description">' + Common.printf(Common._e("Follow Jappix topic on %s"), 'Waaave') + '</span>' +
'<span class="go talk-images"></span>' +
'</a>' +
'</div>' +
'</div>' +
'<div class="bottom">' +
'<div class="wait wait-medium"></div>' +
'<a href="#" class="finish next">' + Common._e("Next") + ' »</a>' +
'<a href="#" class="finish save">' + Common._e("Save") + '</a>' +
var html =
'<div class="top">' + Common._e("Welcome!") + '</div>' +
'<div class="tab">' +
'<a href="#" class="tab-active" data-step="1">' + Common._e("Options") + '</a>' +
'<a href="#" class="tab-missing" data-step="2">' + Common._e("Friends") + '</a>' +
'<a href="#" class="tab-missing" data-step="3">' + Common._e("Share") + '</a>' +
'</div>' +
'<div class="content">' +
'<div class="lap-active one-lap welcome1">' +
'<div class="infos">' +
'<p class="infos-title">' + Common._e("Welcome on Jappix, your own social cloud!") + '</p>' +
'<p>' + Common._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="' + Common._e("Click to disable") + '">' +
'<span class="option">' + Common._e("Sounds") + '</span>' +
'<span class="description">' + Common._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="' + Common._e("Click to disable") + '">' +
'<span class="option">' + Common._e("Geolocation") + '</span>' +
'<span class="description">' + Common._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="' + Common._e("Click to enable") + '">' +
'<span class="option">' + Common._e("XMPP links") + '</span>' +
'<span class="description">' + Common._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 mam-hidable pref" title="' + Common._e("Click to enable") + '">' +
'<span class="option">' + Common._e("Message archiving") + '</span>' +
'<span class="description">' + Common._e("Store a history of your chats") + '</span>' +
'<span class="image mam talk-images"></span>' +
'<span class="tick talk-images"></span>' +
'</a>' +
'<a href="#" class="box" title="' + Common._e("Click to enable") + '">' +
'<span class="option">' + Common._e("Offline friends") + '</span>' +
'<span class="description">' + Common._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">' + Common._e("Friends") + '</p>' +
'<p>' + Common._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">' + Common._e("Share") + '</p>' +
'<p>' + Common._e("Good job! Now, you can share Jappix with your friends!") + '</p>' +
'<p>' + Common._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=' + Common.encodeQuotes(Utils.generateURL(JAPPIX_LOCATION)) + '" target="_blank">' +
'<span class="logo facebook welcome-images"></span>' +
'<span class="name">Facebook</span>' +
'<span class="description">' + Common.printf(Common._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=' + Common.encodeQuotes(share_msg) + '&amp;url=' + Common.encodeQuotes(Utils.generateURL(JAPPIX_LOCATION)) + '" target="_blank">' +
'<span class="logo twitter welcome-images"></span>' +
'<span class="name">Twitter</span>' +
'<span class="description">' + Common.printf(Common._e("Share Jappix on %s"), 'Twitter') + '</span>' +
'<span class="go talk-images"></span>' +
'</a>' +
'<a class="box share" href="https://plus.google.com/share?url=' + Common.encodeQuotes(Utils.generateURL(JAPPIX_LOCATION)) + '" target="_blank">' +
'<span class="logo plus welcome-images"></span>' +
'<span class="name">Google+</span>' +
'<span class="description">' + Common.printf(Common._e("Share Jappix on %s"), 'Google+') + '</span>' +
'<span class="go talk-images"></span>' +
'</a>' +
'<a class="box share" href="https://waaave.com/spot/jappix/" target="_blank">' +
'<span class="logo waaave welcome-images"></span>' +
'<span class="name">Waaave</span>' +
'<span class="description">' + Common.printf(Common._e("Follow Jappix topic on %s"), 'Waaave') + '</span>' +
'<span class="go talk-images"></span>' +
'</a>' +
'</div>' +
'</div>' +
'<div class="bottom">' +
'<div class="wait wait-medium"></div>' +
'<a href="#" class="finish next">' + Common._e("Next") + ' »</a>' +
'<a href="#" class="finish save">' + Common._e("Save") + '</a>' +
'</div>';
// Create the popup
Popup.create('welcome', html);
// Unavoidable popup
$('#welcome').addClass('unavoidable');
// Apply the features
Features.apply('welcome');
// Associate the events
self.instance();
Console.log('Welcome assistant opened.');
} catch(e) {
Console.error('Welcome.open', e);
@ -194,19 +194,20 @@ var Welcome = (function () {
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(!Common.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();
@ -235,26 +236,26 @@ var Welcome = (function () {
// 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 = ['sounds', 'geolocation', '', '', 'roster-showall'];
// Build the XML with the array
for(var 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));
DataStore.setDB(Connection.desktop_hash, 'options', tag, value);
}
}
con.send(iq);
// If geolocation is enabled
if(array[1] == '1') {
PEP.geolocate();
@ -276,24 +277,27 @@ var Welcome = (function () {
try {
// Get the new options
var array = [];
$('#welcome a.box').each(function() {
var current = '0';
if($(this).hasClass('enabled'))
if($(this).hasClass('enabled')) {
current = '1';
}
array.push(current);
});
// If XMPP links is enabled
if(array[2] == '1')
if(array[2] == '1') {
Utils.xmppLinksHandler();
}
// If offline buddies showing is enabled
if(array[4] == '1')
if(array[4] == '1') {
Interface.showAllBuddies('welcome');
}
// If archiving is supported by the server
if(Features.enabledMAM()) {
// If archiving is enabled
@ -301,19 +305,19 @@ var Welcome = (function () {
MAM.setConfig('roster');
}
}
// Send the new options
self.send(array);
// Close the welcome tool
self.close();
// Open the profile editor
vCard.open();
// Unavoidable popup
$('#vcard').addClass('unavoidable');
self.is_done = true;
} catch(e) {
Console.error('Welcome.save', e);
@ -335,10 +339,11 @@ var Welcome = (function () {
// Check the next step to go to
var next = 1;
var missing = '#welcome .tab a.tab-missing';
if(Common.exists(missing))
if(Common.exists(missing)) {
next = parseInt($(missing + ':first').attr('data-step'));
}
// Switch to the next step
self.switchTab(next);
} catch(e) {
@ -360,27 +365,37 @@ var Welcome = (function () {
try {
// Click events
$('#welcome .tab a').click(function() {
var this_sel = $(this);
// Switch to the good tab
var key = parseInt($(this).attr('data-step'));
var key = parseInt(this_sel.attr('data-step'));
return self.switchTab(key);
});
$('#welcome a.box:not(.share)').click(function() {
if($(this).hasClass('enabled'))
$(this).removeClass('enabled').attr('title', Common._e("Click to enable"));
else
$(this).addClass('enabled').attr('title', Common._e("Click to disable"));
var this_sel = $(this);
if(this_sel.hasClass('enabled')) {
this_sel.removeClass('enabled').attr('title', Common._e("Click to enable"));
} else {
this_sel.addClass('enabled').attr('title', Common._e("Click to disable"));
}
return false;
});
$('#welcome .bottom .finish').click(function() {
if($(this).is('.next'))
var this_sel = $(this);
if(this_sel.is('.next')) {
return self.next();
if($(this).is('.save'))
}
if(this_sel.is('.save')) {
return self.save();
}
return false;
});
} catch(e) {

Some files were not shown because too many files have changed in this diff Show more