diff options
73 files changed, 6010 insertions, 0 deletions
diff --git a/mod/beechat/README b/mod/beechat/README new file mode 100644 index 000000000..5ff3f8467 --- /dev/null +++ b/mod/beechat/README @@ -0,0 +1,23 @@ +Beechat the first XMPP chat for Elgg +==================================== + +Beechat is a facebook like chat for elgg using the XMPP protocol. It requires the XMPP serveur ejabberd. + +Installation +------------ + +French Documentation + +http://github.com/beechannels/beechat/wikis/guide-dinstallation + +English Documentation + +http://github.com/beechannels/beechat/wikis/setup-guide + +Feedback +-------- + +We are relying on the [GitHub issues tracker][issues] linked from above for +feedback. File bugs or other issues [here][issues]. + +[issues]: http://github.com/beechannels/beechat/issues diff --git a/mod/beechat/actions/get_connection.php b/mod/beechat/actions/get_connection.php new file mode 100644 index 000000000..a31174179 --- /dev/null +++ b/mod/beechat/actions/get_connection.php @@ -0,0 +1,21 @@ +<?php + /** + * Beechat + * + * @package beechat + * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html GNU Public License version 2 + * @author Beechannels <contact@beechannels.com> + * @copyright Beechannels 2007-2010 + * @link http://beechannels.com/ + */ + + header('Content-type: application/json'); + gatekeeper(); + + global $SESSION; + + if ($SESSION->offsetExists('beechat_conn')) + echo $SESSION->offsetGet('beechat_conn'); + + exit(); +?> diff --git a/mod/beechat/actions/get_details.php b/mod/beechat/actions/get_details.php new file mode 100644 index 000000000..4944fc4a9 --- /dev/null +++ b/mod/beechat/actions/get_details.php @@ -0,0 +1,21 @@ +<?php + /** + * Beechat + * + * @package beechat + * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html GNU Public License version 2 + * @author Beechannels <contact@beechannels.com> + * @copyright Beechannels 2007-2010 + * @link http://beechannels.com/ + */ + + gatekeeper(); + header('Content-type: application/json'); + $user = $_SESSION['user']; + $t = array('username' => $user->username, + 'password' => $user->password); + + echo json_encode($t); + + exit(); +?> diff --git a/mod/beechat/actions/get_icons.php b/mod/beechat/actions/get_icons.php new file mode 100644 index 000000000..33d447e2e --- /dev/null +++ b/mod/beechat/actions/get_icons.php @@ -0,0 +1,52 @@ +<?php + /** + * Beechat + * + * @package beechat + * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html GNU Public License version 2 + * @author Beechannels <contact@beechannels.com> + * @copyright Beechannels 2007-2010 + * @link http://beechannels.com/ + */ + + header('Content-type: application/json'); + gatekeeper(); + global $CONFIG; + + if (!empty($_POST['beechat_roster_items_usernames'])) + { + $rosterItemsUsernames = explode(',', $_POST['beechat_roster_items_usernames']); + /*foreach ($rosterItemsUsernames as $rosterItem) + { + }*/ + $userFriendsEntities = $_SESSION['user']->getFriends('', 0, 0); + + $res = array(); + foreach ($rosterItemsUsernames as $value) + { + $found = false; + $splitjid = explode('@', $value); + $jid_name = $splitjid[0]; + $jid_host = $splitjid[1]; + foreach ($userFriendsEntities as $friend) + { + if ((strtolower($friend->username) == strtolower($jid_name) && $jid_host == elgg_get_plugin_setting("domain", "beechat"))) + { + $res[$value] = array('small' => $friend->getIcon('small'), 'tiny' => $friend->getIcon('tiny')); + $found = true; + break; + } + } + if (!$found) { + $base = $CONFIG->wwwroot."mod/profile/graphics/default"; + $res[$value] = array('small' => $base."small.gif", 'tiny' => $base."tiny.gif"); + } + } + echo json_encode($res); + } + else + echo json_encode(null); + + exit(); + +?> diff --git a/mod/beechat/actions/get_state.php b/mod/beechat/actions/get_state.php new file mode 100644 index 000000000..6cfd2f725 --- /dev/null +++ b/mod/beechat/actions/get_state.php @@ -0,0 +1,21 @@ +<?php + /** + * Beechat + * + * @package beechat + * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html GNU Public License version 2 + * @author Beechannels <contact@beechannels.com> + * @copyright Beechannels 2007-2010 + * @link http://beechannels.com/ + */ + + header('Content-type: application/json'); + gatekeeper(); + + global $SESSION; + + if ($SESSION->offsetExists('beechat_state')) + echo $SESSION->offsetGet('beechat_state'); + + exit(); +?> diff --git a/mod/beechat/actions/get_statuses.php b/mod/beechat/actions/get_statuses.php new file mode 100644 index 000000000..6f7620beb --- /dev/null +++ b/mod/beechat/actions/get_statuses.php @@ -0,0 +1,41 @@ +<?php + /** + * Beechat + * + * @package beechat + * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html GNU Public License version 2 + * @author Beechannels <contact@beechannels.com> + * @copyright Beechannels 2007-2010 + * @link http://beechannels.com/ + */ + + header('Content-type: application/json'); + gatekeeper(); + $usernames = get_input('beechat_roster_items_usernames'); + if (!empty($usernames)) + { + $iconSize = 'small'; + $rosterItemsUsernames = explode(',', $usernames); + $userFriendsEntities = $_SESSION['user']->getFriends('', 1000000000, 0); + + $res = array(); + foreach ($rosterItemsUsernames as $value) + { + foreach ($userFriendsEntities as $friend) + { + if (strtolower($friend->username) == strtolower($value)) + { + $status = get_entities_from_metadata("state", "current", "object", "status", $friend->get('guid')); + $res[$value] = ($status != false) ? $status[0]->description : ''; + break; + } + } + } + echo json_encode($res); + } + else + echo json_encode(null); + + exit(); + +?> diff --git a/mod/beechat/actions/join_groupchat.php b/mod/beechat/actions/join_groupchat.php new file mode 100644 index 000000000..c694d7957 --- /dev/null +++ b/mod/beechat/actions/join_groupchat.php @@ -0,0 +1,15 @@ +<?php + +$user = elgg_get_logged_in_user_entity(); +$group = get_entity(get_input('group_guid')); + +if ($user && $group) { + if (!check_entity_relationship($user->guid, 'groupchat', $group->guid)) { + error_log("joinen ok"); + add_entity_relationship($user->guid, 'groupchat', $group->guid); +} +} +echo "OK"; +error_log("join ok"); + +?> diff --git a/mod/beechat/actions/leave_groupchat.php b/mod/beechat/actions/leave_groupchat.php new file mode 100644 index 000000000..e04ab8846 --- /dev/null +++ b/mod/beechat/actions/leave_groupchat.php @@ -0,0 +1,12 @@ +<?php + +$user = elgg_get_logged_in_user_entity(); +$group = get_entity(get_input('group_guid')); + +if ($user && $group) { + if (check_entity_relationship($user->guid, 'groupchat', $group->guid)) + remove_entity_relationship($user->guid, 'groupchat', $group->guid); +} +error_log("leave ok"); +echo "OK"; +?> diff --git a/mod/beechat/actions/save_state.php b/mod/beechat/actions/save_state.php new file mode 100644 index 000000000..f8a61c580 --- /dev/null +++ b/mod/beechat/actions/save_state.php @@ -0,0 +1,29 @@ +<?php + /** + * Beechat + * + * @package beechat + * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html GNU Public License version 2 + * @author Beechannels <contact@beechannels.com> + * @copyright Beechannels 2007-2010 + * @link http://beechannels.com/ + */ + +// gatekeeper(); + + if (elgg_is_logged_in()) + { + + global $SESSION; + + if (!empty($_POST['beechat_state'])) + { + $SESSION->offsetSet('beechat_state', $_POST['beechat_state']); + } + elseif (!empty($_POST['beechat_conn'])) + { + $SESSION->offsetSet('beechat_conn', get_input('beechat_conn')); + } + } + exit(); +?> diff --git a/mod/beechat/classes/BeechatSync.php b/mod/beechat/classes/BeechatSync.php new file mode 100644 index 000000000..e0a2f90b8 --- /dev/null +++ b/mod/beechat/classes/BeechatSync.php @@ -0,0 +1,37 @@ +<?php + +class BeechatSync { + static function onFriendCreate($event, $object_type, $relationship) { + if ($relationship->relationship == 'friendrequest') { + elgg_load_library('elgg:beechat'); + $friend = get_entity($relationship->guid_two); + // create friend request + ejabberd_friend_request(elgg_get_logged_in_user_entity(), $friend); + } + } + static function onFriendDelete($event, $object_type, $relationship) { + if ($relationship->relationship == 'friendrequest') { + elgg_load_library('elgg:beechat'); + $subject = get_entity($relationship->guid_two); + // here friend is guid_one because is the one initiating + $friend = get_entity($relationship->guid_one); + $friends = $friend->isFriendsWith($subject->guid); + if ($friends) { + // accept friend request + ejabberd_friend_accept(elgg_get_logged_in_user_entity(), $friend); + } else { + // decline friend request + ejabberd_friend_deny(elgg_get_logged_in_user_entity(), $friend); + } + } + elseif ($relationship->relationship == 'friend') { + elgg_load_library('elgg:beechat'); + $subject = get_entity($relationship->guid_one); + $friend = get_entity($relationship->guid_two); + // delete friendship + ejabberd_friend_remove(elgg_get_logged_in_user_entity(), $friend); + } + + } + +} diff --git a/mod/beechat/disablechat.php b/mod/beechat/disablechat.php new file mode 100644 index 000000000..490fb327b --- /dev/null +++ b/mod/beechat/disablechat.php @@ -0,0 +1,8 @@ +<?php + require_once(dirname(dirname(dirname(__FILE__))) . "/engine/start.php"); + if (elgg_is_logged_in()) { + elgg_get_logged_in_user_entity()->chatenabled = false; + system_message(elgg_echo("beechat:disabled")); + } + forward($_SERVER['HTTP_REFERER']); +?> diff --git a/mod/beechat/enablechat.php b/mod/beechat/enablechat.php new file mode 100644 index 000000000..5d3de7e2a --- /dev/null +++ b/mod/beechat/enablechat.php @@ -0,0 +1,8 @@ +<?php + require_once(dirname(dirname(dirname(__FILE__))) . "/engine/start.php"); + if (elgg_is_logged_in()) { + elgg_get_logged_in_user_entity()->chatenabled = true; + system_message(elgg_echo("beechat:enabled")); + } + forward($_SERVER['HTTP_REFERER']); +?> diff --git a/mod/beechat/graphics/icons/bullet_arrow_down.png b/mod/beechat/graphics/icons/bullet_arrow_down.png Binary files differnew file mode 100644 index 000000000..9b23c06d7 --- /dev/null +++ b/mod/beechat/graphics/icons/bullet_arrow_down.png diff --git a/mod/beechat/graphics/icons/bullet_arrow_up.png b/mod/beechat/graphics/icons/bullet_arrow_up.png Binary files differnew file mode 100644 index 000000000..24df0f421 --- /dev/null +++ b/mod/beechat/graphics/icons/bullet_arrow_up.png diff --git a/mod/beechat/graphics/icons/bullet_black.png b/mod/beechat/graphics/icons/bullet_black.png Binary files differnew file mode 100644 index 000000000..57619706d --- /dev/null +++ b/mod/beechat/graphics/icons/bullet_black.png diff --git a/mod/beechat/graphics/icons/bullet_blue.png b/mod/beechat/graphics/icons/bullet_blue.png Binary files differnew file mode 100644 index 000000000..a7651ec8a --- /dev/null +++ b/mod/beechat/graphics/icons/bullet_blue.png diff --git a/mod/beechat/graphics/icons/bullet_delete.png b/mod/beechat/graphics/icons/bullet_delete.png Binary files differnew file mode 100644 index 000000000..bd6271b24 --- /dev/null +++ b/mod/beechat/graphics/icons/bullet_delete.png diff --git a/mod/beechat/graphics/icons/bullet_error.png b/mod/beechat/graphics/icons/bullet_error.png Binary files differnew file mode 100644 index 000000000..bca2b491f --- /dev/null +++ b/mod/beechat/graphics/icons/bullet_error.png diff --git a/mod/beechat/graphics/icons/bullet_green.png b/mod/beechat/graphics/icons/bullet_green.png Binary files differnew file mode 100644 index 000000000..058ad261f --- /dev/null +++ b/mod/beechat/graphics/icons/bullet_green.png diff --git a/mod/beechat/graphics/icons/bullet_orange.png b/mod/beechat/graphics/icons/bullet_orange.png Binary files differnew file mode 100644 index 000000000..fa63024e5 --- /dev/null +++ b/mod/beechat/graphics/icons/bullet_orange.png diff --git a/mod/beechat/graphics/icons/bullet_pink.png b/mod/beechat/graphics/icons/bullet_pink.png Binary files differnew file mode 100644 index 000000000..0c9f73e3f --- /dev/null +++ b/mod/beechat/graphics/icons/bullet_pink.png diff --git a/mod/beechat/graphics/icons/bullet_purple.png b/mod/beechat/graphics/icons/bullet_purple.png Binary files differnew file mode 100644 index 000000000..52ba5036b --- /dev/null +++ b/mod/beechat/graphics/icons/bullet_purple.png diff --git a/mod/beechat/graphics/icons/bullet_red.png b/mod/beechat/graphics/icons/bullet_red.png Binary files differnew file mode 100644 index 000000000..0cd803115 --- /dev/null +++ b/mod/beechat/graphics/icons/bullet_red.png diff --git a/mod/beechat/graphics/icons/bullet_star.png b/mod/beechat/graphics/icons/bullet_star.png Binary files differnew file mode 100644 index 000000000..fab774a32 --- /dev/null +++ b/mod/beechat/graphics/icons/bullet_star.png diff --git a/mod/beechat/graphics/icons/bullet_white.png b/mod/beechat/graphics/icons/bullet_white.png Binary files differnew file mode 100644 index 000000000..a9af8d44b --- /dev/null +++ b/mod/beechat/graphics/icons/bullet_white.png diff --git a/mod/beechat/graphics/icons/bullet_yellow.png b/mod/beechat/graphics/icons/bullet_yellow.png Binary files differnew file mode 100644 index 000000000..6469cea7e --- /dev/null +++ b/mod/beechat/graphics/icons/bullet_yellow.png diff --git a/mod/beechat/graphics/icons/chat_icon.png b/mod/beechat/graphics/icons/chat_icon.png Binary files differnew file mode 100644 index 000000000..0e6d844bd --- /dev/null +++ b/mod/beechat/graphics/icons/chat_icon.png diff --git a/mod/beechat/graphics/icons/cog_edit.png b/mod/beechat/graphics/icons/cog_edit.png Binary files differnew file mode 100644 index 000000000..47b75a456 --- /dev/null +++ b/mod/beechat/graphics/icons/cog_edit.png diff --git a/mod/beechat/graphics/icons/comment_edit.png b/mod/beechat/graphics/icons/comment_edit.png Binary files differnew file mode 100644 index 000000000..73db110df --- /dev/null +++ b/mod/beechat/graphics/icons/comment_edit.png diff --git a/mod/beechat/graphics/icons/emoticon_evilgrin.png b/mod/beechat/graphics/icons/emoticon_evilgrin.png Binary files differnew file mode 100644 index 000000000..817bd509b --- /dev/null +++ b/mod/beechat/graphics/icons/emoticon_evilgrin.png diff --git a/mod/beechat/graphics/icons/emoticon_grin.png b/mod/beechat/graphics/icons/emoticon_grin.png Binary files differnew file mode 100644 index 000000000..fc60c5e1c --- /dev/null +++ b/mod/beechat/graphics/icons/emoticon_grin.png diff --git a/mod/beechat/graphics/icons/emoticon_happy.png b/mod/beechat/graphics/icons/emoticon_happy.png Binary files differnew file mode 100644 index 000000000..6b7336e17 --- /dev/null +++ b/mod/beechat/graphics/icons/emoticon_happy.png diff --git a/mod/beechat/graphics/icons/emoticon_smile.png b/mod/beechat/graphics/icons/emoticon_smile.png Binary files differnew file mode 100644 index 000000000..ade431851 --- /dev/null +++ b/mod/beechat/graphics/icons/emoticon_smile.png diff --git a/mod/beechat/graphics/icons/emoticon_surprised.png b/mod/beechat/graphics/icons/emoticon_surprised.png Binary files differnew file mode 100644 index 000000000..4520cfc55 --- /dev/null +++ b/mod/beechat/graphics/icons/emoticon_surprised.png diff --git a/mod/beechat/graphics/icons/emoticon_tongue.png b/mod/beechat/graphics/icons/emoticon_tongue.png Binary files differnew file mode 100644 index 000000000..ecafd2ffc --- /dev/null +++ b/mod/beechat/graphics/icons/emoticon_tongue.png diff --git a/mod/beechat/graphics/icons/emoticon_unhappy.png b/mod/beechat/graphics/icons/emoticon_unhappy.png Binary files differnew file mode 100644 index 000000000..fd5d030ef --- /dev/null +++ b/mod/beechat/graphics/icons/emoticon_unhappy.png diff --git a/mod/beechat/graphics/icons/emoticon_waii.png b/mod/beechat/graphics/icons/emoticon_waii.png Binary files differnew file mode 100644 index 000000000..458f93611 --- /dev/null +++ b/mod/beechat/graphics/icons/emoticon_waii.png diff --git a/mod/beechat/graphics/icons/emoticon_wink.png b/mod/beechat/graphics/icons/emoticon_wink.png Binary files differnew file mode 100644 index 000000000..a631949b5 --- /dev/null +++ b/mod/beechat/graphics/icons/emoticon_wink.png diff --git a/mod/beechat/graphics/icons/heart.png b/mod/beechat/graphics/icons/heart.png Binary files differnew file mode 100644 index 000000000..d9ee53e59 --- /dev/null +++ b/mod/beechat/graphics/icons/heart.png diff --git a/mod/beechat/graphics/icons/house.png b/mod/beechat/graphics/icons/house.png Binary files differnew file mode 100644 index 000000000..fed62219f --- /dev/null +++ b/mod/beechat/graphics/icons/house.png diff --git a/mod/beechat/graphics/icons/muc_icon.png b/mod/beechat/graphics/icons/muc_icon.png Binary files differnew file mode 100644 index 000000000..efdd60f12 --- /dev/null +++ b/mod/beechat/graphics/icons/muc_icon.png diff --git a/mod/beechat/graphics/icons/notification_pink.png b/mod/beechat/graphics/icons/notification_pink.png Binary files differnew file mode 100644 index 000000000..f40c184f9 --- /dev/null +++ b/mod/beechat/graphics/icons/notification_pink.png diff --git a/mod/beechat/graphics/icons/pointer.png b/mod/beechat/graphics/icons/pointer.png Binary files differnew file mode 100644 index 000000000..4e50a0f9a --- /dev/null +++ b/mod/beechat/graphics/icons/pointer.png diff --git a/mod/beechat/graphics/icons/resultset_next.png b/mod/beechat/graphics/icons/resultset_next.png Binary files differnew file mode 100644 index 000000000..e252606d3 --- /dev/null +++ b/mod/beechat/graphics/icons/resultset_next.png diff --git a/mod/beechat/graphics/icons/resultset_previous.png b/mod/beechat/graphics/icons/resultset_previous.png Binary files differnew file mode 100644 index 000000000..18f9cc109 --- /dev/null +++ b/mod/beechat/graphics/icons/resultset_previous.png diff --git a/mod/beechat/graphics/icons/statuses.png b/mod/beechat/graphics/icons/statuses.png Binary files differnew file mode 100644 index 000000000..e409f61a9 --- /dev/null +++ b/mod/beechat/graphics/icons/statuses.png diff --git a/mod/beechat/graphics/icons/vcard.png b/mod/beechat/graphics/icons/vcard.png Binary files differnew file mode 100644 index 000000000..c02f315d2 --- /dev/null +++ b/mod/beechat/graphics/icons/vcard.png diff --git a/mod/beechat/languages/en.php b/mod/beechat/languages/en.php new file mode 100644 index 000000000..38f03be98 --- /dev/null +++ b/mod/beechat/languages/en.php @@ -0,0 +1,45 @@ +<?php + +$en_array = array( + 'beechat:icons:home' => 'Home', + + 'beechat:contacts:button' => 'Chat', + + 'beechat:availability:available' => 'Available', + 'beechat:availability:dnd' => 'Do not disturb', + 'beechat:availability:away' => 'Away', + 'beechat:availability:xa' => 'Extended away', + 'beechat:availability:offline' => 'Offline', + + 'beechat:connection:state:offline' => 'Offline', + 'beechat:connection:state:connecting' => 'Connecting...', + 'beechat:connection:state:authenticating' => 'Authenticating...', + 'beechat:connection:state:online' => 'Online', + 'beechat:connection:state:failed' => 'Failed', + 'beechat:connection:state:disconnecting' => 'Disconnecting...', + + 'beechat:chat:self' => 'Me', + 'beechat:chat:composing' => ' is typing.', + + 'beechat:box:minimize' => 'Minimize', + 'beechat:box:close' => 'Close', + 'beechat:box:showhide' => 'Show/Hide this chat window', + 'beechat:enabled' => 'Chat enabled', + 'beechat:disabled' => 'Chat disabled', + 'beechat:enablechat' => 'Enable chat', + 'beechat:disablechat' => 'Disable chat', + 'beechat:domain' => 'Chat domain', + 'beechat:groupdomain' => 'MUC domain', + 'beechat:chatroom' => 'Group chat', + 'beechat:dbname' => 'Database name', + 'beechat:dbhost' => 'Database host', + 'beechat:dbuser' => 'Database user', + 'beechat:dbuser' => 'notification:method:xmpp', + 'notification:method:xmpp' => 'Xmpp/Jabber', + 'beechat:dbpassword' => 'Database password', + 'beechat:xmlrpcip' => 'Ejabberd IP' + ); + +add_translation('en', $en_array); + +?> diff --git a/mod/beechat/languages/es.php b/mod/beechat/languages/es.php new file mode 100644 index 000000000..78f009ce9 --- /dev/null +++ b/mod/beechat/languages/es.php @@ -0,0 +1,43 @@ +<?php + +$es_array = array( + 'beechat:icons:home' => 'Home', + + 'beechat:contacts:button' => 'Chat', + + 'beechat:availability:available' => 'Disponible', + 'beechat:availability:dnd' => 'No molestar', + 'beechat:availability:away' => 'Fuera', + 'beechat:availability:xa' => 'Fuera bastante tiempo', + 'beechat:availability:offline' => 'Desconectado', + + 'beechat:connection:state:offline' => 'Desconectado', + 'beechat:connection:state:connecting' => 'Conectando...', + 'beechat:connection:state:authenticating' => 'Iniciando...', + 'beechat:connection:state:online' => 'Conectado', + 'beechat:connection:state:failed' => 'Fallo', + 'beechat:connection:state:disconnecting' => 'Desconectando...', + + 'beechat:chat:self' => 'Yo', + 'beechat:chat:composing' => ' esta escribiendo.', + + 'beechat:box:minimize' => 'Minimizar', + 'beechat:box:close' => 'Cerrar', + 'beechat:box:showhide' => 'Mostrar/Ocultar esta ventana de chat', + 'beechat:enabled' => 'Chat activado', + 'beechat:disabled' => 'Chat desactivado', + 'beechat:enablechat' => 'Activar chat', + 'beechat:disablechat' => 'Desactivar chat', + 'beechat:domain' => 'Dominio Chat', + 'beechat:groupdomain' => 'Dominio MUC', + 'beechat:chatroom' => 'Chat del grupo', + 'beechat:dbname' => 'Database name', + 'beechat:dbhost' => 'Database host', + 'beechat:dbuser' => 'Database user', + 'beechat:dbpassword' => 'Database password', + 'beechat:xmlrpcip' => 'Ejabberd IP' + ); + +add_translation('es', $es_array); + +?> diff --git a/mod/beechat/languages/fr.php b/mod/beechat/languages/fr.php new file mode 100644 index 000000000..58b0eac3a --- /dev/null +++ b/mod/beechat/languages/fr.php @@ -0,0 +1,32 @@ +<?php + +$fr_array = array( + 'beechat:icons:home' => 'Accueil', + + 'beechat:contacts:button' => 'Chat', + + 'beechat:availability:available' => 'Disponible', + 'beechat:availability:dnd' => 'Ne pas déranger', + 'beechat:availability:away' => 'Absent', + 'beechat:availability:xa' => 'Absence prolongée', + 'beechat:availability:offline' => 'Hors ligne', + + 'beechat:connection:state:offline' => 'Hors ligne', + 'beechat:connection:state:connecting' => 'Connexion...', + 'beechat:connection:state:authenticating' => 'Authentification...', + 'beechat:connection:state:online' => 'En ligne', + 'beechat:connection:state:failed' => 'Échec', + 'beechat:connection:state:disconnecting' => 'Déconnexion...', + + 'beechat:chat:self' => 'Moi', + 'beechat:chat:composing' => ' est en train d\'écrire.', + + 'beechat:box:minimize' => 'Diminuer', + 'beechat:box:close' => 'Fermer', + 'beechat:box:showhide' => 'Montrer/Cacher cette fenêtre de chat' + + ); + +add_translation('fr', $fr_array); + +?> diff --git a/mod/beechat/lib/beechat.php b/mod/beechat/lib/beechat.php new file mode 100644 index 000000000..bf002d648 --- /dev/null +++ b/mod/beechat/lib/beechat.php @@ -0,0 +1,250 @@ +<? +/* + allow_change_subj + allow_private_messages + allow_query_users + allow_user_invites + anonymous + logging + max_users + members_by_default + members_only + moderated + password + password_protected + persistent + public + public_list + title + +muc_room_set_affiliation struct[{name, String}, {service, String}, + {jid, String}, {affiliation, Affiliation}] Integer + + +*/ + //$request = xmlrpc_encode_request('muc_online_rooms', "global", (array('encoding' => 'utf-8'))); + + +function ejabberd_xmlrpc_send($request) +{ + $context = stream_context_create(array('http' => array( + 'method' => "POST", + 'header' => "User-Agent: XMLRPC::Client mod_xmlrpc\r\n" . + "Content-Type: text/xml\r\n" . + "Content-Length: ".strlen($request), + 'content' => $request + ))); + + $file = file_get_contents("http://".elgg_get_plugin_setting("xmlrpcip", "beechat").":4560/RPC2", false, $context); + + $response = xmlrpc_decode($file); + if (is_array($response) && xmlrpc_is_fault($response)) { + trigger_error("xmlrpc: $response[faultString] ($response[faultCode])"); + } else { + // print_r($response); + } +} + +function ejabberd_xmlrpc_command($command, $params) +{ + //error_log("send xmlrpc: ".$command); + $request = xmlrpc_encode_request($command, $params, (array('encoding' => 'utf-8'))); + return ejabberd_xmlrpc_send($request); +} + +function xmpp_escape($name) { + // http://xmpp.org/extensions/xep-0106.html#escaping + $name = str_replace(' ', '\\20', $name); + $name = str_replace('"', '\\22', $name); + $name = str_replace('&', '\\26', $name); + $name = str_replace("'", '\\27', $name); + $name = str_replace('/', '\\2f', $name); + $name = str_replace(';', '\\3a', $name); + $name = str_replace('<', '\\3c', $name); + $name = str_replace('>', '\\3e', $name); + $name = str_replace('@', '\\40', $name); + $name = str_replace('\\', '\\5c', $name); + return $name; +} + +class EjabberdMucRoom { + function __construct($group) { + $this->group = $group; + } + function setOption($name, $value) { + $group = $this->group; + $param=array("name"=>elgg_get_friendly_title($group->name), + "service"=>elgg_get_plugin_setting("groupdomain", "beechat"), + "option"=>$name, + "value"=>$value); + ejabberd_xmlrpc_command('muc_room_change_option', $param); + } + function addMember($member) { + //"outcast" | "none" | "member" | "admin" | "owner" + $group = $this->group; + if ($member->guid === $group->owner_guid) + $affiliation = "owner"; + elseif ($group->canEdit($member->guid)) + $affiliation = "admin"; + else + $affiliation = "member"; + $this->setAffiliation($member, $affiliation); + } + + function setAffiliation($member, $affiliation) { + $group = $this->group; + $param = array("name" => elgg_get_friendly_title($group->name), + "service" => elgg_get_plugin_setting("groupdomain", "beechat"), + "jid" => xmpp_escape($member->username) . '@' . elgg_get_plugin_setting("domain", "beechat"), + "affiliation" => $affiliation); + ejabberd_xmlrpc_command('muc_room_set_affiliation', $param); + //echo "set affiliation ".$member->username."<br/>"; + } +} + +function ejabberd_create_group($group) +{ + //echo "creating " . $group->name . "<br/>"; + // create room + $param=array("name"=>elgg_get_friendly_title($group->name), + "service"=>elgg_get_plugin_setting("groupdomain", "beechat"), + "server"=>elgg_get_plugin_setting("domain", "beechat")); + ejabberd_xmlrpc_command('create_muc_room', $param); + + // persistency + + $room = new EjabberdMucRoom($group); + $room->setOption("persistent", true); + $room->setOption("title", $group->name); + // open to public? + if ($group->isPublicMembership()) { + $room->setOption("members_only", false); + } + else + $room->setOption("members_only", true); + + if ($group->access_id === ACCESS_PUBLIC) { + $room->setOption("public_list", true); + $room->setOption("public", true); + } + else { + $room->setOption("public_list", false); + $room->setOption("public", false); + } + $members = $group->getMembers(0); + foreach($members as $member) { + $room->addMember($member); + } + $room->addMember(get_entity($group->owner_guid)); +} + +function ejabberd_destroy_group($group) +{ + $param=array("name"=>elgg_get_friendly_title($group->name), + "service"=>elgg_get_plugin_setting("groupdomain", "beechat"), + "server"=>elgg_get_plugin_setting("domain", "beechat")); + ejabberd_xmlrpc_command('delete_muc_room', $param); +} + +function ejabberd_getjid($user, $do_external=false) +{ + if ($user->foreign || ($do_external && $user->alias && get_plugin_usersetting("usealias", $user->guid,"openid_client"))) { + if ($user->foreign) + $webid = $user->webid; + else + $webid = $user->alias; + if (strpos($webid, 'http') === 0) { + // http or https addresses + $hostparts = parse_url($webid); + $urlparts = explode('/', $webid); + $host = $hostparts['host']; + $username = $urlparts[count($urlparts)-1]; + } else { + if (strpos($webid, ':') > 0) { + $webidparts = explode(':', $webid); + $hostparts = explode('@',$webidparts[1]); + } else { + $hostparts = explode('@',$webid); + } + $username = $hostparts[0]; + $host = $hostparts[1]; + } + } + else { + $username = $user->username; + $host = elgg_get_plugin_setting("domain", "beechat"); + } + return xmpp_escape($username) . '@' . $host; +} + +function ejabberd_friend_command($user, $friend, $command, $is_out) // $user adds $friend +{ + error_log(" * ".$friend->username."->".ejabberd_getjid($user)." ".$command); + if ($friend->foreign) { + error_log(" * beechat: friend is foreign!"); + return; + } + $param = array("user" => elgg_get_friendly_title($friend->username), + "server" => elgg_get_plugin_setting("domain", "beechat"), + "from" => ejabberd_getjid($user), + "subs" => $command); + if ($is_out) { + error_log("out"); + ejabberd_xmlrpc_command('send_roster_request_out', $param); + } + else { + $param['reason'] = 'unknown'; + ejabberd_xmlrpc_command('send_roster_request_in', $param); + } +} + + +function ejabberd_friend_request($user, $friend) // $user adds $friend +{ + error_log('ejabberd_friend_request'); + ejabberd_friend_command($friend, $user, 'subscribe', true); // out:$user : $friend + error_log('ejabberd_friend_requested'); +} +function ejabberd_friend_accept($user, $friend) // $user adds $friend +{ + error_log('ejabberd_friend_accept'); + ejabberd_friend_command($friend, $user, 'subscribed', true); + // following might be needed to have symmetry (and important for remote) + if ($friend->foreign) { + // following is needed for xmpp nodes + ejabberd_friend_command($friend, $user, 'subscribe', true); + } + // ejabberd_friend_command($friend, $user, 'subscribed', false); + // following can't be faked + if (!$friend->foreign) + ejabberd_friend_command($user, $friend, 'subscribed', true); + error_log('ejabberd_friend_accepted'); +} +function ejabberd_friend_deny($user, $friend) // $user adds $friend +{ + error_log('ejabberd_friedeny'); + ejabberd_friend_command($friend, $user, 'unsubscribed', true); +} +function ejabberd_friend_remove($user, $friend) // $user adds $friend +{ + error_log('ejabberd_friend_remove'); + if ($friend->foreign) { + ejabberd_friend_command($friend, $user, 'unsubscribed', true); + ejabberd_friend_command($friend, $user, 'unsubscribed', false); + } + else + ejabberd_friend_command($friend, $user, 'unsubscribed', false); + if (!$friend->foreign) + ejabberd_friend_command($user, $friend, 'unsubscribed', false); + error_log('ejabberd_friend_removed'); +} + +/*function ejabberd_send_chat($from, $to, $body) { // $user adds $friend + $param = array("body"=>$body, + "from"=>$from, + "to"=>$to); + ejabberd_xmlrpc_command('send_chat_message', $param); +}*/ + + +?> diff --git a/mod/beechat/manifest.xml b/mod/beechat/manifest.xml new file mode 100644 index 000000000..ad948fdb4 --- /dev/null +++ b/mod/beechat/manifest.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<plugin_manifest xmlns="http://www.elgg.org/plugin_manifest/1.8"> + <name>Beechat</name> + <author>Beechannels + Lorea dev</author> + <version>1.8.0</version> + <category>widget</category> + <description>XMPP chat for Elgg.</description> + <website>https://lorea.org</website> + <copyright>(C) Beechanels 2009, Lorea 2009-2013</copyright> + <license>GNU General Public License version 2</license> + <requires> + <type>elgg_release</type> + <version>1.8</version> + </requires> +</plugin_manifest> diff --git a/mod/beechat/migrate.php b/mod/beechat/migrate.php new file mode 100644 index 000000000..20bee7973 --- /dev/null +++ b/mod/beechat/migrate.php @@ -0,0 +1,88 @@ +<?php +require_once(dirname(dirname(dirname(__FILE__))) . "/engine/start.php"); + +global $CONFIG; +admin_gatekeeper(); + +// It's possible large upgrades could exceed the max execution time. +set_time_limit(0); + +// get ejabberd db settings from elgg. +$domain = elgg_get_plugin_setting("domain", "beechat"); +$dbname = elgg_get_plugin_setting("dbname", "beechat"); +$dbhost = elgg_get_plugin_setting("dbhost", "beechat"); +$dbuser = elgg_get_plugin_setting("dbuser", "beechat"); +$dbpassword = elgg_get_plugin_setting("dbpassword", "beechat"); + +$jabber_domain = $domain; + +$dbh_elgg = null; +$dbh_ejabberd = null; + +$dsn_elgg = 'mysql:dbname='.$CONFIG->dbname.';host='.$CONFIG->dbhost; +$dsn_ejabberd = 'mysql:dbname='.$dbname.';host='.$dbhost; + +$dbprefix = $CONFIG->dbprefix; + +$user = $dbuser; +$password = $dbpassword; + +$relationship_type = 'friend'; + +$counter = 0; + +try { + $dbh_elgg = new PDO($dsn_elgg, $CONFIG->dbuser, $CONFIG->dbpass); + + $sql = 'SELECT guid, name, username FROM '.$dbprefix.'users_entity'; + $sth = $dbh_elgg->prepare($sql); + $sth->execute(); + + $users = array(); + while ($row = $sth->fetch(PDO::FETCH_ASSOC)) + $users[$row['guid']] = $row; + + $sql = 'SELECT guid_one, guid_two FROM '.$dbprefix.'entity_relationships '; + $sql .= 'WHERE relationship = ?;'; + $sth = $dbh_elgg->prepare($sql); + + $sth->bindParam(1, $relationship_type); + $sth->execute(); + + $dbh_ejabberd = new PDO($dsn_ejabberd, $user, $password); + $dbh_ejabberd->beginTransaction(); + + while ($row = $sth->fetch(PDO::FETCH_ASSOC)) { + $sql = 'INSERT INTO rosterusers (username, jid, nick, subscription, ask, server, type) VALUES (?, ?, ?, ?, ?, ?, ?);'; + $sth_ejabberd = $dbh_ejabberd->prepare($sql); + + + $username = $users[$row['guid_one']]['username']; + $jid = $users[$row['guid_two']]['username'] . '@' . $jabber_domain; + $nick = $users[$row['guid_two']]['name']; + $subscription = 'B'; + $ask = 'N'; + $server = 'N'; + $type = 'item'; + + $sth_ejabberd->execute(array($username, $jid, $nick, $subscription, $ask, $server, $type)); + + $counter += 1; + if ($counter % 1000 == 0) { + //error_log( $username . ' registered ' . $jid . ' as a friend in his roster.' . "\n"); + error_log("importing relations into jabber: $counter"); + } + } + + $dbh_ejabberd->commit(); + + $dbh_elgg = null; + $dbh_ejabberd = null; +} catch (PDOException $e) { + if ($dbh_ejabberd != null) + $dbh_ejabberd->rollBack(); + echo $e->getMessage(); +} +?> + + diff --git a/mod/beechat/migrategroups.php b/mod/beechat/migrategroups.php new file mode 100644 index 000000000..4e3ef3f2b --- /dev/null +++ b/mod/beechat/migrategroups.php @@ -0,0 +1,18 @@ +<? +require_once(dirname(__FILE__) . "/lib.php"); + +admin_gatekeeper(); + +// groups disabled for now +exit(); + +$groups = elgg_get_entities(array('types'=>'group','limit'=>0)); +elgg_set_ignore_access(true); +foreach($groups as $group) { + echo "migrating " . $group->name . "<br/>"; + ejabberd_create_group($group); +} +echo "done!"; +elgg_set_ignore_access(false); + +?> diff --git a/mod/beechat/sounds/newmessage.wav b/mod/beechat/sounds/newmessage.wav Binary files differnew file mode 100644 index 000000000..58cccd0e6 --- /dev/null +++ b/mod/beechat/sounds/newmessage.wav diff --git a/mod/beechat/start.php b/mod/beechat/start.php new file mode 100644 index 000000000..4e4e4bb40 --- /dev/null +++ b/mod/beechat/start.php @@ -0,0 +1,184 @@ +<?php + /** + * Beechat + * + * @package beechat + * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html GNU Public License version 2 + * @author Beechannels <contact@beechannels.com> + * @copyright Beechannels 2007-2010 + * @link http://beechannels.com/ + */ + + GLOBAL $CONFIG; + + function beechat_create_group($event, $object_type, $object) + { + elgg_load_library('elgg:beechat'); + ejabberd_create_group($object); + } + + function beechat_delete_group($event, $object_type, $object) + { + elgg_load_library('elgg:beechat'); + ejabberd_destroy_group($object); + } + + function beechat_member_add($event, $object_type, $object) + { + if ($object->relationship === "member") { + elgg_load_library('elgg:beechat'); + $user = get_entity($object->guid_one); + $group = get_entity($object->guid_two); + $room = new EjabberdMucRoom($group); + $room->addMember($user); + } + } + + function beechat_member_delete($event, $object_type, $object) + { + if ($object->relationship === "member") { + elgg_load_library('elgg:beechat'); + $user = get_entity($object->guid_one); + $group = get_entity($object->guid_two); + $room = new EjabberdMucRoom($group); + $room->setAffiliation($user, "none"); + } + } + + function beechat_init() + { + $pluginspath = elgg_get_plugins_path(); + elgg_register_library('elgg:beechat', $pluginspath . 'beechat/lib/beechat.php'); + + elgg_register_event_handler('pagesetup', 'system', 'beechat_pagesetup'); + // group actions disabled for now + /*if (elgg_get_plugin_setting("groupdomain", "beechat")) { + register_elgg_event_handler('create', 'group', 'beechat_create_group'); + register_elgg_event_handler('delete', 'group', 'beechat_delete_group'); + } + register_elgg_event_handler('create', 'member', 'beechat_member_add'); + register_elgg_event_handler('delete', 'relationship', 'beechat_member_delete');*/ + + + $actions_path = $pluginspath . 'beechat/actions/'; + //elgg_register_action('beechat/join_groupchat', $actions_path . 'join_groupchat.php'); + //elgg_register_action('beechat/leave_groupchat', $actions_path . 'leave_groupchat.php'); + elgg_register_action('beechat/get_statuses', $actions_path . 'get_statuses.php'); + elgg_register_action('beechat/get_icons', $actions_path . 'get_icons.php'); + elgg_register_action('beechat/get_details', $actions_path . 'get_details.php'); + elgg_register_action('beechat/get_connection', $actions_path . 'get_connection.php'); + elgg_register_action('beechat/get_state', $actions_path . 'get_state.php'); + elgg_register_action('beechat/save_state', $actions_path . 'save_state.php'); + + /*register_elgg_event_handler('create', 'friendrequest', 'beechat_xmpp_add_friendx'); + #register_plugin_hook('action', 'friends/add', 'beechat_xmpp_add_friend', 1000); + register_plugin_hook('river_update', 'river_update', 'beechat_xmpp_approve_friendx'); + register_plugin_hook('river_update_foreign', 'river_update', 'beechat_xmpp_approve_friendx'); + #register_plugin_hook('action', 'friendrequest/approve', 'beechat_xmpp_approve_friend', 1000); + + + register_plugin_hook('action', 'friendrequest/decline', 'beechat_xmpp_decline_friend', 1000); + register_plugin_hook('action', 'friends/remove', 'beechat_xmpp_remove_friend', 1000);*/ + + // new friend sync + elgg_register_event_handler('delete', 'friend', array('BeechatSync', 'onFriendDelete')); + //elgg_register_event_handler('create', 'friendrequest', array('BeechatSync', 'onFriendCreate')); + elgg_register_event_handler('delete', 'friendrequest', array('BeechatSync', 'onFriendDelete')); + + + + elgg_extend_view('js/initialise_elgg', 'js/json2.js'); + elgg_extend_view('js/initialise_elgg', 'js/jquery.cookie.min.js'); + elgg_extend_view('js/initialise_elgg', 'js/jquery.scrollTo-min.js'); + elgg_extend_view('js/initialise_elgg', 'js/jquery.serialScroll-min.js'); + elgg_extend_view('js/initialise_elgg', 'js/b64.js'); + elgg_extend_view('js/initialise_elgg', 'js/sha1.js'); + elgg_extend_view('js/initialise_elgg', 'js/md5.js'); + elgg_extend_view('js/initialise_elgg', 'js/strophe.min.js'); + elgg_extend_view('js/initialise_elgg', 'js/strophe.muc.js'); + elgg_extend_view('js/initialise_elgg', 'js/jquery.tools.min.js'); + elgg_extend_view('css', 'beechat/screen.css'); + elgg_extend_view('js/initialise_elgg', 'beechat/beechat.js'); + elgg_extend_view('page/elements/head', 'beechat/beechat.userjs'); + + elgg_extend_view('page/elements/foot', 'beechat/beechat'); + + $domain = elgg_get_plugin_setting("domain", "beechat"); + //$group_domain = elgg_get_plugin_setting("groupdomain", "beechat"); + /*$dbname = elgg_get_plugin_setting("dbname", "beechat"); + $dbhost = elgg_get_plugin_setting("dbhost", "beechat"); + $dbuser = elgg_get_plugin_setting("dbuser", "beechat"); + $dbpassword = elgg_get_plugin_setting("dbpassword", "beechat");*/ + + global $CONFIG; + $CONFIG->chatsettings['domain'] = $domain; + //$CONFIG->chatsettings['groupdomain'] = $group_domain; + + register_notification_handler('xmpp', 'beechat_notifications'); + // register_plugin_hook('notify:entity:message','object','beechat_notifications_msg'); + } + + function beechat_notifications($from, $to, $subject, $topic, $params = array()) { + ejabberd_send_chat($to, "<div>".$topic."</div>"); + } + + + function beechat_friendly_title($title) { + // need this because otherwise seems elgg + // gets in some problem trying to call the view + //$title = iconv('UTF-8', 'ASCII//TRANSLIT', $title); + $title = preg_replace("/[^\w ]/","",$title); + $title = str_replace(" ","-",$title); + $title = str_replace("--","-",$title); + $title = trim($title); + $title = strtolower($title); + return $title; + } + + function beechat_pagesetup() + { + global $CONFIG; + /*if (elgg_get_context() == 'group_profile' && elgg_is_logged_in()) { + if (elgg_get_plugin_setting("groupdomain", "beechat")) { + $user = elgg_get_logged_in_user_entity(); + $group = elgg_get_page_owner_entity(); + if (!$group || !($group instanceof ElggGroup)) + return; + if ($user->chatenabled && elgg_get_plugin_setting("groupdomain", "beechat")) { + if ($group->isPublicMembership() || $group->isMember($user)) { + $item = new ElggMenuItem('chatroom', elgg_echo('beechat:chatroom'), "javascript:g_beechat_user.joinRoom('".beechat_friendly_title($group->name)."@".$CONFIG->chatsettings['groupdomain']."', '".$group->guid."')"); + elgg_register_menu_item('page', 'item'); + } + } + } + } + else*/if (elgg_get_context() == 'settings' && elgg_is_logged_in()) { + $is_enabled = elgg_get_logged_in_user_entity()->chatenabled; + $action = $is_enabled ? 'disable' : 'enable'; + elgg_register_menu_item('page', array( + 'name' => 'beechat', + 'text'=> elgg_echo("beechat:{$action}chat"), + 'href' => $CONFIG->wwwroot . "mod/beechat/{$action}chat.php", + )); + } + } + + + function ejabberd_send_chat($user, $body) { // $user adds $friend + $from = 'notify@'.elgg_get_plugin_setting("domain", "beechat").'/net'; + if ($user->alias) { + + } + elgg_load_library('elgg:beechat'); + $to = ejabberd_getjid($user, true); + //xmlrpc_set_type(&$body, "base64"); + $param = array("body" => $body, + "from" => $from, + "to" => $to); + ejabberd_xmlrpc_command('send_html_message', $param); + } + + + + +elgg_register_event_handler('init', 'system', 'beechat_init'); diff --git a/mod/beechat/views/default/beechat/beechat.js.php b/mod/beechat/views/default/beechat/beechat.js.php new file mode 100644 index 000000000..09f4e8852 --- /dev/null +++ b/mod/beechat/views/default/beechat/beechat.js.php @@ -0,0 +1,2498 @@ +/** + * Beechat + * + * @package beechat + * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html GNU Public License version 2 + * @author Beechannels <contact@beechannels.com> + * @copyright Beechannels 2007-2010 + * @link http://beechannels.com/ + */ + +/** Globals + * + */ +g_beechat_user = null; +g_beechat_roster_items = null; +g_beechat_rooms = new Array(); + +function debugXMPP(msg) { + try { + //console.log(msg) + } + catch (err) { + } + //$('#layout_footer').html($('#layout_footer').html()+'<br/>'+msg); +} + +/** Class: BeeChat + * An object container for all BeeChat mod functions + * + */ +BeeChat = { + BOSH_SERVICE: '/http-bind/', + DOMAIN: '<?php echo $vars['config']->chatsettings['domain'] ?>', + RESOURCE: 'beebac', + INACTIVITY_PERIOD_LENGTH: 60, + + NS: { + CHAT_STATES: 'http://jabber.org/protocol/chatstates' + }, + + Message: { + Types: { + NORMAL: 'normal', + CHAT: 'chat', + GROUPCHAT: 'groupchat', + HEADLINE: 'headline', + ERROR: 'error' + }, + + ChatStates: { + COMPOSING: 'composing', + PAUSED: 'paused', + ACTIVE: 'active', + INACTIVE: 'inactive', + GONE: 'gone' + } + }, + + IQ: { + Types: { + GET: 'get', + RESULT: 'result', + SET: 'set', + ERROR: 'error' + } + }, + + Presence: { + Types: { + UNAVAILABLE: 'unavailable', + SUBSCRIBE: 'subscribe', + SUBSCRIBED: 'subscribed', + UNSUBSCRIBE: 'unsubscribe', + UNSUBSCRIBED: 'unsubscribed', + PROBE: 'probe', + ERROR: 'error' + }, + + ChildElements: { + SHOW: 'show', + STATUS: 'status', + PRIORITY: 'priority' + }, + + ShowElements: { + CHAT: 'chat', + DND: 'dnd', + AWAY: 'away', + XA: 'xa' + } + }, + + Roster: { + DEFAULT_GROUP: 'Contacts' + }, + + + Events: { + Identifiers: { + UPDATE_CONNECTION_STATE: 0, + UPDATE_ROSTER: 1, + RECV_PRESENCE: 2, + RECV_CHAT_MESSAGE: 3 + }, + Messages: { + ConnectionStates: { + CONNECTING: "<?php echo elgg_echo('beechat:connection:state:connecting'); ?>", + AUTHENTICATING: "<?php echo elgg_echo('beechat:connection:state:authenticating'); ?>", + FAILED: "<?php echo elgg_echo('beechat:connection:state:failed'); ?>", + DISCONNECTING: "<?php echo elgg_echo('beechat:connection:state:disconnecting'); ?>", + OFFLINE: "<?php echo elgg_echo('beechat:connection:state:offline'); ?>", + ONLINE: "<?php echo elgg_echo('beechat:connection:state:online'); ?>" + } + } + } +}; + + +/** Class: BeeChat.Core + * An object container for all BeeChat Core functions + * + */ +BeeChat.Core = { + ReferenceTables: { + AvailabilityRates: { + AVAILABLE: 0, + ONLINE: 0, + CHAT: 0, + DND: 1, + AWAY: 2, + XA: 3, + UNAVAILABLE: 10, + OFFLINE: 10 + } + } +}; + + +/** Class: BeeChat.Core.User + * Create a BeeChat.Core.User object + * + * Parameters: + * (String) jid - The user's jabber id + * + * Returns: + * A new BeeChat.Core.User. + */ +BeeChat.Core.User = function(jid) +{ + if (!(this instanceof arguments.callee)) + return new BeeChat.Core.User(jid); + + /** Private members + * + */ + var _connection = null; + var _attached = false; + var _initialized = false; + var _jid = null; + var _roster = null; + var _msgTemp = []; + var _funcs = []; + + /** Constructor + * + */ + this.init = function(jid) + { + _jid = jid; + _roster = new BeeChat.Core.Roster(); + } + + /** Accessors + * + */ + this.getConnection = function() + { + return _connection; + } + + this.getJid = function() + { + return _jid; + } + + this.getRoster = function() + { + return _roster; + } + + this.isAttached = function() + { + return _attached; + } + + this.isInitialized = function() + { + return _initialized; + } + + /** Mutators + * + */ + this.setInitialized = function(isInitialized) + { + _initialized = isInitialized; + } + + /** Function: addObserver + * Add an observer for a specified type of event + * + * Parameters: + * (BeeChat.Events.Identifiers) eventType - The type of event to observer + * (Object) pFunc - A function to call when the event will be triggered + */ + this.addObserver = function(eventType, pFunc) + { + if (jQuery.inArray(pFunc, _funcs) == -1) { + if (!_funcs[eventType]) + _funcs[eventType] = []; + _funcs[eventType].push(pFunc); + } + } + + /** Function: removeObserver + * Remove an observer + * + * Parameters: + * (Object) pFunc - The registered function + */ + this.removeObserver = function(pFunc) + { + var index = null; + + for (var key in _funcs) { + if (typeof _funcs[key] != 'object') + continue; + if ((index = jQuery.inArray(pFunc, _funcs[key])) != -1) + _funcs.splice(index, 1); + } + } + + /** Function: connect + * Connect the user to the BOSH service + * + * Parameters: + * (String) password - The user's password + * + */ + this.connect = function(password) + { + debugXMPP('connect'); + if (_connection == null) + _connection = new Strophe.Connection(BeeChat.BOSH_SERVICE); + _connection.connect(_jid, password, _onConnect); + } + + /** Function: attach + * Attach user's connection to an existing XMPP session + * + * Parameters: + * (String) sid - The SID of the existing XMPP session + * (String) rid - The RID of the existing XMPP session + */ + this.attach = function(sid, rid) + { + if (_connection == null) { + _connection = new Strophe.Connection(BeeChat.BOSH_SERVICE); + } + _connection.attach(_jid, sid, rid, _onConnect); + _attached = true; + _onConnect(Strophe.Status.CONNECTED); + } + + /** Function: disconnect + * Disconnect the user from the BOSH service + * + */ + this.disconnect = function() + { + debugXMPP('disconnect'); + if (_connection != null) { + _connection.disconnect(); + _connection = null; + } + } + + /** Function: requestSessionPause + * Request a session pause to the server connection manager + * + */ + this.requestSessionPause = function() + { + var req = $build('body', { + rid: _connection.rid, + sid: _connection.sid, + pause: BeeChat.INACTIVITY_PERIOD_LENGTH, + xmlns: Strophe.NS.HTTPBIND + }); + + _attached = false; + _connection.send(req.tree()); + } + + /** Function: requestRoster + * Request a new roster to the server + * + */ + this.requestRoster = function() + { + var req = $iq({from: _jid, type: BeeChat.IQ.Types.GET}) + .c('query', {xmlns: Strophe.NS.ROSTER}); + + _connection.send(req.tree()); + } + + /** Function: sendInitialPresence + * Send initial presence to the server in order to signal availability for communications + * + */ + this.sendInitialPresence = function() + { + _connection.send($pres().tree()); + _initialized = true; + } + + /** Function: sendChatMessage + * Send a chat message to the server + * + * Parameters: + * (String) addressee - The addressee of the chat message + * (String) msg - The chat message + * + */ + this.sendChatMessage = function(addressee, msg, msgtype) + { + if (msgtype == null) + msgtype = BeeChat.Message.Types.CHAT; + var req = $msg({ + type: msgtype, + to: addressee, + from: _connection.jid + }).c('body').t(msg).up().c(BeeChat.Message.ChatStates.ACTIVE, {xmlns: BeeChat.NS.CHAT_STATES}); + + _connection.send(req.tree()); + } + + /** Function: sendChatStateMessage + * Send a chat state message to the server + * + * Parameters: + * (String) addressee - The addressee of the chat state message + * (BeeChat.Message.ChatsState) state - The chat state that will be send + * + */ + this.sendChatStateMessage = function(addressee, state) + { + var req = $msg({ + type: BeeChat.Message.Types.CHAT, + to: addressee, + from: _connection.jid + }).c(state, {xmlns: BeeChat.NS.CHAT_STATES}); + + _connection.send(req.tree()); + } + + /** Function: sendPresenceAvailabiliy + * Send a detailed presence stanza to the server + * + * Parameters: + * (BeeChat.Presence.ShowElements) availability - The availability status + * (String) details - Detailed status information + * + */ + this.sendPresenceAvailability = function(availability, details) + { + var req = $pres() + .c(BeeChat.Presence.ChildElements.SHOW).t(availability).up() + .c(BeeChat.Presence.ChildElements.STATUS).t(details).up() + .c(BeeChat.Presence.ChildElements.PRIORITY).t('1'); + + _connection.send(req.tree()); + } + + /** PrivateFunction: _fire + * Triggers registered funcs of registered observers for a specified type of event + * + */ + function _fire(eventType, data, scope) + { + if (_funcs[eventType] != undefined) { + for (var i = 0; i < _funcs[eventType].length; i++) + _funcs[eventType][i].call((scope || window), data); + } + } + this.joinRoom = function(roomname, room_guid) { + var roomJid = roomname; + _connection['muc'].join(roomJid, BeeChat.UI.Resources.Strings.ChatMessages.SELF, false, false, ''); + if (!(roomJid in g_beechat_rooms)) { + g_beechat_rooms[roomJid] = room_guid; + $.ajax({ + url: BeeChat.UI.addActionTokens('<?php echo $vars['url'] . "action/beechat/join_groupchat?group_guid="; ?>'+room_guid, '&'), + async: true }); + } + + + } + + this.reconnectRooms = function() { + $('#' + BeeChat.UI.Resources.Elements.ID_DIV_CHATBOXES).children().each(function() { + if (roomJid in g_beechat_rooms) + delete g_beechat_rooms[roomJid]; + var contactBareJid = $(this).attr('bareJid'); + var isroom = ($(this).attr('isroom')=='true')?true:false; + if (isroom) { + _connection['muc'].join(contactBareJid, BeeChat.UI.Resources.Strings.ChatMessages.SELF, false, false, ''); + } + }); + } + + this.leaveRoom = function(roomJid) { + if (roomJid in g_beechat_rooms) { + $.ajax({ + url: BeeChat.UI.addActionTokens('<?php echo $vars['url'] . "action/beechat/leave_groupchat?group_guid="; ?>'+g_beechat_rooms[roomJid], '&'), + async: true }); + + } + _connection['muc'].leave(roomJid, BeeChat.UI.Resources.Strings.ChatMessages.SELF, function(){}); + } + + /** PrivateFunction: _onConnect + * Connection state manager + * + * Parameters: + * (Strophe.Status) status - A Strophe connection status constant + * + */ + function _onConnect(status) + { + var msg = null; + + if (status == Strophe.Status.CONNECTING) +{ + msg = BeeChat.Events.Messages.ConnectionStates.CONNECTING; + } + else if (status == Strophe.Status.AUTHENTICATING) { + msg = BeeChat.Events.Messages.ConnectionStates.AUTHENTICATING; + } + else if (status == Strophe.Status.AUTHFAIL) + msg = BeeChat.Events.Messages.ConnectionStates.FAILED; + else if (status == Strophe.Status.CONNFAIL) + msg = BeeChat.Events.Messages.ConnectionStates.FAILED; + else if (status == Strophe.Status.DISCONNECTING) + msg = BeeChat.Events.Messages.ConnectionStates.DISCONNECTING; + else if (status == Strophe.Status.DISCONNECTED) + msg = BeeChat.Events.Messages.ConnectionStates.OFFLINE; + else if (status == Strophe.Status.CONNECTED) { + msg = BeeChat.Events.Messages.ConnectionStates.ONLINE; + _connection.addHandler(_onIQResult, null, 'iq', BeeChat.IQ.Types.RESULT, null, null); + _connection.addHandler(_onPresence, null, 'presence', null, null, null); + _connection.addHandler(_onMessageChat, null, 'message', BeeChat.Message.Types.CHAT, null, null); + _connection.addHandler(_onMessageChatRoom, null, 'message', BeeChat.Message.Types.GROUPCHAT, null, null); + } + + _fire(BeeChat.Events.Identifiers.UPDATE_CONNECTION_STATE, msg); + } + + /** PrivateFunction: _onIQResult + * Manage received IQ stanza of 'result' type + * + * Parameters: + * (XMLElement) iq - The iq stanza received + * + */ + function _onIQResult(iq) + { + _roster.updateFromIQResult(iq); + _fire(BeeChat.Events.Identifiers.UPDATE_ROSTER, _roster.getItems()); + + return true; + } + + /** PrivateFunction: _onPresence + * Manage received presence stanza + * + * Parameters: + * (XMLElement) presence - The presence stanza received + * + */ + function _onPresence(presence) + { + var xquery = presence.getElementsByTagName("x"); + debugXMPP('_onPresence'+xquery); + if (xquery.length > 0) + { + //Ignore MUC user protocol + for (var i = 0; i < xquery.length; i++) + { + var xmlns = xquery[i].getAttribute("xmlns"); + if (xmlns && xmlns.match(Strophe.NS.MUC + '#user')) + { + var contactBareJid = $(presence).attr('from').split('/')[0]; + var userNick = $(presence).attr('from').split('/')[1]; + var chatBoxElm = BeeChat.UI.ChatBoxes.getChatBoxElm(contactBareJid); + if ($(presence).attr('type') != 'unavailable') { + BeeChat.UI.ChatBoxes.updateRoster(contactBareJid, userNick, presence); + } + else { + if (chatBoxElm.length) { + BeeChat.UI.ChatBoxes.updateRoster(contactBareJid, userNick, presence); + } + } + return true; + } + + if (xmlns && xmlns.match(Strophe.NS.MUC)) + { + var contactBareJid = $(presence).attr('from').split('/')[0]; + var chatBoxElm = BeeChat.UI.ChatBoxes.getChatBoxElm(contactBareJid); + + if ($(presence).attr('type') != 'unavailable' && $(presence).attr('type') != 'error') { + if (chatBoxElm.length == 0) { + BeeChat.UI.ScrollBoxes.add(contactBareJid); + } + } + return true; + } + + } + } + + if (Strophe.getBareJidFromJid($(presence).attr('from')).toLowerCase() != Strophe.getBareJidFromJid(_jid).toLowerCase()) { + _roster.updateFromPresence(presence); + } + _fire(BeeChat.Events.Identifiers.RECV_PRESENCE, _roster.getOnlineItems()); + return true; + } + + /** PrivateFunction: _onMessageChat + * Manage received message stanza of 'chat' type + * + * Parameters: + * (XMLElement) message - The message stanza received + * + */ + function _onMessageChatRoom(message) + { + var roomJid = $(message).attr('from').split('/'); + +// BeeChat.UI.ChatBoxes.updateChatState($(message).attr('from'), message); + BeeChat.UI.ChatBoxes.update(roomJid[0], roomJid[1], Strophe.getText($(message).find('body')[0]), true); + + return true; + } + + function _onMessageChat(message) + { + var data = { + contactBareJid: Strophe.getBareJidFromJid($(message).attr('from')), + msg: message + }; + _msgTemp.push(data); + //alert("message"); + if (_initialized == true) { + for (var key in _msgTemp) { + if (typeof _msgTemp[key] != 'object') + continue; + _fire(BeeChat.Events.Identifiers.RECV_CHAT_MESSAGE, _msgTemp[key]); + _msgTemp.shift(); + } + } + + return true; + } + + this.init(jid); +}; + + +/** Constructor: BeeChat.Core.Roster + * Create a BeeChat.Core.Roster object + * + * Parameters: + * (Object) items - The roster's items in object notation + * + * Returns: + * A new BeeChat.Core.Roster. + */ +BeeChat.Core.Roster = function() +{ + if (!(this instanceof arguments.callee)) + return new BeeChat.Core.Roster(); + + /** Private members + * + */ + _items = null; + + + /** Constructor + * + */ + this.init = function() + { + _items = (arguments.length > 0) ? arguments[0] : {}; + } + + /** Accessors + * + */ + this.getItems = function() + { + return _items; + } + + /** Mutators + * + */ + this.setItems = function(items) + { + for (var key in items) { + _items[key] = new BeeChat.Core.RosterItem(items[key]); + var contactBareJid = items[key].bareJid; + var chatBoxElm = BeeChat.UI.ChatBoxes.getChatBoxElm(contactBareJid); + var status = items[key].status; + /*if (status != 'unavailable' && status != 'error') { + if (chatBoxElm.length == 0) { + BeeChat.UI.ScrollBoxes.add(contactBareJid); + } + }*/ + + } + } + + this.setIcons = function(icons) + { + if (_items) { + for (var key in icons) { + if (_items[key]) { + _items[key].icon_small = icons[key].small; + _items[key].icon_tiny = icons[key].tiny; + } + } + } + } + + this.setStatuses = function(statuses) + { + if (_items) { + for (var key in statuses) { + if (_items[key]) { + _items[key].status = statuses[key]; + } + } + } + } + + /** Function: updateFromIQResult + * Update the roster items from an IQ result stanza + * + * Parameters: + * (XMLElement) iq - The IQ result stanza + */ + this.updateFromIQResult = function(iq) + { + $(iq).find('item').each(function() { + var attr = { + bareJid: Strophe.getBareJidFromJid($(this).attr('jid')).toLowerCase(), + name: $(this).attr('name'), + subscription: $(this).attr('subscription'), + groups: [], + presences: {} + }; + + $(this).find('group').each(function() { + attr['groups'].push($(this).text()); + }); + + if (attr['groups'].length == 0) + attr['groups'].push(BeeChat.Roster.DEFAULT_GROUP); + + if (!_items[attr.bareJid]) + _items[attr.bareJid] = new BeeChat.Core.RosterItem(attr); + else { + _items[attr.bareJid].bareJid = attr.bareJid; + _items[attr.bareJid].name = attr.name; + _items[attr.bareJid].subscription = attr.subscription; + _items[attr.bareJid].groups = attr.groups; + } + }); + } + + /** Function: updateFromPresence + * Update the roster items from a presence stanza + * + * Parameters: + * (XMLElement) presence - The presence stanza + * + * Returns: + * (String) The bare jid of the roster item who updated his presence + */ + this.updateFromPresence = function(presence) + { + var jid = $(presence).attr('from').toLowerCase(); + var attr = { + bareJid: Strophe.getBareJidFromJid(jid), + name: null, + subscription: null, + groups: null, + presences: {} + }; + + attr.presences[jid] = {}; + attr.presences[jid].type = (!$(presence).attr('type')) ? 'available' : $(presence).attr('type'); + //alert($(presence).attr('from')+presence.toString()); + //alert("presencetype"+attr.presences[jid].type); + + if (attr.presences[jid].type == 'available') { + $(presence).children().each(function() { + if (this.tagName == BeeChat.Presence.ChildElements.SHOW) + attr.presences[jid].show = $(this).text(); + if (this.tagName == BeeChat.Presence.ChildElements.STATUS) + attr.presences[jid].status = $(this).text(); + }); + + if (!attr.presences[jid].show) + attr.presences[jid].show = 'chat'; + } else { + attr.presences[jid].show = 'offline'; + } + + if (!_items[attr.bareJid]) + _items[attr.bareJid] = new BeeChat.Core.RosterItem(attr); + else + _items[attr.bareJid].presences[jid] = attr.presences[jid]; + } + + /** Function: getOnlineItems + * + * + */ + this.getOnlineItems = function() + { + var sortedOnlineBareJid = []; + var sortedOnlineItems = {}; + + for (var key in _items) { + if (typeof _items[key] != 'object') + continue; + + var pres = _items[key].getStrongestPresence(); + + if (pres != null && pres.type == 'available') { + sortedOnlineBareJid.push(key); + } + } + + if (sortedOnlineBareJid.length > 1) { + sortedOnlineBareJid.sort(); + sortedOnlineBareJid.sort(statusSort); + } + + for (var key in sortedOnlineBareJid) { + sortedOnlineItems[sortedOnlineBareJid[key]] = _items[sortedOnlineBareJid[key]]; + } + + return (sortedOnlineItems); + } + + /** Function: getSizeOnlineItems + * Return the number of available items + * + * Returns: + * (int) The number of available items + */ + this.getSizeOnlineItems = function() + { + var n = 0; + + for (var key in _items) { + if (typeof _items[key] != 'object') + continue; + + var pres = _items[key].getStrongestPresence(); + + if (pres != null && pres.type == 'available') + ++n; + } + return (n); + } + + /** Function: getItemsUsernamesAsList + * + */ + this.getItemsUsernamesAsList = function() + { + var data = ''; + + for (var key in _items) { + if (typeof _items[key] != 'object') + continue; + data = data + Strophe.getBareJidFromJid(key) + ','; + // data = data + Strophe.getNodeFromJid(key) + ','; + } + + return (data); + } + + /** PrivateFunction: statusSort + * + */ + function statusSort(x, y) + { + var xPres = _items[x].getStrongestPresence(); + var yPres = _items[y].getStrongestPresence(); + + if (xPres != null && yPres != null) + return (BeeChat.Core.Roster.Utils.comparePresences(xPres, yPres)); + return (0); + } + + this.init(); +}; + +BeeChat.Core.Roster.Utils = { + + /** Function: comparePresences + * Compare the two presences x and y + * + * Parameters: + * (Object) xPres - The x presence in object notation + * (Object) yPres - The y presence in object notation + * + * Returns: + * 0 if presence are equal, 1 if x > y, -1 if y > x + * + * Note: + * Presences are tagged in the following order: + * ONLINE < DND < AWAY < XA < OFFLINE + * + */ + comparePresences: function(xPres, yPres) + { + var xRate = 0; + var yRate = 0; + + if (xPres.type == 'unavailable') + xRate += BeeChat.Core.ReferenceTables.AvailabilityRates[xPres.type.toUpperCase()]; + if (yPres.type == 'unavailable') + yRate += BeeChat.Core.ReferenceTables.AvailabilityRates[yPres.type.toUpperCase()]; + + if (xPres.show != null) + xRate += BeeChat.Core.ReferenceTables.AvailabilityRates[xPres.show.toUpperCase()]; + if (yPres.show != null) + yRate =+ BeeChat.Core.ReferenceTables.AvailabilityRates[yPres.show.toUpperCase()]; + + if (xRate > yRate) + return (1); + else if (xRate == yRate) + return (0); + return (-1); + } +}; + + +/** Constructor: BeeChat.Core.RosterItem + * Create a BeeChat.Core.RosterItem object + * + * Parameters: + * (Object) attr - The RosterItem's attributes in object notation + * + * Returns: + * A new BeeChat.Core.RosterItem. + */ +BeeChat.Core.RosterItem = function() +{ + this.bareJid = (arguments.length > 0) ? arguments[0].bareJid : null; + this.name = (arguments.length > 0) ? arguments[0].name : null; + this.subscription = (arguments.length > 0) ? arguments[0].subscription : null; + this.groups = (arguments.length > 0) ? arguments[0].groups : null; + this.presences = (arguments.length > 0) ? arguments[0].presences : null; + this.icon_small = (arguments.length > 0) ? arguments[0].icon_small : null; + this.icon_tiny = (arguments.length > 0) ? arguments[0].icon_tiny : null; + this.status = (arguments.length > 0) ? arguments[0].status : null; +}; +BeeChat.Core.RosterItem.prototype = { + /** Function: getStrongestPresence + * Return the strongest presence of the RosterItem + * + */ + getStrongestPresence: function() + { + var res = null; + + for (var key in this.presences) { + if (typeof this.presences[key] != 'object') + continue; + if (res == null) + res = this.presences[key]; + else + if (BeeChat.Core.Roster.Utils.comparePresences(this.presences[key], res) == -1) + res = this.presences[key]; + } + return (res); + } +}; + + +/** Class: BeeChat.UI + * An object container for all BeeChat UI functions + * + */ +BeeChat.UI = { + HAS_FOCUS: true, + + Resources: { + Paths: { + ICONS: '<?php echo $vars['config']->url; ?>mod/beechat/graphics/icons/', + MEMBER_PROFILE: '<?php echo $vars['url']; ?>profile/' + }, + + Sounds: { + NEW_MESSAGE: 'beechat_sounds_new_message' + }, + + /* + Cookies: { + DOMAIN: 'beechannels.com', + FILENAME_CONN: 'beechat_conn' + }, + */ + + Emoticons: { + FILENAME_SMILE: 'emoticon_smile.png', + FILENAME_UNHAPPY: 'emoticon_unhappy.png', + FILENAME_GRIN: 'emoticon_grin.png', + FILENAME_EVILGRIN: 'emoticon_evilgrin.png', + FILENAME_SURPRISED: 'emoticon_surprised.png', + FILENAME_TONGUE: 'emoticon_tongue.png', + FILENAME_WINK: 'emoticon_wink.png' + }, + + Strings: { + Availability: { + AVAILABLE: "<?php echo elgg_echo('beechat:availability:available'); ?>", + CHAT: "<?php echo elgg_echo('beechat:availability:available'); ?>", + ONLINE: "<?php echo elgg_echo('beechat:availability:available'); ?>", + DND: "<?php echo elgg_echo('beechat:availability:dnd'); ?>", + AWAY: "<?php echo elgg_echo('beechat:availability:away'); ?>", + XA:"<?php echo elgg_echo('beechat:availability:xa'); ?>", + OFFLINE: "<?php echo elgg_echo('beechat:availability:offline'); ?>" + }, + + Contacts: { + BUTTON: "<?php echo elgg_echo('beechat:contacts:button'); ?>" + }, + + ChatMessages: { + SELF: "<?php echo $_SESSION['user']->name; ?>", + COMPOSING: "<?php echo elgg_echo('beechat:chat:composing'); ?>" + }, + + Box: { + MINIMIZE: "<?php echo elgg_echo('beechat:box:minimize'); ?>", + CLOSE: "<?php echo elgg_echo('beechat:box:close'); ?>", + SHOWHIDE: "<?php echo elgg_echo('beechat:box:showhide'); ?>" + } + }, + + StyleClasses: { + Availability: { + Left: { + ONLINE: 'beechat_left_availability_chat', + DND: 'beechat_left_availability_dnd', + AWAY: 'beechat_left_availability_away', + XA: 'beechat_left_availability_xa', + OFFLINE: 'beechat_left_availability_offline', + ROOM: 'beechat_left_availability_room' + }, + + Right: { + ONLINE: 'beechat_right_availability_chat', + DND: 'beechat_right_availability_dnd', + AWAY: 'beechat_right_availability_away', + XA: 'beechat_right_availability_xa', + OFFLINE: 'beechat_right_availability_offline', + ROOM: 'beechat_right_availability_room' + }, + + Control: { + UP: 'beechat_availability_switcher_control_up', + DOWN: 'beechat_availability_switcher_control_down' + } + }, + + ChatBox: { + MAIN: 'beechat_chatbox', + MAINROOM: 'beechat_chatbox_room', + TOP: 'beechat_chatbox_top', + SUBTOP: 'beechat_chatbox_subtop', + TOP_ICON: 'beechat_chatbox_top_icon', + TOP_CONTROLS: 'beechat_chatbox_top_controls', + CONTENT: 'beechat_chatbox_content', + INPUT: 'beechat_chatbox_input', + BOTTOM: 'beechat_chatbox_bottom', + CONTROL: 'beechat_chatbox_control', + STATE: 'beechat_chatbox_state', + MESSAGE: 'beechat_chatbox_message', + MESSAGE_SENDER: 'beechat_chatbox_message_sender', + MESSAGE_DATE: 'beechat_chatbox_message_date', + CHATROOM: 'beechat_chatbox_chatroom', + ROOMROSTER: 'beechat_chatbox_roomroster', + ROSTER_ITEM: 'beechat_chatbox_roomrosteritem' + }, + + ScrollBox: { + SELECTED: 'beechat_scrollbox_selected' + }, + + BOX_CONTROL: 'beechat_box_control', + LABEL: 'beechat_label', + UNREAD_COUNT: 'beechat_unread_count' + }, + + Elements: { + ID_DIV_BAR: 'beechat', + ID_DIV_BAR_CENTER: 'beechat_center', + ID_DIV_BAR_RIGHT: 'beechat_right', + + ID_TOOLTIP_TRIGGER: 'beechat_tooltip_trigger', + + ID_SPAN_CONTACTS_BUTTON: 'beechat_contacts_button', + ID_SPAN_CLOSE_BOX: 'beechat_box_control_close', + + ID_DIV_CONTACTS: 'beechat_contacts', + ID_DIV_CONTACTS_CONTROLS: 'beechat_contacts_controls', + ID_SPAN_CONTACTS_CONTROL_MINIMIZE: 'beechat_contacts_control_minimize', + ID_DIV_CONTACTS_CONTENT: 'beechat_contacts_content', + ID_UL_CONTACTS_LIST: 'beechat_contacts_list', + + ID_DIV_AVAILABILITY_SWITCHER: 'beechat_availability_switcher', + ID_SPAN_AVAILABILITY_SWITCHER_CONTROL: 'beechat_availability_switcher_control', + ID_SPAN_CURRENT_AVAILABILITY: 'beechat_current_availability', + ID_UL_AVAILABILITY_SWITCHER_LIST: 'beechat_availability_switcher_list', + + ID_DIV_CHATBOXES: 'beechat_chatboxes', + + ID_DIV_SCROLLBOXES: 'beechat_scrollboxes' + } + }, + + + /** Function: initialize + * Initialize the BeeChat UI + * + */ + initialize: function(ts, token) + { + this.ts = ts; + this.token = token; + $('#' + BeeChat.UI.Resources.Elements.ID_TOOLTIP_TRIGGER).tooltip({ + offset: [-3, 8], + effect: 'fade' + }); + + $('#accountlinks').find('li').filter('[class=last]').bind('click', function() { + if (g_beechat_user != null) + g_beechat_user.disconnect(); + }); + + BeeChat.UI.AvailabilitySwitcher.initialize(BeeChat.Presence.ShowElements.CHAT); + BeeChat.UI.ContactsList.initialize(); + BeeChat.UI.ScrollBoxes.initialize(); + BeeChat.UI.loadConnection(); + }, + + /** Function: getUserDetails + * Retrieve user details + * + * Returns: + * User details in object notation. + * + */ + addActionTokens: function(url_string, sep) + { + if (sep == null) + sep = "?"; + return url_string + sep + "__elgg_ts="+this.ts + "&__elgg_token=" + this.token; + }, + + getUserDetails: function(cb_func) + { + var json = null; + var self = this; + + $.ajax({ + url: self.addActionTokens('<?php echo $vars['url'] . "action/beechat/get_details"; ?>'), + async: true, + dataType: 'json', + success: function(data) { + cb_func(data); + } + }); + + return (json); + }, + + /** Function: connect + * Create the user and connect him to the BOSH service + * + * Parameters: + * (Object) conn - Running connection informations in object notation + */ + connect: function() + { + var conn = (arguments.length > 0) ? arguments[0] : null; + var userDetails = { + jid: (conn != null) ? conn.jid : null, + password: null + } + var self = this; + //alert("connect"); + if (conn == null || (conn != null && conn.attached)) { + BeeChat.UI.getUserDetails(function(retrievedUserDetails) { + userDetails.jid = retrievedUserDetails.username + '@' + BeeChat.DOMAIN + '/' + BeeChat.RESOURCE; + userDetails.password = retrievedUserDetails.password; + self.connect_end(conn, userDetails) + }); + } + else + this.connect_end(conn, userDetails) + }, + + connect_end: function(conn, userDetails) + { + g_beechat_user = new BeeChat.Core.User(userDetails.jid); + g_beechat_user.addObserver(BeeChat.Events.Identifiers.UPDATE_CONNECTION_STATE, BeeChat.UI.updateConnectionStatus); + g_beechat_user.addObserver(BeeChat.Events.Identifiers.UPDATE_ROSTER, BeeChat.UI.onRosterUpdate); + g_beechat_user.addObserver(BeeChat.Events.Identifiers.RECV_PRESENCE, BeeChat.UI.ContactsList.update); + g_beechat_user.addObserver(BeeChat.Events.Identifiers.RECV_CHAT_MESSAGE, BeeChat.UI.onChatMessage); + + if (conn == null || (conn != null && conn.attached)) + g_beechat_user.connect(userDetails.password); + else + g_beechat_user.attach(conn.sid, conn.rid); + }, + + /** Function: disconnect + * Terminate the user's XMPP session + * + */ + disconnect: function() + { + g_beechat_user.disconnect(); + }, + + /** Function: updateConnectionStatus + * + */ + updateConnectionStatus: function(connStatusMsg) + { + BeeChat.UI.ContactsList.updateButtonText(connStatusMsg); + if (connStatusMsg == BeeChat.Events.Messages.ConnectionStates.ONLINE) { + if (!g_beechat_user.isAttached()) { + debugXMPP("not attached"); + BeeChat.UI.ScrollBoxes.isOpened = true; + g_beechat_user.requestRoster(); + g_beechat_user.reconnectRooms(); + //BeeChat.UI.ContactsList.toggleDisplay(); + $('#' + BeeChat.UI.Resources.Elements.ID_UL_CONTACTS_LIST).show(); + $('.' + BeeChat.UI.Resources.StyleClasses.ChatBox.INPUT + '>textarea').removeAttr('disabled'); + for (room_idx in g_user_rooms) { + var room = g_user_rooms[room_idx]; + var chatBox = BeeChat.UI.ChatBoxes.getChatBoxElm(room[0]); + if (chatBox.length == 0) { + g_beechat_user.joinRoom(room[0], room[1]) + } + } + + } + if (g_beechat_user.isAttached()) { + debugXMPP("attached"); + BeeChat.UI.loadState(); + } + + + $('#' + BeeChat.UI.Resources.Elements.ID_SPAN_CONTACTS_BUTTON).attr('class', 'online'); + BeeChat.UI.saveConnection(); + } + else if (connStatusMsg == BeeChat.Events.Messages.ConnectionStates.OFFLINE) { + var contactsBoxElm = $('#' + BeeChat.UI.Resources.Elements.ID_DIV_CONTACTS); + + if (!contactsBoxElm.is(':hidden')) + BeeChat.UI.ContactsList.toggleDisplay(); + + $('#' + BeeChat.UI.Resources.Elements.ID_UL_CONTACTS_LIST).empty(); + BeeChat.UI.AvailabilitySwitcher.initialize(BeeChat.Presence.ShowElements.CHAT); + BeeChat.UI.ContactsList.updateButtonText(BeeChat.UI.Resources.Strings.Contacts.BUTTON); + $('#' + BeeChat.UI.Resources.Elements.ID_SPAN_CONTACTS_BUTTON).attr('class', 'offline'); + $('.' + BeeChat.UI.Resources.StyleClasses.ChatBox.INPUT + '>textarea').attr('disabled', 'true'); + $('#' + BeeChat.UI.Resources.Elements.ID_DIV_CHATBOXES).children().hide(); + $('#' + BeeChat.UI.Resources.Elements.ID_DIV_SCROLLBOXES).find('ul').children() + .attr('class', BeeChat.UI.Resources.StyleClasses.LABEL + ' ' + BeeChat.UI.Resources.ReferenceTables.Styles.Availability.Left[BeeChat.Presence.Types.UNAVAILABLE.toUpperCase()]); + g_beechat_user = null; + BeeChat.UI.saveConnection(); + } + }, + + /** Function: saveConnection + * Save connection informations (non sensible data) in $_SESSION. + * + */ + saveConnection: function() + { + var conn = null; + + if (g_beechat_user != null) { + var userConn = g_beechat_user.getConnection(); + + conn = { + 'jid': userConn.jid, + 'sid': userConn.sid, + 'rid': userConn.rid, + 'attached': g_beechat_user.isAttached() + }; + } + var self = this; + + $.ajax({ + type: 'POST', + async: false, + url: self.addActionTokens('<?php echo $vars['url'] . "action/beechat/save_state"; ?>'), + data: { beechat_conn: JSON.stringify(conn) } + }); + + /* + $.cookie(BeeChat.UI.Resources.Cookies.FILENAME_CONN, null); + $.cookie(BeeChat.UI.Resources.Cookies.FILENAME_CONN, JSON.stringify(conn), {path: '/', domain: BeeChat.UI.Resources.Cookies.DOMAIN}); + */ + }, + + /** Function: loadConnection + * Check if a connection already exists. In the case that a connection exists, + * this function triggers the connection process. + * + */ + loadConnection: function() + { + var self = this; + $.ajax({ + type: 'GET', + async: false, + cache: false, + dataType: 'json', + url: self.addActionTokens('<?php echo $vars['url'] . "action/beechat/get_connection"; ?>'), + success: function(conn) { + if (conn != null) { + if (conn.attached) + BeeChat.UI.connect(); + else + BeeChat.UI.connect(conn); + } + }, + error: function() { + BeeChat.UI.connect(); + } + }); + + /* + var conn = JSON.parse($.cookie(BeeChat.UI.Resources.Cookies.FILENAME_CONN)); + + if (conn != null) { + if (conn.attached) + BeeChat.UI.connect(); + else + BeeChat.UI.connect(conn); + } else + BeeChat.UI.connect(); + */ + }, + + /** Function: saveState + * Save app state in $_SESSION + * + */ + saveState: function() + { + var self = this; + var currentAvailabilityClass = $('#' + BeeChat.UI.Resources.Elements.ID_SPAN_CURRENT_AVAILABILITY).attr('class'); + var currentAvailability = currentAvailabilityClass.substr(currentAvailabilityClass.lastIndexOf('_') + 1); + + var data = { + availability: currentAvailability, + contacts: g_beechat_roster_items, + chats: {}, + contacts_list: { + minimized: $('#' + BeeChat.UI.Resources.Elements.ID_DIV_CONTACTS).is(':hidden') + } + }; + + $('#' + BeeChat.UI.Resources.Elements.ID_DIV_CHATBOXES).children().each(function() { + var contactBareJid = $(this).attr('bareJid'); + //var contactBareJid = $(this).data('bareJid'); + var isroom = ($(this).attr('isroom') == 'true'); + if (isroom) + var roster = $(this).find('div').filter('[class=' + BeeChat.UI.Resources.StyleClasses.ChatBox.ROOMROSTER + ']'); + var html_content = $(this).children().filter('[bareJid="' + contactBareJid + '"]').html(); + data.chats[contactBareJid] = { + 'html_content': escape(html_content), + 'roster_content': isroom?escape(roster.html()):'', + 'isroom': $(this).attr('isroom'), + 'group_guid': (contactBareJid in g_beechat_rooms)?g_beechat_rooms[contactBareJid]:0, + 'minimized': $(this).is(':hidden'), + 'unread': BeeChat.UI.UnreadCountBox.getElm(contactBareJid).text() + }; + }); + + $.ajax({ + type: 'POST', + async: false, + url: self.addActionTokens('<?php echo $vars['url'] . "action/beechat/save_state"; ?>'), + data: { beechat_state: JSON.stringify(data) } + }); + }, + + /** Function: loadState + * Load app state from $_SESSION + * + */ + loadState: function() + { + var self = this; + $.ajax({ + type: 'GET', + async: true, + cache: false, + dataType: 'json', + url: self.addActionTokens('<?php echo $vars['url'] . "action/beechat/get_state"; ?>'), + error: function() { + alert('error getting state'); + }, + success: function(json) { + debugXMPP('loadState'); + BeeChat.UI.AvailabilitySwitcher.initialize(json.availability); + + if (!json.contacts_list.minimized) { + $('#' + BeeChat.UI.Resources.Elements.ID_DIV_CONTACTS).show(); + BeeChat.UI.ContactsList.showedStyle(); + } + + g_beechat_user.getRoster().setItems(json.contacts); + self.loadRosterItemsIcons(false); + self.loadRosterItemsStatuses(false); + g_beechat_roster_items = g_beechat_user.getRoster().getItems(); + BeeChat.UI.ContactsList.update(g_beechat_user.getRoster().getOnlineItems()) + g_beechat_user.setInitialized(true); + + var scrollBoxesElm = $('#' + BeeChat.UI.Resources.Elements.ID_DIV_SCROLLBOXES); + var scrollBoxElmToShow = null; + + // Load saved chats + for (var key in json.chats) { + var isroom = (json.chats[key].isroom == 'true'); + if (isroom) + BeeChat.UI.ScrollBoxes.addRoom(key); + else + BeeChat.UI.ScrollBoxes.add(key); + + var chatBoxElm = BeeChat.UI.ChatBoxes.getChatBoxElm(key); + debugXMPP("load chat " + key); + chatBoxElm.hide(); + + if (!json.chats[key].minimized) { + scrollBoxElmToShow = BeeChat.UI.ScrollBoxes.getScrollBoxElm(key); + } + + var chatBoxContentElm = chatBoxElm.children().filter('[bareJid="' + key + '"]'); + + chatBoxContentElm.append(unescape(json.chats[key].html_content)); + chatBoxContentElm.attr({scrollTop: chatBoxContentElm.attr('scrollHeight')}); + if (isroom) { + g_beechat_rooms[key] = json.chats[key].room_guid; + var rosterElm = chatBoxElm.find('div').filter('[class=' + BeeChat.UI.Resources.StyleClasses.ChatBox.ROOMROSTER + ']'); + rosterElm.append(unescape(json.chats[key].roster_content)); + } + + BeeChat.UI.UnreadCountBox.update(key, json.chats[key].unread); + } + if (scrollBoxElmToShow != null) + scrollBoxesElm.trigger('goto', scrollBoxesElm.find('ul').children().index(scrollBoxElmToShow)); + else + scrollBoxesElm.trigger('goto', 0); + + // g_beechat_user.sendPresenceAvailability(json.availability, ''); + BeeChat.UI.ScrollBoxes.isInitialized = true; + BeeChat.UI.ScrollBoxes.isOpened = true; + + for (var key in json.chats) { + if (json.chats[key].minimized) { + BeeChat.UI.ChatBoxes.getChatBoxElm(key).hide(); + BeeChat.UI.ScrollBoxes.unselect(key); + } + else { + BeeChat.UI.ChatBoxes.getChatBoxElm(key).show(); + BeeChat.UI.ScrollBoxes.select(key); + } + } + for (room_idx in g_user_rooms) { + var room = g_user_rooms[room_idx]; + var chatBox = BeeChat.UI.ChatBoxes.getChatBoxElm(room[0]); + if (chatBox.length == 0) { + g_beechat_user.joinRoom(room[0], room[1]) + } + } + + }, + error: function() { + BeeChat.UI.ContactsList.initialize(); + } + }); + }, + + /** Function: loadRosterItemsIcons + * + */ + loadRosterItemsIcons: function(is_async, cb) + { + var data = g_beechat_user.getRoster().getItemsUsernamesAsList(); + var self = this; + + $.ajax({ + type: 'POST', + url: self.addActionTokens('<?php echo $vars['url'] . "action/beechat/get_icons"; ?>'), + async: is_async, + cache: false, + data: {'beechat_roster_items_usernames': data}, + dataType: 'json', + success: function(json) { + g_beechat_user.getRoster().setIcons(json); + g_beechat_roster_items = g_beechat_user.getRoster().getItems(); + + BeeChat.UI.ContactsList.update(g_beechat_user.getRoster().getOnlineItems()) + if (cb) { + cb(); + } + } + }); + }, + + /** Function: loadRosterItemsStatuses + * + */ + loadRosterItemsStatuses: function(is_async, cb) + { + var data = g_beechat_user.getRoster().getItemsUsernamesAsList(); +//alert(data) + var self = this; + $.ajax({ + type: 'POST', + url: self.addActionTokens('<?php echo $vars['url'] . "action/beechat/get_statuses"; ?>'), + async: true, // force + cache: false, + data: {'beechat_roster_items_usernames': data}, + dataType: 'json', + success: function(json) { + g_beechat_user.getRoster().setStatuses(json); + g_beechat_roster_items = g_beechat_user.getRoster().getItems(); + BeeChat.UI.ContactsList.update(g_beechat_user.getRoster().getOnlineItems()) + if (cb) { + cb(); + } + } + }); + }, + + /** Function: onRosterUpdate + * Notified by core on a roster update + * + */ + onRosterUpdate: function(rosterItems) + { + g_beechat_roster_items = rosterItems; + //alert("get roster"); + if (!g_beechat_user.isInitialized()) { + //alert("load roster" + rosterItems.length); + BeeChat.UI.loadRosterItemsStatuses(true, + function() { BeeChat.UI.loadRosterItemsIcons(true, + function() {g_beechat_user.sendInitialPresence();}); }); + //BeeChat.UI.loadRosterItemsIcons(false); + //g_beechat_user.sendInitialPresence(); + } + }, + + /** Function: onChatMessage + * + */ + onChatMessage: function(data) + { + if ($(data.msg).find('body').length == 0) { + BeeChat.UI.ChatBoxes.updateChatState(data.contactBareJid, data.msg); + } + else { + BeeChat.UI.ChatBoxes.update(data.contactBareJid, BeeChat.UI.Utils.getContactName(data.contactBareJid), Strophe.getText($(data.msg).find('body')[0])); + } + } +}; + + +/** Class: BeeChat.UI.Resources.ReferenceTables + * An object container for all reference tables + * + */ +BeeChat.UI.Resources.ReferenceTables = { + Styles: { + Availability: { + Left: { + AVAILABLE: BeeChat.UI.Resources.StyleClasses.Availability.Left.ONLINE, + CHAT: BeeChat.UI.Resources.StyleClasses.Availability.Left.ONLINE, + DND: BeeChat.UI.Resources.StyleClasses.Availability.Left.DND, + AWAY: BeeChat.UI.Resources.StyleClasses.Availability.Left.AWAY, + XA: BeeChat.UI.Resources.StyleClasses.Availability.Left.XA, + UNAVAILABLE: BeeChat.UI.Resources.StyleClasses.Availability.Left.OFFLINE, + OFFLINE: BeeChat.UI.Resources.StyleClasses.Availability.Left.OFFLINE, + ROOM: BeeChat.UI.Resources.StyleClasses.Availability.Left.ROOM + }, + + Right: { + AVAILABLE: BeeChat.UI.Resources.StyleClasses.Availability.Right.ONLINE, + CHAT: BeeChat.UI.Resources.StyleClasses.Availability.Right.ONLINE, + DND: BeeChat.UI.Resources.StyleClasses.Availability.Right.DND, + AWAY: BeeChat.UI.Resources.StyleClasses.Availability.Right.AWAY, + XA: BeeChat.UI.Resources.StyleClasses.Availability.Right.XA, + UNAVAILABLE: BeeChat.UI.Resources.StyleClasses.Availability.Right.OFFLINE, + OFFLINE: BeeChat.UI.Resources.StyleClasses.Availability.Right.OFFLINE, + ROOM: BeeChat.UI.Resources.StyleClasses.Availability.Right.ROOM + } + } + } +}; + + +/** Class: BeeChat.UI.ContactsList + * An object container for all ContactsList functions + * + */ +BeeChat.UI.ContactsList = { + /** Function: initialize + * Initialize the contacts list by binding elements + * + */ + initialize: function() + { + $('#' + BeeChat.UI.Resources.Elements.ID_SPAN_CONTACTS_CONTROL_MINIMIZE).unbind('click').bind('click', BeeChat.UI.ContactsList.toggleDisplay); + $('#' + BeeChat.UI.Resources.Elements.ID_SPAN_CONTACTS_BUTTON).unbind('click').bind('click', function() { + if (g_beechat_user == null) + BeeChat.UI.connect(); + else + BeeChat.UI.ContactsList.toggleDisplay(); + }); + }, + + /** Function: update + * Update the contacts list content + * + * Parameters: + * (Object)(BeeChat.Core.RosterItem) onlineRosterItems - A hash of RosterItems in object notation + * + */ + update: function(onlineRosterItems) + { + var contactsListElm = $('#' + BeeChat.UI.Resources.Elements.ID_UL_CONTACTS_LIST); + + contactsListElm.children().each(function() { + var contactBareJid = $(this).attr('bareJid'); + + if (g_beechat_roster_items != null) { + if ($.inArray(contactBareJid, onlineRosterItems) == -1) { + BeeChat.UI.ScrollBoxes.updateAvailability(contactBareJid); + $(this).remove(); + } + } + }); + + for (var key in onlineRosterItems) { + if (typeof onlineRosterItems[key] != 'object') + continue; + + var contactElm = contactsListElm.find('li').filter('[bareJid="' + key + '"]'); + + if (contactElm.length == 0) { + contactElm = $('<li></li>') + .attr('bareJid', key) + .append($('<img />') + .attr('src', g_beechat_roster_items[key].icon_tiny)) + .append(BeeChat.UI.Utils.getTruncatedContactName(key, 25)) + .appendTo(contactsListElm) + .bind('click', function() { + if (!BeeChat.UI.ChatBoxes.getChatBoxElm($(this).attr('bareJid')).is(':visible')) { + BeeChat.UI.ContactsList.toggleDisplay(); + } + + BeeChat.UI.ScrollBoxes.add($(this).attr('bareJid'), false, true); + }); + } + + BeeChat.UI.ContactsList.updateContactAvailability(contactElm, key); + } + + BeeChat.UI.ContactsList.updateButtonText(BeeChat.UI.Resources.Strings.Contacts.BUTTON + ' (<strong>' + g_beechat_user.getRoster().getSizeOnlineItems() + '</strong>)'); + }, + + /** Function: updateContactAvailability + * + */ + updateContactAvailability: function(contactElm, contactBareJid) + { + // Update from contactsList + contactElm.attr('class', BeeChat.UI.Resources.ReferenceTables.Styles.Availability.Right[g_beechat_roster_items[contactBareJid].getStrongestPresence().show.toUpperCase()]); + + // Update from scrollBoxes + BeeChat.UI.ScrollBoxes.updateAvailability(contactBareJid); + }, + + /** Function: updateButtonText + * + * + */ + updateButtonText: function(msg) + { + $('#' + BeeChat.UI.Resources.Elements.ID_SPAN_CONTACTS_BUTTON).html(msg); + }, + + /** Function: toggleDisplay + * Toggle the contacts box display (hide | show) + * + */ + toggleDisplay: function() + { + var contactsBoxElm = $('#' + BeeChat.UI.Resources.Elements.ID_DIV_CONTACTS); + + contactsBoxElm.toggle(); + if (contactsBoxElm.is(':hidden')) { + BeeChat.UI.ContactsList.hiddenStyle(); + } else { + BeeChat.UI.ContactsList.showedStyle(); + } + $('#' + BeeChat.UI.Resources.Elements.ID_UL_AVAILABILITY_SWITCHER_LIST).hide(); + }, + + /** Function: hiddenStyle + * + */ + hiddenStyle: function() + { + $('#' + BeeChat.UI.Resources.Elements.ID_DIV_BAR_RIGHT).css({'border-left': '1px solid #BBBBBB', 'border-right': '1px solid #BBBBBB', 'background-color': '#DDDDDD'}); + }, + + /** Function: showedStyle + * + */ + showedStyle: function() + { + $('#' + BeeChat.UI.Resources.Elements.ID_DIV_BAR_RIGHT).css({'border-left': '1px solid #666666', 'border-right': '1px solid #666666', 'background-color': 'white'}); + } +}; + + +/** Class: BeeChat.UI.AvailabilitySwitcher + * An object container for all AvailabilitySwitcher functions + * + */ +BeeChat.UI.AvailabilitySwitcher = { + /** Function: initialize + * Initialize the availability switcher by setting the current user's availability + * and binding actions + * + */ + initialize: function(availability) + { + $('#' + BeeChat.UI.Resources.Elements.ID_SPAN_CURRENT_AVAILABILITY).unbind('click').bind('click', BeeChat.UI.AvailabilitySwitcher.toggleListDisplay); + + $('#' + BeeChat.UI.Resources.Elements.ID_SPAN_AVAILABILITY_SWITCHER_CONTROL).unbind('click').bind('click', BeeChat.UI.AvailabilitySwitcher.toggleListDisplay); + + $('#' + BeeChat.UI.Resources.Elements.ID_UL_AVAILABILITY_SWITCHER_LIST).find('li').each(function() { + $(this).unbind('click').bind('click', function() { + var availabilityClass = $(this).attr('class'); + var availability = availabilityClass.substr(availabilityClass.lastIndexOf('_') + 1); + + if (availability == 'offline') + BeeChat.UI.disconnect(); + else { + g_beechat_user.sendPresenceAvailability(availability, ''); + BeeChat.UI.AvailabilitySwitcher.update(availability); + $('#' + BeeChat.UI.Resources.Elements.ID_UL_AVAILABILITY_SWITCHER_LIST).hide('slow'); + $('#' + BeeChat.UI.Resources.Elements.ID_UL_CONTACTS_LIST).show('slow'); + } + }); + }); + BeeChat.UI.AvailabilitySwitcher.update(availability); + }, + + /** Function: update + * Update the current user's availability + * + * Parameters: + * (BeeChat.Presence.ShowElements) availability - The current user's availability + */ + update: function(availability) + { + var upperCasedAvailability = availability.toUpperCase(); + + $('#' + BeeChat.UI.Resources.Elements.ID_SPAN_CURRENT_AVAILABILITY) + .attr('class', BeeChat.UI.Resources.ReferenceTables.Styles.Availability.Left[upperCasedAvailability]) + .text(BeeChat.UI.Resources.Strings.Availability[upperCasedAvailability]); + + if (availability == 'chat') + $('#' + BeeChat.UI.Resources.Elements.ID_SPAN_CONTACTS_BUTTON).attr('class', 'online'); + else if (availability == 'xa' || availability == 'away') + $('#' + BeeChat.UI.Resources.Elements.ID_SPAN_CONTACTS_BUTTON).attr('class', 'away'); + else if (availability == 'dnd') + $('#' + BeeChat.UI.Resources.Elements.ID_SPAN_CONTACTS_BUTTON).attr('class', 'dnd'); + }, + + /** Function: switchControlClass + * + */ + switchControlClass: function() + { + var switcherControlElm = $('#' + BeeChat.UI.Resources.Elements.ID_SPAN_AVAILABILITY_SWITCHER_CONTROL); + + if (switcherControlElm.attr('class') == BeeChat.UI.Resources.StyleClasses.Availability.Control.UP) + switcherControlElm.attr('class', BeeChat.UI.Resources.StyleClasses.Availability.Control.DOWN); + else + switcherControlElm.attr('class', BeeChat.UI.Resources.StyleClasses.Availability.Control.UP); + }, + + /** Function: toggleListDisplay + * + */ + toggleListDisplay: function() + { + BeeChat.UI.AvailabilitySwitcher.switchControlClass(); + $('#' + BeeChat.UI.Resources.Elements.ID_UL_CONTACTS_LIST).toggle('slow'); + $('#' + BeeChat.UI.Resources.Elements.ID_UL_AVAILABILITY_SWITCHER_LIST).toggle('slow'); + } +}; + + +/** Class: BeeChat.UI.ScrollBoxes + * An object container for all ScrollBoxes related functions + * + */ +BeeChat.UI.ScrollBoxes = { + isInitialized: false, + isOpened: false, + + /** Function: initialize + * + */ + initialize: function() { + var $prev = $('#beechat_center_prev'), + $next = $('#beechat_center_next'); + + $('#' + BeeChat.UI.Resources.Elements.ID_DIV_BAR_CENTER).serialScroll({ + target: '#beechat_scrollboxes', + items: 'li', + prev: '#beechat_center_prev', + next: '#beechat_center_next', + axys: 'x', + start: 2, + step: -1, + interval: 0, + duration: 0, + cycle: false, + force: true, + jump: true, + lock: true, + lazy: true, + constant: true, + + onBefore: function(e, elem, $pane, $items, pos) { + $next.add($prev).hide(); + $prev.add($next).hide(); + if (pos != 0) { + $next.show(); + } + if (pos != $items.length - 1) + $prev.show(); + }, + + onAfter: function(elem) { + BeeChat.UI.ChatBoxes.takeStand($(elem).attr('bareJid')); + BeeChat.UI.ScrollBoxes.isInitialized = true; + } + }); + }, + + /** Function: add + * Add a scrollbox to the scrollboxes bar + * + */ + addRoom: function(contactBareJid) + { + debugXMPP('addRoom' + contactBareJid); + BeeChat.UI.ScrollBoxes.add(contactBareJid, true); + var scrollBoxElm = BeeChat.UI.ScrollBoxes.getScrollBoxElm(contactBareJid); + scrollBoxElm.attr('class', BeeChat.UI.Resources.StyleClasses.Availability.Left.ROOM); + }, + + add: function(contactBareJid, isroom) + { + var scrollBoxesElm = $('#' + BeeChat.UI.Resources.Elements.ID_DIV_SCROLLBOXES); + var scrollBoxElm = scrollBoxesElm.find('ul').children().filter('[bareJid="' + contactBareJid + '"]'); + debugXMPP("add " + contactBareJid + " " + scrollBoxElm.length); + if (scrollBoxElm.length == 0) { + var availClass = null; + var pres = null; + if (g_beechat_roster_items != undefined) + pres = g_beechat_roster_items[contactBareJid] != null ? g_beechat_roster_items[contactBareJid].getStrongestPresence() : null; + + if (pres != null) + availClass = BeeChat.UI.Resources.ReferenceTables.Styles.Availability.Left[pres.show.toUpperCase()]; + else + availClass = BeeChat.UI.Resources.ReferenceTables.Styles.Availability.Left[BeeChat.Presence.Types.UNAVAILABLE.toUpperCase()]; + + scrollBoxElm = $('<li></li>') + .attr('class', BeeChat.UI.Resources.StyleClasses.LABEL + ' ' + availClass) + .attr('bareJid', contactBareJid) + .attr('isroom', isroom?'true':'false') + .attr('title', BeeChat.UI.Resources.Strings.Box.SHOWHIDE) + .text(BeeChat.UI.Utils.getTruncatedContactName(contactBareJid, 11)) + .append($('<span></span>') + .attr('class', BeeChat.UI.Resources.StyleClasses.BOX_CONTROL) + .attr('id', BeeChat.UI.Resources.Elements.ID_SPAN_CLOSE_BOX) + .text('X') + .attr('title', BeeChat.UI.Resources.Strings.Box.CLOSE) + .bind('click', function() { + if (isroom) + g_beechat_user.leaveRoom(contactBareJid); + var scrollBoxesElm = $('#' + BeeChat.UI.Resources.Elements.ID_DIV_SCROLLBOXES); + + BeeChat.UI.ChatBoxes.remove($(this).parent().attr('bareJid')); + BeeChat.UI.UnreadCountBox.remove($(this).parent().attr('bareJid')); + scrollBoxesElm.trigger('goto', scrollBoxesElm.find('ul').children().index(BeeChat.UI.ScrollBoxes.getSelectedScrollBoxElm())); + BeeChat.UI.saveState(); + })); + + scrollBoxesElm.find('ul').append(scrollBoxElm); + BeeChat.UI.ChatBoxes.add(contactBareJid, isroom); + if (arguments.length == 3 && arguments[2]) + scrollBoxesElm.trigger('goto', scrollBoxesElm.find('ul').children().index(scrollBoxElm)); + if (!isroom) { + BeeChat.UI.loadRosterItemsStatuses(true, function () { BeeChat.UI.loadRosterItemsIcons(true); }); + } + } else { + scrollBoxesElm.trigger('goto', scrollBoxesElm.find('ul').children().index(scrollBoxElm)); + } + }, + + /** Function: remove + * + */ + remove: function(contactBareJid) + { + BeeChat.UI.ScrollBoxes.getScrollBoxElm(contactBareJid).remove(); + }, + + /** Function: unselect + * + */ + unselect: function(contactBareJid) + { + var scrollBoxElm = BeeChat.UI.ScrollBoxes.getScrollBoxElm(contactBareJid); + scrollBoxElm.attr('class', (scrollBoxElm.attr('class')).replace(/beechat_scrollbox_selected/, '')); + }, + + /** Function: select + * + */ + select: function(contactBareJid) + { + var scrollBoxElm = BeeChat.UI.ScrollBoxes.getScrollBoxElm(contactBareJid); + var scrollBoxElmClasses = scrollBoxElm.attr('class'); + + if (scrollBoxElmClasses.search(/beechat_scrollbox_selected/) == -1) + scrollBoxElm.attr('class', scrollBoxElmClasses + ' ' + BeeChat.UI.Resources.StyleClasses.ScrollBox.SELECTED); + }, + + /** Function: updateAvailability + * + */ + updateAvailability: function(contactBareJid) + { + var pres = g_beechat_roster_items[contactBareJid].getStrongestPresence(); + var scrollBoxElm = BeeChat.UI.ScrollBoxes.getScrollBoxElm(contactBareJid); + var scrollBoxElmClasses = scrollBoxElm.attr('class'); + var updatedAvailability = null; + + if (pres != null) + updatedAvailability = BeeChat.UI.Resources.ReferenceTables.Styles.Availability.Left[pres.show.toUpperCase()]; + else + updatedAvailability = BeeChat.UI.Resources.ReferenceTables.Styles.Availability.Left[BeeChat.Presence.Types.UNAVAILABLE.toUpperCase()]; + + if (scrollBoxElmClasses == undefined || scrollBoxElmClasses.search(/(beechat_left_availability_)/g) == -1) { + scrollBoxElm.attr('class', BeeChat.UI.Resources.StyleClasses.LABEL + ' ' + updatedAvailability); + } else { + updatedAvailability = updatedAvailability.replace(/(beechat_left_availability)/g, ''); + + scrollBoxElmClasses = scrollBoxElmClasses.replace(/(_chat)/g, updatedAvailability); + scrollBoxElmClasses = scrollBoxElmClasses.replace(/(_dnd)/g, updatedAvailability); + scrollBoxElmClasses = scrollBoxElmClasses.replace(/(_away)/g, updatedAvailability); + scrollBoxElmClasses = scrollBoxElmClasses.replace(/(_xa)/g, updatedAvailability); + scrollBoxElmClasses = scrollBoxElmClasses.replace(/(_offline)/g, updatedAvailability); + + scrollBoxElm.attr('class', scrollBoxElmClasses); + } + }, + + /** Function: getSelectedScrollBoxElm + * + */ + getSelectedScrollBoxElm: function(contactBareJid) + { + var elm = undefined; + + $('#' + BeeChat.UI.Resources.Elements.ID_DIV_SCROLLBOXES).find('ul').children().each(function() { + if ($(this).attr('class').search(/beechat_scrollbox_selected/) != -1) + elm = $(this); + }); + + return (elm); + }, + + /** Function: getScrollBoxElm + * + */ + getScrollBoxElm: function(contactBareJid) + { + return $('#' + BeeChat.UI.Resources.Elements.ID_DIV_SCROLLBOXES).find('ul').children().filter('[bareJid="' + contactBareJid + '"]'); + } +}; + + +/** Class: BeeChat.UI.ChatBoxes + * An object container for all ChatBoxes related functions + * + */ +BeeChat.UI.ChatBoxes = { + dateLastComposing: {}, + lastTimedPauses: {}, + + /** Function: add + * + */ + add: function(contactBareJid, isroom) + { + var chatBoxes = $('#' + BeeChat.UI.Resources.Elements.ID_DIV_CHATBOXES); + + if ($(chatBoxes).children().filter('[bareJid="' + contactBareJid + '"]').length == 0) { + debugXMPP("create chatbox " + contactBareJid); + var chatBox = $('<div></div>') + .attr('class', isroom ? BeeChat.UI.Resources.StyleClasses.ChatBox.MAIN : BeeChat.UI.Resources.StyleClasses.ChatBox.MAIN) + .attr('bareJid', contactBareJid) + .attr('isroom', isroom ? 'true' : 'false') + .hide(); + + var chatBoxTop = $('<div></div>') + .attr('class', BeeChat.UI.Resources.StyleClasses.ChatBox.TOP); + if (!isroom) + chatBoxTop.append($('<a></a>') + .attr('href', BeeChat.UI.Resources.Paths.MEMBER_PROFILE + Strophe.getNodeFromJid(contactBareJid)) + .append($('<img />') + .attr('class', BeeChat.UI.Resources.StyleClasses.ChatBox.TOP_ICON) + .attr('src', (g_beechat_roster_items != null && g_beechat_roster_items[contactBareJid] != undefined)?g_beechat_roster_items[contactBareJid].icon_small:''))) + chatBoxTop.append($('<span></span>') + .attr('class', BeeChat.UI.Resources.StyleClasses.LABEL) + .html(isroom?BeeChat.UI.Utils.getTruncatedContactName(contactBareJid).split('@')[0]:'<a href="' + BeeChat.UI.Resources.Paths.MEMBER_PROFILE + Strophe.getNodeFromJid(contactBareJid) + '">' + BeeChat.UI.Utils.getTruncatedContactName(contactBareJid) + '</a>')) + .append($('<div></div>') + .attr('class', BeeChat.UI.Resources.StyleClasses.ChatBox.TOP_CONTROLS) + .append($('<span></span>') + .attr('class', BeeChat.UI.Resources.StyleClasses.ChatBox.CONTROL) + .attr('id', BeeChat.UI.Resources.Elements.ID_SPAN_CLOSE_BOX) + .text('X') + .attr('title', BeeChat.UI.Resources.Strings.Box.CLOSE) + .bind('click', function() { + if (isroom) + g_beechat_user.leaveRoom(contactBareJid); + BeeChat.UI.ChatBoxes.remove(contactBareJid); + })) + .append($('<span></span>') + .attr('class', BeeChat.UI.Resources.StyleClasses.ChatBox.CONTROL) + .attr('id', BeeChat.UI.Resources.Elements.ID_SPAN_CLOSE_BOX) + .text('_') + .attr('title', BeeChat.UI.Resources.Strings.Box.MINIMIZE) + .css({'font-size': '1.6em', 'position': 'relative', 'line-height': '4px'}) + .bind('click', function() { + BeeChat.UI.ScrollBoxes.unselect($(this).parent().parent().parent().attr('bareJid')); + $(this).parent().parent().parent().fadeOut('slow'); + }))); + + var chatBoxSubTop = $('<div></div>') + .attr('class', BeeChat.UI.Resources.StyleClasses.ChatBox.SUBTOP) + .append(BeeChat.UI.Utils.getTruncatedContactStatus((g_beechat_roster_items != null && g_beechat_roster_items[contactBareJid] != undefined && g_beechat_roster_items[contactBareJid].status != undefined) ? g_beechat_roster_items[contactBareJid].status : '')); + + var chatBoxContent = $('<div></div>') + .attr('class', BeeChat.UI.Resources.StyleClasses.ChatBox.CONTENT) + .attr('bareJid', contactBareJid); + + var chatBoxInput = $('<div></div>') + .attr('class', BeeChat.UI.Resources.StyleClasses.ChatBox.INPUT) + .append($('<textarea></textarea>') + .attr('bareJid', contactBareJid) + .bind('keypress', isroom?BeeChat.UI.ChatBoxes.onRoomTypingMessage:BeeChat.UI.ChatBoxes.onTypingMessage) + .bind('keyup', function(e) { + if ((e.keyCode ? e.keyCode : e.which) == 13) + $(this).attr('value', ''); + })); + + var chatBoxBottom = $('<div></div>') + .attr('class', BeeChat.UI.Resources.StyleClasses.ChatBox.BOTTOM) + .append($('<span></span>') + .append($('<span></span>'))); + if (isroom) { + //var chatBoxBox = $('<div></div>') + // .attr('class', BeeChat.UI.Resources.StyleClasses.ChatBox.CHATROOM) + var chatBoxRoster = $('<div></div>') + .attr('class', BeeChat.UI.Resources.StyleClasses.ChatBox.ROOMROSTER) + //chatBoxBox.append(chatBoxTop).append(chatBoxSubTop).append(chatBoxContent).append(chatBoxInput).append(chatBoxBottom) + //chatBox.append(chatBoxRoster).append(chatBoxBox).appendTo(chatBoxes); + chatBox.append(chatBoxTop).append(chatBoxSubTop).append(chatBoxContent).append(chatBoxInput).append(chatBoxBottom).append(chatBoxRoster).appendTo(chatBoxes); + } + else + chatBox.append(chatBoxTop).append(chatBoxSubTop).append(chatBoxContent).append(chatBoxInput).append(chatBoxBottom).appendTo(chatBoxes); + } + else { + /*debugXMPP("show chatbox " + contactBareJid); + var chatBox = $(chatBoxes).children().filter('[bareJid="' + contactBareJid + '"]'); + chatBox.show();*/ + } + }, + + /** Function: takeStand + * + */ + takeStand: function(contactBareJid) + { + var chatBoxesElm = $('#' + BeeChat.UI.Resources.Elements.ID_DIV_CHATBOXES).children(); + var chatBoxElm = chatBoxesElm.filter('[bareJid="' + contactBareJid + '"]'); + var chatBoxContentElm = chatBoxElm.children().filter('[bareJid="' + contactBareJid + '"]'); + var scrollBoxesElm = $('#' + BeeChat.UI.Resources.Elements.ID_DIV_SCROLLBOXES); + var scrollBoxElm = BeeChat.UI.ScrollBoxes.getScrollBoxElm(contactBareJid); + + if (!chatBoxElm.is(':hidden')) { + BeeChat.UI.ScrollBoxes.unselect(contactBareJid); + chatBoxElm.hide(); + } else { + // Hide all other chatboxes + $.each(chatBoxesElm.filter('[bareJid!="' + contactBareJid + '"]'), function() { + BeeChat.UI.ScrollBoxes.unselect($(this).attr('bareJid')); + $(this).hide(); + }); + // Add selected scrollbox style + BeeChat.UI.ScrollBoxes.select(contactBareJid); + // Remove UnreadCountBox + BeeChat.UI.UnreadCountBox.remove(contactBareJid); + // Position the chatbox + var pos = scrollBoxElm.position().left - (chatBoxElm.width() - scrollBoxElm.width()) + 24; + chatBoxElm.css({'left': pos}); + if (!BeeChat.UI.ScrollBoxes.isOpened) + return; + chatBoxElm.show().css({'left': pos}); + // Scroll down the content of the chatbox + chatBoxContentElm.attr({scrollTop: chatBoxContentElm.attr('scrollHeight')}); + // Focus textarea + chatBoxElm.children().filter('[class=' + BeeChat.UI.Resources.StyleClasses.ChatBox.INPUT + ']').find('textarea').focus(); + } + }, + + /** Function: onTypingMessage + * + */ + onRoomTypingMessage: function(e) { + BeeChat.UI.ChatBoxes._onTypingMessage(e, true, this); + }, + + onTypingMessage: function(e) { + BeeChat.UI.ChatBoxes._onTypingMessage(e, false, this); + }, + + _onTypingMessage: function(e, isroom, self) + { + var keyCode = (e.keyCode) ? e.keyCode : e.which; + var contactBareJid = $(self).attr('bareJid'); + + var msgtype = BeeChat.Message.Types.CHAT; + if (isroom) + msgtype = BeeChat.Message.Types.GROUPCHAT; + + if (keyCode == 13 && $(self).val() != '') { + g_beechat_user.sendChatMessage(contactBareJid, jQuery.trim($(self).val()), msgtype); + if (!isroom) + BeeChat.UI.ChatBoxes.update(contactBareJid, BeeChat.UI.Utils.truncateString(BeeChat.UI.Resources.Strings.ChatMessages.SELF, 24), $(self).val(), isroom); + clearTimeout(BeeChat.UI.ChatBoxes.lastTimedPauses[contactBareJid]); + BeeChat.UI.ChatBoxes.lastTimedPauses[contactBareJid] = null; + } else { + var nowTime = new Date().getTime(); + + if (BeeChat.UI.ChatBoxes.dateLastComposing[contactBareJid] == null || BeeChat.UI.ChatBoxes.dateLastComposing[contactBareJid] + 2000 < nowTime) { + BeeChat.UI.ChatBoxes.dateLastComposing[contactBareJid] = nowTime; + g_beechat_user.sendChatStateMessage(contactBareJid, BeeChat.Message.ChatStates.COMPOSING); + } + + clearTimeout(BeeChat.UI.ChatBoxes.lastTimedPauses[contactBareJid]); + BeeChat.UI.ChatBoxes.lastTimedPauses[contactBareJid] = setTimeout('g_beechat_user.sendChatStateMessage(\'' + contactBareJid + '\', BeeChat.Message.ChatStates.PAUSED)', 2000); + + var chatBoxTextAreaElm = BeeChat.UI.ChatBoxes.getChatBoxElm(contactBareJid).children().filter('[class=' + BeeChat.UI.Resources.StyleClasses.ChatBox.INPUT + ']').find('textarea'); + chatBoxTextAreaElm.attr({scrollTop: chatBoxTextAreaElm.attr('scrollHeight')}); + } + }, + + updateRoster: function(contactBareJid, fromName, presence) + { + var availability = $(presence).attr('type'); + var item = $(presence).find('item'); + var chatBoxElm = BeeChat.UI.ChatBoxes.getChatBoxElm(contactBareJid); + + if (chatBoxElm.length == 0) { + BeeChat.UI.ScrollBoxes.add(contactBareJid); + //BeeChat.UI.ScrollBoxes.addRoom(contactBareJid); + chatBoxElm = BeeChat.UI.ChatBoxes.getChatBoxElm(contactBareJid); + } + + //var chatBoxContentElm = chatBoxElm.children().filter('[bareJid="' + contactBareJid + '"]'); + + var roster = chatBoxElm.find('div').filter('[class=' + BeeChat.UI.Resources.StyleClasses.ChatBox.ROOMROSTER + ']'); + if (availability == 'unavailable') { + roster.find('div').filter('[contactName='+fromName+']').remove(); + } + else { + var hasName = roster.find('div').filter('[contactName='+fromName+']'); + if (hasName.length == 0) { + roster.append($('<div>' + fromName + '</div>') + .attr('class', BeeChat.UI.Resources.StyleClasses.ChatBox.ROSTER_ITEM) + .attr('title', item.attr('affiliation') + '/' + item.attr('role')) + .attr('contactName', fromName)) + } + } + }, + + + /** Function: update + * + */ + update: function(contactBareJid, fromName, msg, isroom) + { + var chatBoxElm = BeeChat.UI.ChatBoxes.getChatBoxElm(contactBareJid); + debugXMPP(contactBareJid + " " + msg + " " + chatBoxElm.length); + if (chatBoxElm.length == 0) { + if (isroom) { + BeeChat.UI.ScrollBoxes.addRoom(contactBareJid); + BeeChat.UI.ChatBoxes.show(contactBareJid); + BeeChat.UI.ChatBoxes.takeStand(contactBareJid); + } + else { + BeeChat.UI.ScrollBoxes.add(contactBareJid,false,true); + // BeeChat.UI.ChatBoxes.show(contactBareJid); + BeeChat.UI.ChatBoxes.takeStand(contactBareJid); + } + chatBoxElm = BeeChat.UI.ChatBoxes.getChatBoxElm(contactBareJid); + } + + var chatBoxContentElm = chatBoxElm.children().filter('[bareJid="' + contactBareJid + '"]'); + + chatBoxContentElm.find('p').filter('[class=' + BeeChat.UI.Resources.StyleClasses.ChatBox.STATE + ']').remove(); + + var chatBoxLastMessageElm = $(chatBoxContentElm).find('div').filter('[class=' + BeeChat.UI.Resources.StyleClasses.ChatBox.MESSAGE + ']').filter(':last'); + + if (chatBoxLastMessageElm && chatBoxLastMessageElm.find('span').filter('[class=' + BeeChat.UI.Resources.StyleClasses.ChatBox.MESSAGE_SENDER + ']').text() == fromName) { + chatBoxLastMessageElm.append('<p>' + BeeChat.UI.Utils.getPrintableChatMessage(msg) + '</p>'); + } else { + chatBoxContentElm.append($('<div></div>') + .attr('class', BeeChat.UI.Resources.StyleClasses.ChatBox.MESSAGE) + .append($('<span></span>') + .attr('class', BeeChat.UI.Resources.StyleClasses.ChatBox.MESSAGE_SENDER) + .text(fromName)) + .append($('<span></span>') + .attr('class', BeeChat.UI.Resources.StyleClasses.ChatBox.MESSAGE_DATE) + .text(BeeChat.UI.Utils.getNowFormattedTime())) + .append('<p>' + BeeChat.UI.Utils.getPrintableChatMessage(msg) + '</p>')); + } + + chatBoxContentElm.attr({scrollTop: chatBoxContentElm.attr('scrollHeight')}); + + var scrollBoxesElm = $('#' + BeeChat.UI.Resources.Elements.ID_DIV_SCROLLBOXES); + var scrollBoxElm = BeeChat.UI.ScrollBoxes.getScrollBoxElm(contactBareJid); + + if (BeeChat.UI.ScrollBoxes.isInitialized == false) { + scrollBoxesElm.trigger('goto', scrollBoxesElm.find('ul').children().index(scrollBoxElm)); + } + + debugXMPP("about to update number!"); + if (chatBoxElm.is(':hidden')) { + debugXMPP("update number!"); + BeeChat.UI.UnreadCountBox.update(contactBareJid); +// if (BeeChat.UI.HAS_FOCUS) +// document.getElementById(BeeChat.UI.Resources.Sounds.NEW_MESSAGE).Play(); + } + +// if (!BeeChat.UI.HAS_FOCUS) +// document.getElementById(BeeChat.UI.Resources.Sounds.NEW_MESSAGE).Play(); + }, + + /** Function: updateChatState + * + */ + updateChatState: function(contactBareJid, msg) + { + var chatBoxContentElm = BeeChat.UI.ChatBoxes.getChatBoxElm(contactBareJid).children().filter('[bareJid="' + contactBareJid + '"]'); + + $(msg).children().each(function() { + if (this.tagName == BeeChat.Message.ChatStates.COMPOSING) { + if (chatBoxContentElm.find('p').filter('[class=' + BeeChat.UI.Resources.StyleClasses.ChatBox.STATE + ']').length == 0) { + $('<p></p>') + .attr('class', BeeChat.UI.Resources.StyleClasses.ChatBox.STATE) + .html(BeeChat.UI.Utils.getContactName(contactBareJid) + BeeChat.UI.Resources.Strings.ChatMessages.COMPOSING + "</br />") + .appendTo(chatBoxContentElm); + } + } else if (this.tagName == BeeChat.Message.ChatStates.PAUSED) { + chatBoxContentElm.find('p').filter('[class=' + BeeChat.UI.Resources.StyleClasses.ChatBox.STATE + ']').remove(); + } + }); + chatBoxContentElm.attr({scrollTop: chatBoxContentElm.attr('scrollHeight')}); + }, + + /** Function: remove + * + */ + remove: function(contactBareJid) + { + BeeChat.UI.ChatBoxes.getChatBoxElm(contactBareJid).remove(); + BeeChat.UI.ScrollBoxes.getScrollBoxElm(contactBareJid).remove(); + }, + + /** Function: show + * + */ + show: function(contactBareJid) + { + BeeChat.UI.ChatBoxes.getChatBoxElm(contactBareJid).show(); + }, + + /** Function: hide + * + */ + hide: function(contactBareJid) + { + BeeChat.UI.ChatBoxes.getChatBoxElm(contactBareJid).hide(); + }, + + /** Function: getChatBoxElm + * + */ + getChatBoxElm: function(contactBareJid) + { + return $('#' + BeeChat.UI.Resources.Elements.ID_DIV_CHATBOXES).children().filter('[bareJid="' + contactBareJid + '"]'); + } +}; + +BeeChat.UI.UnreadCountBox = { + /** Function: add + * + */ + add: function(contactBareJid) + { + BeeChat.UI.ScrollBoxes.getScrollBoxElm(contactBareJid) + .append($('<span></span>') + .attr('class', BeeChat.UI.Resources.StyleClasses.UNREAD_COUNT)); + }, + + /** Function: remove + * + */ + remove: function(contactBareJid) + { + BeeChat.UI.UnreadCountBox.getElm(contactBareJid).remove(); + }, + + /** Function: update + * + */ + update: function(contactBareJid) + { + if (arguments.length > 1 && !arguments[1]) + return; + + var unreadCountBoxElm = BeeChat.UI.UnreadCountBox.getElm(contactBareJid); + if (unreadCountBoxElm.length == 0) { + BeeChat.UI.UnreadCountBox.add(contactBareJid); + unreadCountBoxElm = BeeChat.UI.UnreadCountBox.getElm(contactBareJid); + } + if (arguments.length == 1) { + var unreadCount = unreadCountBoxElm.text(); + unreadCountBoxElm.text(++unreadCount); + } else + unreadCountBoxElm.text(arguments[1]); + }, + + /** Function: getElm + * + */ + getElm: function(contactBareJid) + { + return BeeChat.UI.ScrollBoxes.getScrollBoxElm(contactBareJid).find('span').filter('[class=' + BeeChat.UI.Resources.StyleClasses.UNREAD_COUNT +' ]'); + } +}; + +/** Class: BeeChat.UI.Utils + * An object container for all UI utilities functions + * + */ +BeeChat.UI.Utils = { + /** Function: getTruncatedContactName + * + */ + getTruncatedContactName: function(bareJid) + { + return (BeeChat.UI.Utils.truncateString(BeeChat.UI.Utils.getContactName(bareJid), (arguments.length == 2) ? arguments[1] : 21)); + }, + + /** Function: getTruncatedContactStatus + * + */ + getTruncatedContactStatus: function(contactStatus) + { + return (BeeChat.UI.Utils.truncateString(contactStatus, (arguments.length == 2 ? arguments[1] : 50))); + }, + + /** Function: getContactName + * + */ + getContactName: function(bareJid) + { + var contactName = bareJid; + + if (g_beechat_roster_items != null && g_beechat_roster_items[bareJid]) + contactName = g_beechat_roster_items[bareJid].name; + // no contact name so we show bareJid + if (!contactName || contactName == '') + contactName = bareJid; + + return (contactName); + }, + + /** Function: getPrintableChatMessage + * + */ + getPrintableChatMessage: function(msg) + { + var val = new String; + val = $('<div>' + msg + '</div>'); + msg = val.text(); + + msg = jQuery.trim(msg); + msg = BeeChat.UI.Utils.replaceLinks(msg); + msg = BeeChat.UI.Utils.replaceSmileys(msg); + + return msg; + }, + + /** Function: getNowFormattedTime + * + */ + getNowFormattedTime: function() + { + var date = new Date(); + + var hours = date.getHours(); + var minutes = date.getMinutes(); + var seconds = date.getSeconds(); + + if (hours < 10) + hours = '0' + hours; + if (minutes < 10) + minutes = '0' + minutes; + if (seconds < 10) + seconds = '0' + seconds; + return (hours + ':' + minutes + ':' + seconds); + }, + + + /** Function: replaceSmileys + * Replace smileys founded in a string to beautiful icons :) + * + * Parameters: + * (String) str - The string containing smileys + * + */ + replaceSmileys: function(str) + { + str = str.replace(/(;\))/gi, '<img src="' + BeeChat.UI.Resources.Paths.ICONS + BeeChat.UI.Resources.Emoticons.FILENAME_WINK + '" />'); + str = str.replace(/(:\))/gi, '<img src="' + BeeChat.UI.Resources.Paths.ICONS + BeeChat.UI.Resources.Emoticons.FILENAME_SMILE + '" />'); + str = str.replace(/(:\()/gi, '<img src="' + BeeChat.UI.Resources.Paths.ICONS + BeeChat.UI.Resources.Emoticons.FILENAME_UNHAPPY + '" />'); + str = str.replace(/(:D)/gi, '<img src="' + BeeChat.UI.Resources.Paths.ICONS + BeeChat.UI.Resources.Emoticons.FILENAME_GRIN + '" />'); + str = str.replace(/(:o)/gi, '<img src="' + BeeChat.UI.Resources.Paths.ICONS + BeeChat.UI.Resources.Emoticons.FILENAME_SURPRISED + '" />'); + str = str.replace(/(xD)/gi, '<img src="' + BeeChat.UI.Resources.Paths.ICONS + BeeChat.UI.Resources.Emoticons.FILENAME_EVILGRIN + '" />'); + str = str.replace(/(:p)/gi, '<img src="' + BeeChat.UI.Resources.Paths.ICONS + BeeChat.UI.Resources.Emoticons.FILENAME_TONGUE + '" />'); + + return (str); + }, + + /** Function: replaceLinks + * Transform links founded in a string to clickable links + * + * Parameters: + * (String) str - The string where will be replaced links + */ + replaceLinks: function(str) + { + var xpr = + /((ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?)/gi; + + return (str.replace(xpr, '<a href="$1" target="_blank">$1</a>')); + }, + + /** Function: truncateString + * Truncate a string at a specified length + * + * Parameters: + * (String) str - The string to truncate + * (int) len - The maximum length of str + */ + truncateString: function(str, len) + { + if (str != null && str.length > len) + return ((str.substr(0, len) + '...')); + return (str); + } +}; + + +/** Executed when the DOM is ready + * + */ +function init_beechat(ts, token) { + if (typeof document.body.style.maxHeight === "undefined") { // IE6 + return; + } + + BeeChat.UI.initialize(ts, token); +} + +/** Window resizing + * + */ +$(window).resize(function() { + if (typeof document.body.style.maxHeight === "undefined") { // IE6 + return; + } + + $('#' + BeeChat.UI.Resources.Elements.ID_DIV_CHATBOXES).children().each(function() { + var scrollBoxElm = BeeChat.UI.ScrollBoxes.getScrollBoxElm($(this).attr('bareJid')); + var pos = scrollBoxElm.position().left - ($(this).width() - scrollBoxElm.width()) + 24; + + $(this).css({'left': pos}); + }); +}); + + +/** Executed when the page is unloaded + * + */ +$(window).unload(function() { + if (typeof document.body.style.maxHeight === "undefined") { // IE6 + return; + } + + if (!$('#beechat').length) + return; + + if (g_beechat_user != null) { + g_beechat_user.requestSessionPause(); + BeeChat.UI.saveState(); + } + + BeeChat.UI.saveConnection(); + }); + + +/** Check whether the BeeChat tab is active or not + * + */ +$(window).bind('blur', function() { + BeeChat.UI.HAS_FOCUS = false; + }); + +$(window).bind('focus', function() { + BeeChat.UI.HAS_FOCUS = true; + }); diff --git a/mod/beechat/views/default/beechat/beechat.php b/mod/beechat/views/default/beechat/beechat.php new file mode 100644 index 000000000..397d35f74 --- /dev/null +++ b/mod/beechat/views/default/beechat/beechat.php @@ -0,0 +1,84 @@ +<?php + /** + * Beechat + * + * @package beechat + * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html GNU Public License version 2 + * @author Beechannels <contact@beechannels.com> + * @copyright Beechannels 2007-2010 + * @link http://beechannels.com/ + */ + +if (elgg_is_logged_in() && elgg_get_logged_in_user_entity()->chatenabled && elgg_get_context() != 'admin') { +?> +<div id="beechat"> + <div id="beechat_left"> + <a id="beechat_tooltip_trigger" href="<?php echo $vars['url']; ?>"><img src="<?php echo $vars['config']->wwwroot; ?>favicon.ico" /></a> + <div class="tooltip tooltipchat"> + <h3><?php echo elgg_echo('beechat:icons:home'); ?></h3> + </div> + </div> + <div id="beechat_center"> + <span id="beechat_center_prev" class="prev"></span> + <div id="beechat_scrollboxes"><ul></ul></div> + <span id="beechat_center_next" class="next"></span> + </div> + <div id="beechat_right"> + <span id="beechat_contacts_button" class="offline"> + <?php echo elgg_echo('beechat:contacts:button'); ?> + </span> + </div> + <div id="beechat_contacts"> + <div id="beechat_contacts_top"> + <span class="beechat_label"><?php echo elgg_echo('beechat:contacts:button'); ?></span> + <div id="beechat_contacts_controls"> + <span id="beechat_contacts_control_minimize" class="beechat_control" title="<?php echo elgg_echo('beechat:box:minimize'); ?>">_</span> + </div> + <br clear="all" /> + </div> + <div id="beechat_availability_switcher"> + <span id="beechat_current_availability"></span> + <span class="beechat_availability_switcher_control_down" id="beechat_availability_switcher_control"></span> + </div> + <div id="beechat_contacts_content"> + <ul id="beechat_contacts_list"></ul> + <ul id="beechat_availability_switcher_list"> + <li class="beechat_left_availability_chat"><?php echo elgg_echo('beechat:availability:available'); ?></li> + <li class="beechat_left_availability_dnd"><?php echo elgg_echo('beechat:availability:dnd'); ?></li> + <li class="beechat_left_availability_away"><?php echo elgg_echo('beechat:availability:away'); ?></li> + <li class="beechat_left_availability_xa"><?php echo elgg_echo('beechat:availability:xa'); ?></li> + <li class="beechat_left_availability_offline"><?php echo elgg_echo('beechat:availability:offline'); ?></li> + </ul> + </div> + <div id="beechat_contacts_bottom"> + <span id="beechat_contacts_bottom_bar"></span> + </div> + </div> + <div id="beechat_chatboxes"></div> +</div> +<!-- SOUNDS --> +<!-- +<embed src="<?php echo $vars['config']->staticurl; ?>mod/beechat/sounds/newmessage.wav" autostart=false width=0 height=0 + id="beechat_sounds_new_message" + enablejavascript="true" /> +--> + +<?php + $ts = time(); + $token = generate_action_token($ts); +?> + +<script> + $(function () { + var e = document.createElement('script'); + e.async = true; + e.type = 'text/javascript'; + e.text = 'init_beechat("<?php echo $ts; ?>","<?php echo $token; ?>");'; + document.getElementById('beechat').appendChild(e); + + }) +</script> + +<?php + } +?> diff --git a/mod/beechat/views/default/beechat/beechat.userjs.php b/mod/beechat/views/default/beechat/beechat.userjs.php new file mode 100644 index 000000000..ed59b683f --- /dev/null +++ b/mod/beechat/views/default/beechat/beechat.userjs.php @@ -0,0 +1,54 @@ +<script type="text/javascript"> +BeeChat.Events.Messages = { + ConnectionStates: { + CONNECTING: "<?php echo elgg_echo('beechat:connection:state:connecting'); ?>", + AUTHENTICATING: "<?php echo elgg_echo('beechat:connection:state:authenticating'); ?>", + FAILED: "<?php echo elgg_echo('beechat:connection:state:failed'); ?>", + DISCONNECTING: "<?php echo elgg_echo('beechat:connection:state:disconnecting'); ?>", + OFFLINE: "<?php echo elgg_echo('beechat:connection:state:offline'); ?>", + ONLINE: "<?php echo elgg_echo('beechat:connection:state:online'); ?>" + } + } + +BeeChat.UI.Resources.Strings = { + Availability: { + AVAILABLE: "<?php echo elgg_echo('beechat:availability:available'); ?>", + CHAT: "<?php echo elgg_echo('beechat:availability:available'); ?>", + ONLINE: "<?php echo elgg_echo('beechat:availability:available'); ?>", + DND: "<?php echo elgg_echo('beechat:availability:dnd'); ?>", + AWAY: "<?php echo elgg_echo('beechat:availability:away'); ?>", + XA:"<?php echo elgg_echo('beechat:availability:xa'); ?>", + OFFLINE: "<?php echo elgg_echo('beechat:availability:offline'); ?>" + }, + + Contacts: { + BUTTON: "<?php echo elgg_echo('beechat:contacts:button'); ?>" + }, + + ChatMessages: { + SELF: "<?php echo $_SESSION['user']->name; ?>", + COMPOSING: "<?php echo elgg_echo('beechat:chat:composing'); ?>" + }, + + Box: { + MINIMIZE: "<?php echo elgg_echo('beechat:box:minimize'); ?>", + CLOSE: "<?php echo elgg_echo('beechat:box:close'); ?>", + SHOWHIDE: "<?php echo elgg_echo('beechat:box:showhide'); ?>" + } + } +g_user_rooms = new Array(); +<?php +if (elgg_is_logged_in()) { + $user = elgg_get_logged_in_user_entity(); + $chatrooms = elgg_get_entities_from_relationship(array('relationship' => 'groupchat', + 'relationship_guid' => $user->guid, + 'inverse_relationship' => false, + 'limit' => 0)); + if (!empty($chatrooms)) { + foreach($chatrooms as $chatroom) { + echo "g_user_rooms.push(['".beechat_friendly_title($chatroom->name)."@".elgg_get_plugin_setting("groupdomain", "beechat")."', '".$chatroom->guid."']);"; + } + } +} +?> +</script> diff --git a/mod/beechat/views/default/beechat/screen.css.php b/mod/beechat/views/default/beechat/screen.css.php new file mode 100644 index 000000000..930e60089 --- /dev/null +++ b/mod/beechat/views/default/beechat/screen.css.php @@ -0,0 +1,672 @@ +<?php + global $CONFIG; + $url = $CONFIG->wwwroot; + +?> +/** + * Beechat + * + * @package beechat + * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html GNU Public License version 2 + * @author Beechannels <contact@beechannels.com> + * @copyright Beechannels 2007-2010 + * @link http://beechannels.com/ + */ + +div#beechat { + display: block !important; + display: none; + position: fixed; + left: 1%; + right: 1%; + bottom: 0; + margin: 0; + padding: 0; + height: 20px; + z-index: 999; + + font-family: Arial, Helvetica, "Liberation Sans", FreeSans, sans-serif; + font-size: 0.9em; + color: #222222; + background-color: #DDDDDD; + border-top: 1px solid #BBBBBB; + border-left: 1px solid #BBBBBB; +} +div#beechat a img { + border: none; +} +div#beechat a { + text-decoration: none; +} +div#beechat img { + vertical-align: middle; +} +div#beechat a:hover { + text-decoration: underline; +} +.beechat_control { + cursor: pointer; + color: #CCCCFF; + font-size: 1.6em; +} +.beechat_control:hover { + color: white; +} +.beechat_box_control { + cursor: pointer; + color: #888888; + font-size: 1em; +} +.beechat_box_control:hover { + color: #222222; +} +.beechat_chatbox_control { + cursor: pointer; + color: #CCCCFF; + font-size: 1.6em; +} +.beechat_chatbox_control:hover { + color: white; +} +.beechat_label { + font-weight: bold; + font-size: 1.1em; +} + +/* +** - +** left side +** - +*/ +div#beechat_left { + position: absolute; + top: 0; + left: 0; + width: 116px; + height: 18px; + margin: 0; + padding: 1px 2px; +} + + +/* +** - +** right side +** - +*/ +div#beechat_right { + position: absolute; + top: 0; + right: 0; + width: 220px; + height: 20px; + margin: 0; + padding: 0 0 0 0; + + border-left: 1px solid #BBBBBB; + border-right: 1px solid #BBBBBB; +} +div#beechat_contacts { + position: absolute; + right: 0px; + bottom: 0; + width: 222px; + height: 240px; + margin: 0 auto 20px auto; + padding: 0; + display: none; + + background-color: white; +} +div#beechat_contacts_top { + color: white; + background-color: #193C60; + width: 220px; + height: 32px; + + border-top: 1px solid #0B2C4F; + border-left: 1px solid #0B2C4F; + border-right: 1px solid #0B2C4F; +} +div#beechat_contacts_top .beechat_label { + float: left; + height: 20px; + padding: 6px; +} +div#beechat_contacts_controls { + margin: 0; + padding: 0; +} +div#beechat_contacts_controls span#beechat_contacts_control_minimize { + position: relative; + top: -7px; + float: right; + display: block; + width: 20px; + height: 20px; + padding: 2px; + + font-size: 1.6em; + font-weight: bold; + text-align: center; +} +span#beechat_contacts_button { + display: block; + width: 190px; + padding: 2px 6px 0 24px; + height: 18px; + cursor: pointer; + font-size: 1.1em; + font-weight: normal; + + background-image: url('<?php echo $url; ?>mod/beechat/graphics/icons/statuses.png'); +} +span#beechat_contacts_button.online { + background-position: 4px -750px; + background-repeat: no-repeat; +} +span#beechat_contacts_button.dnd { + background-position: 4px -796px; + background-repeat: no-repeat; +} +span#beechat_contacts_button.away { + background-position: 4px -842px; + background-repeat: no-repeat; +} +span#beechat_contacts_button.offline { + background-position: 4px -888px; + background-repeat: no-repeat; +} +span#beechat_contacts_button:hover { + background-color: white; +} +div#beechat_availability_switcher { + width: 218px; + height: 24px; + margin: 0; + padding: 0 0 0 2px; + + background-color: #EEEEEE; + border-left: 1px solid #666666; + border-right: 1px solid #666666; + border-bottom: 1px solid #BBBBBB; +} +span#beechat_current_availability { + float: left; + padding: 4px 4px 4px 22px; + + font-weight: bold; + cursor: pointer; +} +span#beechat_current_availability:hover { + text-decoration: underline; +} +span#beechat_availability_switcher_control { + float: right; + width: 24px; + height: 20px; + cursor: pointer; +} +span.beechat_availability_switcher_control_up { + background: no-repeat 50% 50% url('<?php echo $url; ?>mod/beechat/graphics/icons/bullet_arrow_up.png'); +} +span.beechat_availability_switcher_control_down { + background: no-repeat 50% 50% url('<?php echo $url; ?>mod/beechat/graphics/icons/bullet_arrow_down.png'); +} +ul#beechat_availability_switcher_list { + display: none; + padding:0; + margin:0; + list-style:none; +} +ul#beechat_availability_switcher_list li { + margin: 0; + padding: 4px 4px 4px 24px; + + cursor: pointer; +} +ul#beechat_availability_switcher_list li:hover { + background-color: #EEEEEE; +} +div#beechat_contacts_content { + width: 220px; + height: 164px; + overflow: auto; + + border-left: 1px solid #666666; + border-right: 1px solid #666666; + background-color: white; +} +ul#beechat_contacts_list { + background-color: white; + padding:0; + margin:0; + list-style:none; +} +ul#beechat_contacts_list li img { + margin: 0 4px 0 0; + width: 25px; + height: 25px; +} +ul#beechat_contacts_list li { + margin: 0; + padding: 4px 4px 4px 6px; + + cursor: pointer; + color: #333; +} +ul#beechat_contacts_list li:hover { + background-color: #F5F6F8; + color: #333; +} +div#beechat_contacts_bottom { + width: 220px; + height: 18px; + + border-left: 1px solid #666666; + border-right: 1px solid #666666; +} +span#beechat_contacts_bottom_bar { + position: absolute; + display: block; + bottom: 0; + width: 210px; + height: 1px; + + background-color: #BBBBBB; + margin: auto 4px; +} + + +/* +** - +** center area +** - +*/ +div#beechat_center { + float: right; + display: block; + width: 586px; + height: 20px; + margin: 0 220px 0 100px; + *margin: 0 312px 0 100px; + padding: 0; +} +div#beechat_center .next, div#beechat_center .prev { + display: none; + + border-left: 1px solid #BBBBBB; + cursor: pointer; +} +div#beechat_center .next { + position: absolute; + right: 220px; + width: 24px; + height: 20px; + + background: no-repeat 50% url("<?php echo $url; ?>mod/beechat/graphics/icons/resultset_next.png"); +} +div#beechat_center .prev { + position: absolute; + right: 872px; + width: 24px; + height: 20px; + + background: no-repeat 50% url("<?php echo $url; ?>mod/beechat/graphics/icons/resultset_previous.png"); +} +div#beechat_scrollboxes { + float: right; + overflow: hidden; + width: 628px; + height: 21px; + margin: 0 24px 0 24px; + text-align: left; +} +div#beechat_scrollboxes ul { + width: 200000em; + list-style: none; + padding:0; + margin:0; +} +div#beechat_scrollboxes ul li { + float: right; + display: block; + width: 130px; + height: 20px; + padding: 1px 0 0 22px; + + cursor: pointer; + border-left: 1px solid #BBBBBB; +} +div#beechat_scrollboxes ul li:hover { + color: #000000; + background-color: white; +} +div#beechat_scrollboxes ul li.beechat_scrollbox_selected { + border-left: 1px solid #666666; + border-right: 1px solid #666666; + background-color: white; +} +div#beechat_scrollboxes ul li span.beechat_unread_count { + float: right; + display: block; + width: 16px; + height: 14px; + padding-top: 2px; + margin: 0 6px 0 0; + + text-align: center; + font-size: 0.7em; + color: white; + background: no-repeat 0% 50% url('<?php echo $url; ?>mod/beechat/graphics/icons/notification_pink.png'); +} +div#beechat_scrollboxes ul li span#beechat_box_control_close { + float: right; + width: auto; + padding: 1px 4px; + height: 20px; +} + +/* +** -- +** availability classes +** -- +*/ +.beechat_left_availability_chat { + background: no-repeat 2% 50% url('<?php echo $url; ?>mod/beechat/graphics/icons/bullet_green.png'); +} +.beechat_left_availability_dnd { + background: no-repeat 2% 50% url('<?php echo $url; ?>mod/beechat/graphics/icons/bullet_delete.png'); +} +.beechat_left_availability_away { + background: no-repeat 2% 50% url('<?php echo $url; ?>mod/beechat/graphics/icons/bullet_orange.png'); +} +.beechat_left_availability_xa { + background: no-repeat 2% 50% url('<?php echo $url; ?>mod/beechat/graphics/icons/bullet_red.png'); +} +.beechat_left_availability_offline { + background: no-repeat 2% 50% url('<?php echo $url; ?>mod/beechat/graphics/icons/bullet_black.png'); +} +.beechat_left_availability_room { + background: no-repeat 2% 50% url('<?php echo $url; ?>mod/beechat/graphics/icons/muc_icon.png'); +} + + + +.beechat_right_availability_chat { + background: no-repeat 96% 50% url('<?php echo $url; ?>mod/beechat/graphics/icons/bullet_green.png'); +} +.beechat_right_availability_dnd { + background: no-repeat 96% 50% url('<?php echo $url; ?>mod/beechat/graphics/icons/bullet_delete.png'); +} +.beechat_right_availability_away { + background: no-repeat 96% 50% url('<?php echo $url; ?>mod/beechat/graphics/icons/bullet_orange.png'); +} +.beechat_right_availability_xa { + background: no-repeat 96% 50% url('<?php echo $url; ?>mod/beechat/graphics/icons/bullet_red.png'); +} +.beechat_right_availability_offline { + background: no-repeat 96% 50% url('<?php echo $url; ?>mod/beechat/graphics/icons/bullet_black.png'); +} +.beechat_right_availability_room { + background: no-repeat 96% 50% url('<?php echo $url; ?>mod/beechat/graphics/icons/muc_icon.png'); +} + +/* +** -- +** tooltips +** -- +*/ +div.tooltip.tooltipchat { + display: none; + padding: 4px; + width: auto; + background: transparent no-repeat left bottom url('<?php echo $url; ?>mod/beechat/graphics/icons/pointer.png'); +} +div.tooltip.tooltipchat h3 { + margin: 0; + padding: 4px; + + font-weight: normal; + font-size: 0.9em; + color: white; + background-color: #222222; +} + + +/* +** -- +** chatboxes +** -- +*/ +div.beechat_chatbox { + position: absolute; + width: 240px; + height: 300px; + bottom: 25px; + margin: 0; + padding: 0; + + background-color: #DDDDDD; +} +div.beechat_chatbox a { + color: white; +} +div.beechat_chatbox a:hover { + text-decoration: underline; +} +div.beechat_chatbox_roomroster { + position: absolute; + width: 100px; + height: 276px; + left: -101px; + bottom: -2px; + margin: 0; + padding: 0; + overflow: auto; + + border: 1px solid #4B6C8F; + + background-color: #EEEEEE; +} +div.beechat_chatbox_roomrosteritem { + background-color: #FFFFFF; + margin: 3px; + padding-left: 2px; +} +div.beechat_chatbox_chatroom { + position: absolute; + width: 240px; + height: 300px; + left: 100px; + bottom: 0px; + margin: 0; + padding: 0; + + background-color: #DDDDDD; +} +div.beechat_chatbox_chatroom a { + color: white; +} +div.beechat_chatbox_chatroom a:hover { + text-decoration: underline; +} + +div.beechat_chatbox_room { + position: absolute; + width: 340px; + height: 300px; + bottom: 25px; + margin: 0; + padding: 0; + + background-color: #DDDDDD; +} +div.beechat_chatbox_room a { + color: white; +} +div.beechat_chatbox_room a:hover { + text-decoration: underline; +} +div.beechat_chatbox_top { + width: 238px; + height: 24px; + margin: 0; + padding: 0; + + font-size: 0.9em; + color: white; + background-color: #193C60; + border-top: 1px solid #0B2C4F; + border-left: 1px solid #0B2C4F; + border-right: 1px solid #0B2C4F; +} +div.beechat_chatbox_top .beechat_chatbox_top_icon { + position: absolute; + top: 4px; + left: 4px; + z-index: 2; + + width: 50px; + height: 50px; +} +div.beechat_chatbox_top .beechat_label { + float: left; + height: 13px; + padding: 4px 6px 6px 6px; + + margin-left: 54px; +} +div.beechat_chatbox_top_controls { + margin: 0; + padding: 0; +} +div.beechat_chatbox_top_controls .beechat_chatbox_control { + float: right; + display: block; + width: 20px; + height: 19px; + padding: 2px; + margin: 0; + + font-size: 1.2em; + font-weight: bold; + text-align: center; +} +div.beechat_chatbox_subtop { + width: 172px; + height: 30px; + padding: 2px 6px 2px 60px; + + border-left: 1px solid #666666; + border-right: 1px solid #666666; + border-bottom: 1px solid #CCCCCC; + background-color: #DDDDDD; +} +div.beechat_chatbox_content { + width: 238px; + height: 202px; + margin: 0; + padding: 0; + overflow: auto; + + border-left: 1px solid #666666; + border-right: 1px solid #666666; + background-color: white; +} +div.beechat_chatbox_content div.beechat_chatbox_message { + width: auto; + height: auto; + margin: 0; + padding: 2px; + border-top: 1px solid #DDDDDD; +} +div.beechat_chatbox_message span.beechat_chatbox_message_sender { + position: relative; + top: 0; + left: 6px; + font-weight: bold; + font-size: 1em; +} +div.beechat_chatbox_message span.beechat_chatbox_message_date { + float: right; + margin: 0 6px 0 0; +} +div.beechat_chatbox_content a { + color: #003399; +} +div.beechat_chatbox_content a:hover { + text-decoration: underline; +} +div.beechat_chatbox_content p { + margin: 0; + padding: 2px 6px; +} +div.beechat_chatbox_content p.beechat_chatbox_state { + font-size: 1em; + color: #888888; +} +div.beechat_chatbox_input { + width: 238px; + height: 40px; + margin: 0; + padding: 0; + + border-top: 2px solid #BBBBBB; + border-left: 1px solid #666666; + border-right: 1px solid #666666; + background-color: #DDDDDD; +} +div.beechat_chatbox_input textarea { + width: 204px; + height: 32px; + max-width: 240px; + max-height: 40px; + padding: 4px 4px 4px 30px; + margin: auto; + overflow: hidden; + vertical-align: top; + resize: none; + + font-size: 1em; + font-family: Arial, Helvetica, "Liberation Sans", FreeSans, sans-serif; + outline: none; + border: none; + background: white no-repeat 4px 3px url('<?php echo $url; ?>mod/beechat/graphics/icons/chat_icon.png'); +} +div.beechat_chatbox_input textarea:focus { + outline: none; + border: none; + background-color: white; +} +div.beechat_chatbox_bottom { + position: absolute; + width: 238px; + height: 1px; + + background-color: white; + border-left: 1px solid #666666; + border-right: 1px solid #666666; + border-bottom: 1px solid #666666; + z-index: 2; +} +div.beechat_chatbox_bottom span { + position: absolute; + display: block; + right: 0; + top: 0; + width: 152px; + height: 1px; + + border-bottom: 1px solid white; +} +div.beechat_chatbox_bottom span span { + position: absolute; + display: block; + width: 146px; + height: 1px; + right: 4px; + top: 0; + + border-bottom: 1px solid #BBBBBB; +} diff --git a/mod/beechat/views/default/js/b64.js.php b/mod/beechat/views/default/js/b64.js.php new file mode 100644 index 000000000..201bdbd7c --- /dev/null +++ b/mod/beechat/views/default/js/b64.js.php @@ -0,0 +1,74 @@ +// This code was written by Tyler Akins and has been placed in the +// public domain. It would be nice if you left this header intact. +// Base64 code from Tyler Akins -- http://rumkin.com + +var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + +/** + * Encodes a string in base64 + * @param {String} input The string to encode in base64. + */ +function encode64(input) { + var output = ""; + var chr1, chr2, chr3; + var enc1, enc2, enc3, enc4; + var i = 0; + + do { + chr1 = input.charCodeAt(i++); + chr2 = input.charCodeAt(i++); + chr3 = input.charCodeAt(i++); + + enc1 = chr1 >> 2; + enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); + enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); + enc4 = chr3 & 63; + + if (isNaN(chr2)) { + enc3 = enc4 = 64; + } else if (isNaN(chr3)) { + enc4 = 64; + } + + output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) + + keyStr.charAt(enc3) + keyStr.charAt(enc4); + } while (i < input.length); + + return output; +} + +/** + * Decodes a base64 string. + * @param {String} input The string to decode. + */ +function decode64(input) { + var output = ""; + var chr1, chr2, chr3; + var enc1, enc2, enc3, enc4; + var i = 0; + + // remove all characters that are not A-Z, a-z, 0-9, +, /, or = + input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); + + do { + enc1 = keyStr.indexOf(input.charAt(i++)); + enc2 = keyStr.indexOf(input.charAt(i++)); + enc3 = keyStr.indexOf(input.charAt(i++)); + enc4 = keyStr.indexOf(input.charAt(i++)); + + chr1 = (enc1 << 2) | (enc2 >> 4); + chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); + chr3 = ((enc3 & 3) << 6) | enc4; + + output = output + String.fromCharCode(chr1); + + if (enc3 != 64) { + output = output + String.fromCharCode(chr2); + } + if (enc4 != 64) { + output = output + String.fromCharCode(chr3); + } + } while (i < input.length); + + return output; +} diff --git a/mod/beechat/views/default/js/jquery.cookie.min.js.php b/mod/beechat/views/default/js/jquery.cookie.min.js.php new file mode 100644 index 000000000..cb09af984 --- /dev/null +++ b/mod/beechat/views/default/js/jquery.cookie.min.js.php @@ -0,0 +1,10 @@ +/** + * Cookie plugin + * + * Copyright (c) 2006 Klaus Hartl (stilbuero.de) + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + * + */ +jQuery.cookie=function(name,value,options){if(typeof value!='undefined'){options=options||{};if(value===null){value='';options=$.extend({},options);options.expires=-1;}var expires='';if(options.expires&&(typeof options.expires=='number'||options.expires.toUTCString)){var date;if(typeof options.expires=='number'){date=new Date();date.setTime(date.getTime()+(options.expires*24*60*60*1000));}else{date=options.expires;}expires='; expires='+date.toUTCString();}var path=options.path?'; path='+(options.path):'';var domain=options.domain?'; domain='+(options.domain):'';var secure=options.secure?'; secure':'';document.cookie=[name,'=',encodeURIComponent(value),expires,path,domain,secure].join('');}else{var cookieValue=null;if(document.cookie&&document.cookie!=''){var cookies=document.cookie.split(';');for(var i=0;i<cookies.length;i++){var cookie=jQuery.trim(cookies[i]);if(cookie.substring(0,name.length+1)==(name+'=')){cookieValue=decodeURIComponent(cookie.substring(name.length+1));break;}}}return cookieValue;}};
\ No newline at end of file diff --git a/mod/beechat/views/default/js/jquery.localscroll-1.2.7-min.js.php b/mod/beechat/views/default/js/jquery.localscroll-1.2.7-min.js.php new file mode 100644 index 000000000..fa583a451 --- /dev/null +++ b/mod/beechat/views/default/js/jquery.localscroll-1.2.7-min.js.php @@ -0,0 +1,9 @@ +/** + * jQuery.LocalScroll - Animated scrolling navigation, using anchors. + * Copyright (c) 2007-2009 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com + * Dual licensed under MIT and GPL. + * Date: 3/11/2009 + * @author Ariel Flesler + * @version 1.2.7 + **/ +;(function($){var l=location.href.replace(/#.*/,'');var g=$.localScroll=function(a){$('body').localScroll(a)};g.defaults={duration:1e3,axis:'y',event:'click',stop:true,target:window,reset:true};g.hash=function(a){if(location.hash){a=$.extend({},g.defaults,a);a.hash=false;if(a.reset){var e=a.duration;delete a.duration;$(a.target).scrollTo(0,a);a.duration=e}i(0,location,a)}};$.fn.localScroll=function(b){b=$.extend({},g.defaults,b);return b.lazy?this.bind(b.event,function(a){var e=$([a.target,a.target.parentNode]).filter(d)[0];if(e)i(a,e,b)}):this.find('a,area').filter(d).bind(b.event,function(a){i(a,this,b)}).end().end();function d(){return!!this.href&&!!this.hash&&this.href.replace(this.hash,'')==l&&(!b.filter||$(this).is(b.filter))}};function i(a,e,b){var d=e.hash.slice(1),f=document.getElementById(d)||document.getElementsByName(d)[0];if(!f)return;if(a)a.preventDefault();var h=$(b.target);if(b.lock&&h.is(':animated')||b.onBefore&&b.onBefore.call(b,a,f,h)===false)return;if(b.stop)h.stop(true);if(b.hash){var j=f.id==d?'id':'name',k=$('<a> </a>').attr(j,d).css({position:'absolute',top:$(window).scrollTop(),left:$(window).scrollLeft()});f[j]='';$('body').prepend(k);location=e.hash;k.remove();f[j]=d}h.scrollTo(f,b).trigger('notify.serialScroll',[f])}})(jQuery);
\ No newline at end of file diff --git a/mod/beechat/views/default/js/jquery.scrollTo-min.js.php b/mod/beechat/views/default/js/jquery.scrollTo-min.js.php new file mode 100755 index 000000000..5e7877810 --- /dev/null +++ b/mod/beechat/views/default/js/jquery.scrollTo-min.js.php @@ -0,0 +1,11 @@ +/** + * jQuery.ScrollTo - Easy element scrolling using jQuery. + * Copyright (c) 2007-2009 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com + * Dual licensed under MIT and GPL. + * Date: 5/25/2009 + * @author Ariel Flesler + * @version 1.4.2 + * + * http://flesler.blogspot.com/2007/10/jqueryscrollto.html + */ +;(function(d){var k=d.scrollTo=function(a,i,e){d(window).scrollTo(a,i,e)};k.defaults={axis:'xy',duration:parseFloat(d.fn.jquery)>=1.3?0:1};k.window=function(a){return d(window)._scrollable()};d.fn._scrollable=function(){return this.map(function(){var a=this,i=!a.nodeName||d.inArray(a.nodeName.toLowerCase(),['iframe','#document','html','body'])!=-1;if(!i)return a;var e=(a.contentWindow||a).document||a.ownerDocument||a;return d.browser.safari||e.compatMode=='BackCompat'?e.body:e.documentElement})};d.fn.scrollTo=function(n,j,b){if(typeof j=='object'){b=j;j=0}if(typeof b=='function')b={onAfter:b};if(n=='max')n=9e9;b=d.extend({},k.defaults,b);j=j||b.speed||b.duration;b.queue=b.queue&&b.axis.length>1;if(b.queue)j/=2;b.offset=p(b.offset);b.over=p(b.over);return this._scrollable().each(function(){var q=this,r=d(q),f=n,s,g={},u=r.is('html,body');switch(typeof f){case'number':case'string':if(/^([+-]=)?\d+(\.\d+)?(px|%)?$/.test(f)){f=p(f);break}f=d(f,this);case'object':if(f.is||f.style)s=(f=d(f)).offset()}d.each(b.axis.split(''),function(a,i){var e=i=='x'?'Left':'Top',h=e.toLowerCase(),c='scroll'+e,l=q[c],m=k.max(q,i);if(s){g[c]=s[h]+(u?0:l-r.offset()[h]);if(b.margin){g[c]-=parseInt(f.css('margin'+e))||0;g[c]-=parseInt(f.css('border'+e+'Width'))||0}g[c]+=b.offset[h]||0;if(b.over[h])g[c]+=f[i=='x'?'width':'height']()*b.over[h]}else{var o=f[h];g[c]=o.slice&&o.slice(-1)=='%'?parseFloat(o)/100*m:o}if(/^\d+$/.test(g[c]))g[c]=g[c]<=0?0:Math.min(g[c],m);if(!a&&b.queue){if(l!=g[c])t(b.onAfterFirst);delete g[c]}});t(b.onAfter);function t(a){r.animate(g,j,b.easing,a&&function(){a.call(this,n,b)})}}).end()};k.max=function(a,i){var e=i=='x'?'Width':'Height',h='scroll'+e;if(!d(a).is('html,body'))return a[h]-d(a)[e.toLowerCase()]();var c='client'+e,l=a.ownerDocument.documentElement,m=a.ownerDocument.body;return Math.max(l[h],m[h])-Math.min(l[c],m[c])};function p(a){return typeof a=='object'?a:{top:a,left:a}}})(jQuery);
\ No newline at end of file diff --git a/mod/beechat/views/default/js/jquery.serialScroll-min.js.php b/mod/beechat/views/default/js/jquery.serialScroll-min.js.php new file mode 100755 index 000000000..d716124f9 --- /dev/null +++ b/mod/beechat/views/default/js/jquery.serialScroll-min.js.php @@ -0,0 +1,10 @@ +/* + * jQuery.SerialScroll - Animated scrolling of series + * Copyright (c) 2007-2009 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com + * Dual licensed under MIT and GPL. + * Date: 06/14/2009 + * @author Ariel Flesler + * @version 1.2.2 + * http://flesler.blogspot.com/2008/02/jqueryserialscroll.html + */ +;(function(a){var b=a.serialScroll=function(c){return a(window).serialScroll(c)};b.defaults={duration:1e3,axis:"x",event:"click",start:0,step:1,lock:!0,cycle:!0,constant:!0};a.fn.serialScroll=function(c){return this.each(function(){var t=a.extend({},b.defaults,c),s=t.event,i=t.step,r=t.lazy,e=t.target?this:document,u=a(t.target||this,e),p=u[0],m=t.items,h=t.start,g=t.interval,k=t.navigation,l;if(!r){m=d()}if(t.force){f({},h)}a(t.prev||[],e).bind(s,-i,q);a(t.next||[],e).bind(s,i,q);if(!p.ssbound){u.bind("prev.serialScroll",-i,q).bind("next.serialScroll",i,q).bind("goto.serialScroll",f)}if(g){u.bind("start.serialScroll",function(v){if(!g){o();g=!0;n()}}).bind("stop.serialScroll",function(){o();g=!1})}u.bind("notify.serialScroll",function(x,w){var v=j(w);if(v>-1){h=v}});p.ssbound=!0;if(t.jump){(r?u:d()).bind(s,function(v){f(v,j(v.target))})}if(k){k=a(k,e).bind(s,function(v){v.data=Math.round(d().length/k.length)*k.index(this);f(v,this)})}function q(v){v.data+=h;f(v,this)}function f(B,z){if(!isNaN(z)){B.data=z;z=p}var C=B.data,v,D=B.type,A=t.exclude?d().slice(0,-t.exclude):d(),y=A.length,w=A[C],x=t.duration;if(D){B.preventDefault()}if(g){o();l=setTimeout(n,t.interval)}if(!w){v=C<0?0:y-1;if(h!=v){C=v}else{if(!t.cycle){return}else{C=y-v-1}}w=A[C]}if(!w||t.lock&&u.is(":animated")||D&&t.onBefore&&t.onBefore(B,w,u,d(),C)===!1){return}if(t.stop){u.queue("fx",[]).stop()}if(t.constant){x=Math.abs(x/i*(h-C))}u.scrollTo(w,x,t).trigger("notify.serialScroll",[C])}function n(){u.trigger("next.serialScroll")}function o(){clearTimeout(l)}function d(){return a(m,p)}function j(w){if(!isNaN(w)){return w}var x=d(),v;while((v=x.index(w))==-1&&w!=p){w=w.parentNode}return v}})}})(jQuery);
\ No newline at end of file diff --git a/mod/beechat/views/default/js/jquery.tools.min.js.php b/mod/beechat/views/default/js/jquery.tools.min.js.php new file mode 100644 index 000000000..1574af45b --- /dev/null +++ b/mod/beechat/views/default/js/jquery.tools.min.js.php @@ -0,0 +1,49 @@ +/* + * jQuery Tools 1.2.2 - The missing UI library for the Web + * + * [tabs, tabs.slideshow, tooltip, tooltip.slide, tooltip.dynamic, scrollable, scrollable.autoscroll, scrollable.navigator, overlay] + * + * NO COPYRIGHTS OR LICENSES. DO WHAT YOU LIKE. + * + * http://flowplayer.org/tools/ + * + * File generated: Mon Jun 07 08:32:38 GMT 2010 + */ +(function(c){function p(d,a,b){var e=this,l=d.add(this),h=d.find(b.tabs),j=a.jquery?a:d.children(a),i;h.length||(h=d.children());j.length||(j=d.parent().find(a));j.length||(j=c(a));c.extend(this,{click:function(f,g){var k=h.eq(f);if(typeof f=="string"&&f.replace("#","")){k=h.filter("[href*="+f.replace("#","")+"]");f=Math.max(h.index(k),0)}if(b.rotate){var n=h.length-1;if(f<0)return e.click(n,g);if(f>n)return e.click(0,g)}if(!k.length){if(i>=0)return e;f=b.initialIndex;k=h.eq(f)}if(f===i)return e; +g=g||c.Event();g.type="onBeforeClick";l.trigger(g,[f]);if(!g.isDefaultPrevented()){o[b.effect].call(e,f,function(){g.type="onClick";l.trigger(g,[f])});i=f;h.removeClass(b.current);k.addClass(b.current);return e}},getConf:function(){return b},getTabs:function(){return h},getPanes:function(){return j},getCurrentPane:function(){return j.eq(i)},getCurrentTab:function(){return h.eq(i)},getIndex:function(){return i},next:function(){return e.click(i+1)},prev:function(){return e.click(i-1)}});c.each("onBeforeClick,onClick".split(","), +function(f,g){c.isFunction(b[g])&&c(e).bind(g,b[g]);e[g]=function(k){c(e).bind(g,k);return e}});if(b.history&&c.fn.history){c.tools.history.init(h);b.event="history"}h.each(function(f){c(this).bind(b.event,function(g){e.click(f,g);return g.preventDefault()})});j.find("a[href^=#]").click(function(f){e.click(c(this).attr("href"),f)});if(location.hash)e.click(location.hash);else if(b.initialIndex===0||b.initialIndex>0)e.click(b.initialIndex)}c.tools=c.tools||{version:"1.2.2"};c.tools.tabs={conf:{tabs:"a", +current:"current",onBeforeClick:null,onClick:null,effect:"default",initialIndex:0,event:"click",rotate:false,history:false},addEffect:function(d,a){o[d]=a}};var o={"default":function(d,a){this.getPanes().hide().eq(d).show();a.call()},fade:function(d,a){var b=this.getConf(),e=b.fadeOutSpeed,l=this.getPanes();e?l.fadeOut(e):l.hide();l.eq(d).fadeIn(b.fadeInSpeed,a)},slide:function(d,a){this.getPanes().slideUp(200);this.getPanes().eq(d).slideDown(400,a)},ajax:function(d,a){this.getPanes().eq(0).load(this.getTabs().eq(d).attr("href"), +a)}},m;c.tools.tabs.addEffect("horizontal",function(d,a){m||(m=this.getPanes().eq(0).width());this.getCurrentPane().animate({width:0},function(){c(this).hide()});this.getPanes().eq(d).animate({width:m},function(){c(this).show();a.call()})});c.fn.tabs=function(d,a){var b=this.data("tabs");if(b)return b;if(c.isFunction(a))a={onBeforeClick:a};a=c.extend({},c.tools.tabs.conf,a);this.each(function(){b=new p(c(this),d,a);c(this).data("tabs",b)});return a.api?b:this}})(jQuery); +(function(d){function r(g,a){function p(f){var e=d(f);return e.length<2?e:g.parent().find(f)}var c=this,j=g.add(this),b=g.data("tabs"),h,l,m,n=false,o=p(a.next).click(function(){b.next()}),k=p(a.prev).click(function(){b.prev()});d.extend(c,{getTabs:function(){return b},getConf:function(){return a},play:function(){if(!h){var f=d.Event("onBeforePlay");j.trigger(f);if(f.isDefaultPrevented())return c;n=false;h=setInterval(b.next,a.interval);j.trigger("onPlay");b.next()}},pause:function(){if(!h)return c; +var f=d.Event("onBeforePause");j.trigger(f);if(f.isDefaultPrevented())return c;h=clearInterval(h);m=clearInterval(m);j.trigger("onPause")},stop:function(){c.pause();n=true}});d.each("onBeforePlay,onPlay,onBeforePause,onPause".split(","),function(f,e){d.isFunction(a[e])&&c.bind(e,a[e]);c[e]=function(s){return c.bind(e,s)}});if(a.autopause){var t=b.getTabs().add(o).add(k).add(b.getPanes());t.hover(function(){c.pause();l=clearInterval(l)},function(){n||(l=setTimeout(c.play,a.interval))})}if(a.autoplay)m= +setTimeout(c.play,a.interval);else c.stop();a.clickable&&b.getPanes().click(function(){b.next()});if(!b.getConf().rotate){var i=a.disabledClass;b.getIndex()||k.addClass(i);b.onBeforeClick(function(f,e){if(e){k.removeClass(i);e==b.getTabs().length-1?o.addClass(i):o.removeClass(i)}else k.addClass(i)})}}var q;q=d.tools.tabs.slideshow={conf:{next:".forward",prev:".backward",disabledClass:"disabled",autoplay:false,autopause:true,interval:3E3,clickable:true,api:false}};d.fn.slideshow=function(g){var a= +this.data("slideshow");if(a)return a;g=d.extend({},q.conf,g);this.each(function(){a=new r(d(this),g);d(this).data("slideshow",a)});return g.api?a:this}})(jQuery); +(function(f){function p(a,b,c){var h=c.relative?a.position().top:a.offset().top,e=c.relative?a.position().left:a.offset().left,i=c.position[0];h-=b.outerHeight()-c.offset[0];e+=a.outerWidth()+c.offset[1];var j=b.outerHeight()+a.outerHeight();if(i=="center")h+=j/2;if(i=="bottom")h+=j;i=c.position[1];a=b.outerWidth()+a.outerWidth();if(i=="center")e-=a/2;if(i=="left")e-=a;return{top:h,left:e}}function t(a,b){var c=this,h=a.add(c),e,i=0,j=0,m=a.attr("title"),q=n[b.effect],k,r=a.is(":input"),u=r&&a.is(":checkbox, :radio, select, :button"), +s=a.attr("type"),l=b.events[s]||b.events[r?u?"widget":"input":"def"];if(!q)throw'Nonexistent effect "'+b.effect+'"';l=l.split(/,\s*/);if(l.length!=2)throw"Tooltip: bad events configuration for "+s;a.bind(l[0],function(d){if(b.predelay){clearTimeout(i);j=setTimeout(function(){c.show(d)},b.predelay)}else c.show(d)}).bind(l[1],function(d){if(b.delay){clearTimeout(j);i=setTimeout(function(){c.hide(d)},b.delay)}else c.hide(d)});if(m&&b.cancelDefault){a.removeAttr("title");a.data("title",m)}f.extend(c, +{show:function(d){if(!e){if(m)e=f(b.layout).addClass(b.tipClass).appendTo(document.body).hide().append(m);else if(b.tip)e=f(b.tip).eq(0);else{e=a.next();e.length||(e=a.parent().next())}if(!e.length)throw"Cannot find tooltip for "+a;}if(c.isShown())return c;e.stop(true,true);var g=p(a,e,b);d=d||f.Event();d.type="onBeforeShow";h.trigger(d,[g]);if(d.isDefaultPrevented())return c;g=p(a,e,b);e.css({position:"absolute",top:g.top,left:g.left});k=true;q[0].call(c,function(){d.type="onShow";k="full";h.trigger(d)}); +g=b.events.tooltip.split(/,\s*/);e.bind(g[0],function(){clearTimeout(i);clearTimeout(j)});g[1]&&!a.is("input:not(:checkbox, :radio), textarea")&&e.bind(g[1],function(o){o.relatedTarget!=a[0]&&a.trigger(l[1].split(" ")[0])});return c},hide:function(d){if(!e||!c.isShown())return c;d=d||f.Event();d.type="onBeforeHide";h.trigger(d);if(!d.isDefaultPrevented()){k=false;n[b.effect][1].call(c,function(){d.type="onHide";k=false;h.trigger(d)});return c}},isShown:function(d){return d?k=="full":k},getConf:function(){return b}, +getTip:function(){return e},getTrigger:function(){return a}});f.each("onHide,onBeforeShow,onShow,onBeforeHide".split(","),function(d,g){f.isFunction(b[g])&&f(c).bind(g,b[g]);c[g]=function(o){f(c).bind(g,o);return c}})}f.tools=f.tools||{version:"1.2.2"};f.tools.tooltip={conf:{effect:"toggle",fadeOutSpeed:"fast",predelay:0,delay:30,opacity:1,tip:0,position:["top","center"],offset:[0,0],relative:false,cancelDefault:true,events:{def:"mouseenter,mouseleave",input:"focus,blur",widget:"focus mouseenter,blur mouseleave", +tooltip:"mouseenter,mouseleave"},layout:"<div/>",tipClass:"tooltip"},addEffect:function(a,b,c){n[a]=[b,c]}};var n={toggle:[function(a){var b=this.getConf(),c=this.getTip();b=b.opacity;b<1&&c.css({opacity:b});c.show();a.call()},function(a){this.getTip().hide();a.call()}],fade:[function(a){var b=this.getConf();this.getTip().fadeTo(b.fadeInSpeed,b.opacity,a)},function(a){this.getTip().fadeOut(this.getConf().fadeOutSpeed,a)}]};f.fn.tooltip=function(a){var b=this.data("tooltip");if(b)return b;a=f.extend(true, +{},f.tools.tooltip.conf,a);if(typeof a.position=="string")a.position=a.position.split(/,?\s/);this.each(function(){b=new t(f(this),a);f(this).data("tooltip",b)});return a.api?b:this}})(jQuery); +(function(d){var i=d.tools.tooltip;d.extend(i.conf,{direction:"up",bounce:false,slideOffset:10,slideInSpeed:200,slideOutSpeed:200,slideFade:!d.browser.msie});var e={up:["-","top"],down:["+","top"],left:["-","left"],right:["+","left"]};i.addEffect("slide",function(g){var a=this.getConf(),f=this.getTip(),b=a.slideFade?{opacity:a.opacity}:{},c=e[a.direction]||e.up;b[c[1]]=c[0]+"="+a.slideOffset;a.slideFade&&f.css({opacity:0});f.show().animate(b,a.slideInSpeed,g)},function(g){var a=this.getConf(),f=a.slideOffset, +b=a.slideFade?{opacity:0}:{},c=e[a.direction]||e.up,h=""+c[0];if(a.bounce)h=h=="+"?"-":"+";b[c[1]]=h+"="+f;this.getTip().animate(b,a.slideOutSpeed,function(){d(this).hide();g.call()})})})(jQuery); +(function(g){function j(a){var c=g(window),d=c.width()+c.scrollLeft(),h=c.height()+c.scrollTop();return[a.offset().top<=c.scrollTop(),d<=a.offset().left+a.width(),h<=a.offset().top+a.height(),c.scrollLeft()>=a.offset().left]}function k(a){for(var c=a.length;c--;)if(a[c])return false;return true}var i=g.tools.tooltip;i.dynamic={conf:{classNames:"top right bottom left"}};g.fn.dynamic=function(a){if(typeof a=="number")a={speed:a};a=g.extend({},i.dynamic.conf,a);var c=a.classNames.split(/\s/),d;this.each(function(){var h= +g(this).tooltip().onBeforeShow(function(e,f){e=this.getTip();var b=this.getConf();d||(d=[b.position[0],b.position[1],b.offset[0],b.offset[1],g.extend({},b)]);g.extend(b,d[4]);b.position=[d[0],d[1]];b.offset=[d[2],d[3]];e.css({visibility:"hidden",position:"absolute",top:f.top,left:f.left}).show();f=j(e);if(!k(f)){if(f[2]){g.extend(b,a.top);b.position[0]="top";e.addClass(c[0])}if(f[3]){g.extend(b,a.right);b.position[1]="right";e.addClass(c[1])}if(f[0]){g.extend(b,a.bottom);b.position[0]="bottom";e.addClass(c[2])}if(f[1]){g.extend(b, +a.left);b.position[1]="left";e.addClass(c[3])}if(f[0]||f[2])b.offset[0]*=-1;if(f[1]||f[3])b.offset[1]*=-1}e.css({visibility:"visible"}).hide()});h.onBeforeShow(function(){var e=this.getConf();this.getTip();setTimeout(function(){e.position=[d[0],d[1]];e.offset=[d[2],d[3]]},0)});h.onHide(function(){var e=this.getTip();e.removeClass(a.classNames)});ret=h});return a.api?ret:this}})(jQuery); +(function(e){function n(f,c){var a=e(c);return a.length<2?a:f.parent().find(c)}function t(f,c){var a=this,l=f.add(a),g=f.children(),k=0,m=c.vertical;j||(j=a);if(g.length>1)g=e(c.items,f);e.extend(a,{getConf:function(){return c},getIndex:function(){return k},getSize:function(){return a.getItems().size()},getNaviButtons:function(){return o.add(p)},getRoot:function(){return f},getItemWrap:function(){return g},getItems:function(){return g.children(c.item).not("."+c.clonedClass)},move:function(b,d){return a.seekTo(k+ +b,d)},next:function(b){return a.move(1,b)},prev:function(b){return a.move(-1,b)},begin:function(b){return a.seekTo(0,b)},end:function(b){return a.seekTo(a.getSize()-1,b)},focus:function(){return j=a},addItem:function(b){b=e(b);if(c.circular){e(".cloned:last").before(b);e(".cloned:first").replaceWith(b.clone().addClass(c.clonedClass))}else g.append(b);l.trigger("onAddItem",[b]);return a},seekTo:function(b,d,h){if(c.circular&&b===0&&k==-1&&d!==0)return a;if(!c.circular&&b<0||b>a.getSize()||b<-1)return a; +var i=b;if(b.jquery)b=a.getItems().index(b);else i=a.getItems().eq(b);var q=e.Event("onBeforeSeek");if(!h){l.trigger(q,[b,d]);if(q.isDefaultPrevented()||!i.length)return a}i=m?{top:-i.position().top}:{left:-i.position().left};k=b;j=a;if(d===undefined)d=c.speed;g.animate(i,d,c.easing,h||function(){l.trigger("onSeek",[b])});return a}});e.each(["onBeforeSeek","onSeek","onAddItem"],function(b,d){e.isFunction(c[d])&&e(a).bind(d,c[d]);a[d]=function(h){e(a).bind(d,h);return a}});if(c.circular){var r=a.getItems().slice(-1).clone().prependTo(g), +s=a.getItems().eq(1).clone().appendTo(g);r.add(s).addClass(c.clonedClass);a.onBeforeSeek(function(b,d,h){if(!b.isDefaultPrevented())if(d==-1){a.seekTo(r,h,function(){a.end(0)});return b.preventDefault()}else d==a.getSize()&&a.seekTo(s,h,function(){a.begin(0)})});a.seekTo(0,0)}var o=n(f,c.prev).click(function(){a.prev()}),p=n(f,c.next).click(function(){a.next()});!c.circular&&a.getSize()>1&&a.onBeforeSeek(function(b,d){o.toggleClass(c.disabledClass,d<=0);p.toggleClass(c.disabledClass,d>=a.getSize()- +1)});c.mousewheel&&e.fn.mousewheel&&f.mousewheel(function(b,d){if(c.mousewheel){a.move(d<0?1:-1,c.wheelSpeed||50);return false}});c.keyboard&&e(document).bind("keydown.scrollable",function(b){if(!(!c.keyboard||b.altKey||b.ctrlKey||e(b.target).is(":input")))if(!(c.keyboard!="static"&&j!=a)){var d=b.keyCode;if(m&&(d==38||d==40)){a.move(d==38?-1:1);return b.preventDefault()}if(!m&&(d==37||d==39)){a.move(d==37?-1:1);return b.preventDefault()}}});e(a).trigger("onBeforeSeek",[c.initialIndex])}e.tools=e.tools|| +{version:"1.2.2"};e.tools.scrollable={conf:{activeClass:"active",circular:false,clonedClass:"cloned",disabledClass:"disabled",easing:"swing",initialIndex:0,item:null,items:".items",keyboard:true,mousewheel:false,next:".next",prev:".prev",speed:400,vertical:false,wheelSpeed:0}};var j;e.fn.scrollable=function(f){var c=this.data("scrollable");if(c)return c;f=e.extend({},e.tools.scrollable.conf,f);this.each(function(){c=new t(e(this),f);e(this).data("scrollable",c)});return f.api?c:this}})(jQuery); +(function(c){var g=c.tools.scrollable;g.autoscroll={conf:{autoplay:true,interval:3E3,autopause:true}};c.fn.autoscroll=function(d){if(typeof d=="number")d={interval:d};var b=c.extend({},g.autoscroll.conf,d),h;this.each(function(){var a=c(this).data("scrollable");if(a)h=a;var e,i,f=true;a.play=function(){if(!e){f=false;e=setInterval(function(){a.next()},b.interval);a.next()}};a.pause=function(){e=clearInterval(e)};a.stop=function(){a.pause();f=true};b.autopause&&a.getRoot().add(a.getNaviButtons()).hover(function(){a.pause(); +clearInterval(i)},function(){f||(i=setTimeout(a.play,b.interval))});b.autoplay&&setTimeout(a.play,b.interval)});return b.api?h:this}})(jQuery); +(function(d){function p(c,g){var h=d(g);return h.length<2?h:c.parent().find(g)}var m=d.tools.scrollable;m.navigator={conf:{navi:".navi",naviItem:null,activeClass:"active",indexed:false,idPrefix:null,history:false}};d.fn.navigator=function(c){if(typeof c=="string")c={navi:c};c=d.extend({},m.navigator.conf,c);var g;this.each(function(){function h(a,b,i){e.seekTo(b);if(j){if(location.hash)location.hash=a.attr("href").replace("#","")}else return i.preventDefault()}function f(){return k.find(c.naviItem|| +"> *")}function n(a){var b=d("<"+(c.naviItem||"a")+"/>").click(function(i){h(d(this),a,i)}).attr("href","#"+a);a===0&&b.addClass(l);c.indexed&&b.text(a+1);c.idPrefix&&b.attr("id",c.idPrefix+a);return b.appendTo(k)}function o(a,b){a=f().eq(b.replace("#",""));a.length||(a=f().filter("[href="+b+"]"));a.click()}var e=d(this).data("scrollable"),k=p(e.getRoot(),c.navi),q=e.getNaviButtons(),l=c.activeClass,j=c.history&&d.fn.history;if(e)g=e;e.getNaviButtons=function(){return q.add(k)};f().length?f().each(function(a){d(this).click(function(b){h(d(this), +a,b)})}):d.each(e.getItems(),function(a){n(a)});e.onBeforeSeek(function(a,b){var i=f().eq(b);!a.isDefaultPrevented()&&i.length&&f().removeClass(l).eq(b).addClass(l)});e.onAddItem(function(a,b){b=n(e.getItems().index(b));j&&b.history(o)});j&&f().history(o)});return c.api?g:this}})(jQuery); +(function(a){function t(d,b){var c=this,i=d.add(c),o=a(window),k,f,m,g=a.tools.expose&&(b.mask||b.expose),n=Math.random().toString().slice(10);if(g){if(typeof g=="string")g={color:g};g.closeOnClick=g.closeOnEsc=false}var p=b.target||d.attr("rel");f=p?a(p):d;if(!f.length)throw"Could not find Overlay: "+p;d&&d.index(f)==-1&&d.click(function(e){c.load(e);return e.preventDefault()});a.extend(c,{load:function(e){if(c.isOpened())return c;var h=q[b.effect];if(!h)throw'Overlay: cannot find effect : "'+b.effect+ +'"';b.oneInstance&&a.each(s,function(){this.close(e)});e=e||a.Event();e.type="onBeforeLoad";i.trigger(e);if(e.isDefaultPrevented())return c;m=true;g&&a(f).expose(g);var j=b.top,r=b.left,u=f.outerWidth({margin:true}),v=f.outerHeight({margin:true});if(typeof j=="string")j=j=="center"?Math.max((o.height()-v)/2,0):parseInt(j,10)/100*o.height();if(r=="center")r=Math.max((o.width()-u)/2,0);h[0].call(c,{top:j,left:r},function(){if(m){e.type="onLoad";i.trigger(e)}});g&&b.closeOnClick&&a.mask.getMask().one("click", +c.close);b.closeOnClick&&a(document).bind("click."+n,function(l){a(l.target).parents(f).length||c.close(l)});b.closeOnEsc&&a(document).bind("keydown."+n,function(l){l.keyCode==27&&c.close(l)});return c},close:function(e){if(!c.isOpened())return c;e=e||a.Event();e.type="onBeforeClose";i.trigger(e);if(!e.isDefaultPrevented()){m=false;q[b.effect][1].call(c,function(){e.type="onClose";i.trigger(e)});a(document).unbind("click."+n).unbind("keydown."+n);g&&a.mask.close();return c}},getOverlay:function(){return f}, +getTrigger:function(){return d},getClosers:function(){return k},isOpened:function(){return m},getConf:function(){return b}});a.each("onBeforeLoad,onStart,onLoad,onBeforeClose,onClose".split(","),function(e,h){a.isFunction(b[h])&&a(c).bind(h,b[h]);c[h]=function(j){a(c).bind(h,j);return c}});k=f.find(b.close||".close");if(!k.length&&!b.close){k=a('<div class="close"></div>');f.prepend(k)}k.click(function(e){c.close(e)});b.load&&c.load()}a.tools=a.tools||{version:"1.2.2"};a.tools.overlay={addEffect:function(d, +b,c){q[d]=[b,c]},conf:{close:null,closeOnClick:true,closeOnEsc:true,closeSpeed:"fast",effect:"default",fixed:!a.browser.msie||a.browser.version>6,left:"center",load:false,mask:null,oneInstance:true,speed:"normal",target:null,top:"10%"}};var s=[],q={};a.tools.overlay.addEffect("default",function(d,b){var c=this.getConf(),i=a(window);if(!c.fixed){d.top+=i.scrollTop();d.left+=i.scrollLeft()}d.position=c.fixed?"fixed":"absolute";this.getOverlay().css(d).fadeIn(c.speed,b)},function(d){this.getOverlay().fadeOut(this.getConf().closeSpeed, +d)});a.fn.overlay=function(d){var b=this.data("overlay");if(b)return b;if(a.isFunction(d))d={onBeforeLoad:d};d=a.extend(true,{},a.tools.overlay.conf,d);this.each(function(){b=new t(a(this),d);s.push(b);a(this).data("overlay",b)});return d.api?b:this}})(jQuery); diff --git a/mod/beechat/views/default/js/json2.js.php b/mod/beechat/views/default/js/json2.js.php new file mode 100644 index 000000000..7ae503202 --- /dev/null +++ b/mod/beechat/views/default/js/json2.js.php @@ -0,0 +1,476 @@ +/* + http://www.JSON.org/json2.js + 2009-06-29 + + Public Domain. + + NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. + + See http://www.JSON.org/js.html + + This file creates a global JSON object containing two methods: stringify + and parse. + + JSON.stringify(value, replacer, space) + value any JavaScript value, usually an object or array. + + replacer an optional parameter that determines how object + values are stringified for objects. It can be a + function or an array of strings. + + space an optional parameter that specifies the indentation + of nested structures. If it is omitted, the text will + be packed without extra whitespace. If it is a number, + it will specify the number of spaces to indent at each + level. If it is a string (such as '\t' or ' '), + it contains the characters used to indent at each level. + + This method produces a JSON text from a JavaScript value. + + When an object value is found, if the object contains a toJSON + method, its toJSON method will be called and the result will be + stringified. A toJSON method does not serialize: it returns the + value represented by the name/value pair that should be serialized, + or undefined if nothing should be serialized. The toJSON method + will be passed the key associated with the value, and this will be + bound to the object holding the key. + + For example, this would serialize Dates as ISO strings. + + Date.prototype.toJSON = function (key) { + function f(n) { + // Format integers to have at least two digits. + return n < 10 ? '0' + n : n; + } + + return this.getUTCFullYear() + '-' + + f(this.getUTCMonth() + 1) + '-' + + f(this.getUTCDate()) + 'T' + + f(this.getUTCHours()) + ':' + + f(this.getUTCMinutes()) + ':' + + f(this.getUTCSeconds()) + 'Z'; + }; + + You can provide an optional replacer method. It will be passed the + key and value of each member, with this bound to the containing + object. The value that is returned from your method will be + serialized. If your method returns undefined, then the member will + be excluded from the serialization. + + If the replacer parameter is an array of strings, then it will be + used to select the members to be serialized. It filters the results + such that only members with keys listed in the replacer array are + stringified. + + Values that do not have JSON representations, such as undefined or + functions, will not be serialized. Such values in objects will be + dropped; in arrays they will be replaced with null. You can use + a replacer function to replace those with JSON values. + JSON.stringify(undefined) returns undefined. + + The optional space parameter produces a stringification of the + value that is filled with line breaks and indentation to make it + easier to read. + + If the space parameter is a non-empty string, then that string will + be used for indentation. If the space parameter is a number, then + the indentation will be that many spaces. + + Example: + + text = JSON.stringify(['e', {pluribus: 'unum'}]); + // text is '["e",{"pluribus":"unum"}]' + + + text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t'); + // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]' + + text = JSON.stringify([new Date()], function (key, value) { + return this[key] instanceof Date ? + 'Date(' + this[key] + ')' : value; + }); + // text is '["Date(---current time---)"]' + + + JSON.parse(text, reviver) + This method parses a JSON text to produce an object or array. + It can throw a SyntaxError exception. + + The optional reviver parameter is a function that can filter and + transform the results. It receives each of the keys and values, + and its return value is used instead of the original value. + If it returns what it received, then the structure is not modified. + If it returns undefined then the member is deleted. + + Example: + + // Parse the text. Values that look like ISO date strings will + // be converted to Date objects. + + myData = JSON.parse(text, function (key, value) { + var a; + if (typeof value === 'string') { + a = +/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value); + if (a) { + return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], + +a[5], +a[6])); + } + } + return value; + }); + + myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) { + var d; + if (typeof value === 'string' && + value.slice(0, 5) === 'Date(' && + value.slice(-1) === ')') { + d = new Date(value.slice(5, -1)); + if (d) { + return d; + } + } + return value; + }); + + + This is a reference implementation. You are free to copy, modify, or + redistribute. + + This code should be minified before deployment. + See http://javascript.crockford.com/jsmin.html + + USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO + NOT CONTROL. +*/ + +/*jslint evil: true */ + +/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply, + call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours, + getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join, + lastIndex, length, parse, prototype, push, replace, slice, stringify, + test, toJSON, toString, valueOf +*/ + +// Create a JSON object only if one does not already exist. We create the +// methods in a closure to avoid creating global variables. + +var JSON = JSON || {}; + +(function () { + + function f(n) { + // Format integers to have at least two digits. + return n < 10 ? '0' + n : n; + } + + if (typeof Date.prototype.toJSON !== 'function') { + + Date.prototype.toJSON = function (key) { + + return isFinite(this.valueOf()) ? + this.getUTCFullYear() + '-' + + f(this.getUTCMonth() + 1) + '-' + + f(this.getUTCDate()) + 'T' + + f(this.getUTCHours()) + ':' + + f(this.getUTCMinutes()) + ':' + + f(this.getUTCSeconds()) + 'Z' : null; + }; + + String.prototype.toJSON = + Number.prototype.toJSON = + Boolean.prototype.toJSON = function (key) { + return this.valueOf(); + }; + } + + var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, + escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, + gap, + indent, + meta = { // table of character substitutions + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + '"' : '\\"', + '\\': '\\\\' + }, + rep; + + + function quote(string) { + +// If the string contains no control characters, no quote characters, and no +// backslash characters, then we can safely slap some quotes around it. +// Otherwise we must also replace the offending characters with safe escape +// sequences. + + escapable.lastIndex = 0; + return escapable.test(string) ? + '"' + string.replace(escapable, function (a) { + var c = meta[a]; + return typeof c === 'string' ? c : + '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); + }) + '"' : + '"' + string + '"'; + } + + + function str(key, holder) { + +// Produce a string from holder[key]. + + var i, // The loop counter. + k, // The member key. + v, // The member value. + length, + mind = gap, + partial, + value = holder[key]; + +// If the value has a toJSON method, call it to obtain a replacement value. + + if (value && typeof value === 'object' && + typeof value.toJSON === 'function') { + value = value.toJSON(key); + } + +// If we were called with a replacer function, then call the replacer to +// obtain a replacement value. + + if (typeof rep === 'function') { + value = rep.call(holder, key, value); + } + +// What happens next depends on the value's type. + + switch (typeof value) { + case 'string': + return quote(value); + + case 'number': + +// JSON numbers must be finite. Encode non-finite numbers as null. + + return isFinite(value) ? String(value) : 'null'; + + case 'boolean': + case 'null': + +// If the value is a boolean or null, convert it to a string. Note: +// typeof null does not produce 'null'. The case is included here in +// the remote chance that this gets fixed someday. + + return String(value); + +// If the type is 'object', we might be dealing with an object or an array or +// null. + + case 'object': + +// Due to a specification blunder in ECMAScript, typeof null is 'object', +// so watch out for that case. + + if (!value) { + return 'null'; + } + +// Make an array to hold the partial results of stringifying this object value. + + gap += indent; + partial = []; + +// Is the value an array? + + if (Object.prototype.toString.apply(value) === '[object Array]') { + +// The value is an array. Stringify every element. Use null as a placeholder +// for non-JSON values. + + length = value.length; + for (i = 0; i < length; i += 1) { + partial[i] = str(i, value) || 'null'; + } + +// Join all of the elements together, separated with commas, and wrap them in +// brackets. + + v = partial.length === 0 ? '[]' : + gap ? '[\n' + gap + + partial.join(',\n' + gap) + '\n' + + mind + ']' : + '[' + partial.join(',') + ']'; + gap = mind; + return v; + } + +// If the replacer is an array, use it to select the members to be stringified. + + if (rep && typeof rep === 'object') { + length = rep.length; + for (i = 0; i < length; i += 1) { + k = rep[i]; + if (typeof k === 'string') { + v = str(k, value); + if (v) { + partial.push(quote(k) + (gap ? ': ' : ':') + v); + } + } + } + } else { + +// Otherwise, iterate through all of the keys in the object. + + for (k in value) { + if (Object.hasOwnProperty.call(value, k)) { + v = str(k, value); + if (v) { + partial.push(quote(k) + (gap ? ': ' : ':') + v); + } + } + } + } + +// Join all of the member texts together, separated with commas, +// and wrap them in braces. + + v = partial.length === 0 ? '{}' : + gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + + mind + '}' : '{' + partial.join(',') + '}'; + gap = mind; + return v; + } + } + +// If the JSON object does not yet have a stringify method, give it one. + + if (typeof JSON.stringify !== 'function') { + JSON.stringify = function (value, replacer, space) { + +// The stringify method takes a value and an optional replacer, and an optional +// space parameter, and returns a JSON text. The replacer can be a function +// that can replace values, or an array of strings that will select the keys. +// A default replacer method can be provided. Use of the space parameter can +// produce text that is more easily readable. + + var i; + gap = ''; + indent = ''; + +// If the space parameter is a number, make an indent string containing that +// many spaces. + + if (typeof space === 'number') { + for (i = 0; i < space; i += 1) { + indent += ' '; + } + +// If the space parameter is a string, it will be used as the indent string. + + } else if (typeof space === 'string') { + indent = space; + } + +// If there is a replacer, it must be a function or an array. +// Otherwise, throw an error. + + rep = replacer; + if (replacer && typeof replacer !== 'function' && + (typeof replacer !== 'object' || + typeof replacer.length !== 'number')) { + throw new Error('JSON.stringify'); + } + +// Make a fake root object containing our value under the key of ''. +// Return the result of stringifying the value. + + return str('', {'': value}); + }; + } + + +// If the JSON object does not yet have a parse method, give it one. + + if (typeof JSON.parse !== 'function') { + JSON.parse = function (text, reviver) { + +// The parse method takes a text and an optional reviver function, and returns +// a JavaScript value if the text is a valid JSON text. + + var j; + + function walk(holder, key) { + +// The walk method is used to recursively walk the resulting structure so +// that modifications can be made. + + var k, v, value = holder[key]; + if (value && typeof value === 'object') { + for (k in value) { + if (Object.hasOwnProperty.call(value, k)) { + v = walk(value, k); + if (v !== undefined) { + value[k] = v; + } else { + delete value[k]; + } + } + } + } + return reviver.call(holder, key, value); + } + + +// Parsing happens in four stages. In the first stage, we replace certain +// Unicode characters with escape sequences. JavaScript handles many characters +// incorrectly, either silently deleting them, or treating them as line endings. + + cx.lastIndex = 0; + if (cx.test(text)) { + text = text.replace(cx, function (a) { + return '\\u' + + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); + }); + } + +// In the second stage, we run the text against regular expressions that look +// for non-JSON patterns. We are especially concerned with '()' and 'new' +// because they can cause invocation, and '=' because it can cause mutation. +// But just to be safe, we want to reject all unexpected forms. + +// We split the second stage into 4 regexp operations in order to work around +// crippling inefficiencies in IE's and Safari's regexp engines. First we +// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we +// replace all simple value tokens with ']' characters. Third, we delete all +// open brackets that follow a colon or comma or that begin the text. Finally, +// we look to see that the remaining characters are only whitespace or ']' or +// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. + + if (/^[\],:{}\s]*$/. +test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@'). +replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']'). +replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { + +// In the third stage we use the eval function to compile the text into a +// JavaScript structure. The '{' operator is subject to a syntactic ambiguity +// in JavaScript: it can begin a block or an object literal. We wrap the text +// in parens to eliminate the ambiguity. + + j = eval('(' + text + ')'); + +// In the optional fourth stage, we recursively walk the new structure, passing +// each name/value pair to a reviver function for possible transformation. + + return typeof reviver === 'function' ? + walk({'': j}, '') : j; + } + +// If the text is not JSON parseable, then a SyntaxError is thrown. + + throw new SyntaxError('JSON.parse'); + }; + } +}()); diff --git a/mod/beechat/views/default/js/md5.js.php b/mod/beechat/views/default/js/md5.js.php new file mode 100644 index 000000000..4284f62bb --- /dev/null +++ b/mod/beechat/views/default/js/md5.js.php @@ -0,0 +1,261 @@ +/* + * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message + * Digest Algorithm, as defined in RFC 1321. + * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002. + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet + * Distributed under the BSD License + * See http://pajhome.org.uk/crypt/md5 for more info. + */ + +/* + * Configurable variables. You may need to tweak these to be compatible with + * the server-side, but the defaults work in most cases. + */ +var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */ +var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */ +var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */ + +/* + * These are the functions you'll usually want to call + * They take string arguments and return either hex or base-64 encoded strings + */ +function hex_md5(s){ return binl2hex(core_md5(str2binl(s), s.length * chrsz));} +function b64_md5(s){ return binl2b64(core_md5(str2binl(s), s.length * chrsz));} +function str_md5(s){ return binl2str(core_md5(str2binl(s), s.length * chrsz));} +function hex_hmac_md5(key, data) { return binl2hex(core_hmac_md5(key, data)); } +function b64_hmac_md5(key, data) { return binl2b64(core_hmac_md5(key, data)); } +function str_hmac_md5(key, data) { return binl2str(core_hmac_md5(key, data)); } + +/* + * Perform a simple self-test to see if the VM is working + */ +function md5_vm_test() +{ + return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72"; +} + +/* + * Calculate the MD5 of an array of little-endian words, and a bit length + */ +function core_md5(x, len) +{ + /* append padding */ + x[len >> 5] |= 0x80 << ((len) % 32); + x[(((len + 64) >>> 9) << 4) + 14] = len; + + var a = 1732584193; + var b = -271733879; + var c = -1732584194; + var d = 271733878; + + var olda, oldb, oldc, oldd; + for(var i = 0; i < x.length; i += 16) + { + olda = a; + oldb = b; + oldc = c; + oldd = d; + + a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936); + d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586); + c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819); + b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330); + a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897); + d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426); + c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341); + b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983); + a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416); + d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417); + c = md5_ff(c, d, a, b, x[i+10], 17, -42063); + b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162); + a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682); + d = md5_ff(d, a, b, c, x[i+13], 12, -40341101); + c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290); + b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329); + + a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510); + d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632); + c = md5_gg(c, d, a, b, x[i+11], 14, 643717713); + b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302); + a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691); + d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083); + c = md5_gg(c, d, a, b, x[i+15], 14, -660478335); + b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848); + a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438); + d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690); + c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961); + b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501); + a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467); + d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784); + c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473); + b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734); + + a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558); + d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463); + c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562); + b = md5_hh(b, c, d, a, x[i+14], 23, -35309556); + a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060); + d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353); + c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632); + b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640); + a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174); + d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222); + c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979); + b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189); + a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487); + d = md5_hh(d, a, b, c, x[i+12], 11, -421815835); + c = md5_hh(c, d, a, b, x[i+15], 16, 530742520); + b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651); + + a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844); + d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415); + c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905); + b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055); + a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571); + d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606); + c = md5_ii(c, d, a, b, x[i+10], 15, -1051523); + b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799); + a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359); + d = md5_ii(d, a, b, c, x[i+15], 10, -30611744); + c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380); + b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649); + a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070); + d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379); + c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259); + b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551); + + a = safe_add(a, olda); + b = safe_add(b, oldb); + c = safe_add(c, oldc); + d = safe_add(d, oldd); + } + return [a, b, c, d]; +} + +/* + * These functions implement the four basic operations the algorithm uses. + */ +function md5_cmn(q, a, b, x, s, t) +{ + return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b); +} +function md5_ff(a, b, c, d, x, s, t) +{ + return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t); +} +function md5_gg(a, b, c, d, x, s, t) +{ + return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t); +} +function md5_hh(a, b, c, d, x, s, t) +{ + return md5_cmn(b ^ c ^ d, a, b, x, s, t); +} +function md5_ii(a, b, c, d, x, s, t) +{ + return md5_cmn(c ^ (b | (~d)), a, b, x, s, t); +} + +/* + * Calculate the HMAC-MD5, of a key and some data + */ +function core_hmac_md5(key, data) +{ + var bkey = str2binl(key); + if(bkey.length > 16) { bkey = core_md5(bkey, key.length * chrsz); } + + var ipad = new Array(16), opad = new Array(16); + for(var i = 0; i < 16; i++) + { + ipad[i] = bkey[i] ^ 0x36363636; + opad[i] = bkey[i] ^ 0x5C5C5C5C; + } + + var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz); + return core_md5(opad.concat(hash), 512 + 128); +} + +/* + * Add integers, wrapping at 2^32. This uses 16-bit operations internally + * to work around bugs in some JS interpreters. + */ +function safe_add(x, y) +{ + var lsw = (x & 0xFFFF) + (y & 0xFFFF); + var msw = (x >> 16) + (y >> 16) + (lsw >> 16); + return (msw << 16) | (lsw & 0xFFFF); +} + +/* + * Bitwise rotate a 32-bit number to the left. + */ +function bit_rol(num, cnt) +{ + return (num << cnt) | (num >>> (32 - cnt)); +} + +/* + * Convert a string to an array of little-endian words + * If chrsz is ASCII, characters >255 have their hi-byte silently ignored. + */ +function str2binl(str) +{ + var bin = []; + var mask = (1 << chrsz) - 1; + for(var i = 0; i < str.length * chrsz; i += chrsz) + { + bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32); + } + return bin; +} + +/* + * Convert an array of little-endian words to a string + */ +function binl2str(bin) +{ + var str = ""; + var mask = (1 << chrsz) - 1; + for(var i = 0; i < bin.length * 32; i += chrsz) + { + str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask); + } + return str; +} + +/* + * Convert an array of little-endian words to a hex string. + */ +function binl2hex(binarray) +{ + var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; + var str = ""; + for(var i = 0; i < binarray.length * 4; i++) + { + str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) + + hex_tab.charAt((binarray[i>>2] >> ((i%4)*8 )) & 0xF); + } + return str; +} + +/* + * Convert an array of little-endian words to a base-64 string + */ +function binl2b64(binarray) +{ + var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + var str = ""; + var triplet, j; + for(var i = 0; i < binarray.length * 4; i += 3) + { + triplet = (((binarray[i >> 2] >> 8 * ( i %4)) & 0xFF) << 16) | + (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 ) | + ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF); + for(j = 0; j < 4; j++) + { + if(i * 8 + j * 6 > binarray.length * 32) { str += b64pad; } + else { str += tab.charAt((triplet >> 6*(3-j)) & 0x3F); } + } + } + return str; +} diff --git a/mod/beechat/views/default/js/sha1.js.php b/mod/beechat/views/default/js/sha1.js.php new file mode 100644 index 000000000..db3bf0544 --- /dev/null +++ b/mod/beechat/views/default/js/sha1.js.php @@ -0,0 +1,207 @@ +/* + * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined + * in FIPS PUB 180-1 + * Version 2.1a Copyright Paul Johnston 2000 - 2002. + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet + * Distributed under the BSD License + * See http://pajhome.org.uk/crypt/md5 for details. + */ + +/* + * Configurable variables. You may need to tweak these to be compatible with + * the server-side, but the defaults work in most cases. + */ +var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */ +var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */ +var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */ + +/* + * These are the functions you'll usually want to call + * They take string arguments and return either hex or base-64 encoded strings + */ +function hex_sha1(s){return binb2hex(core_sha1(str2binb(s),s.length * chrsz));} +function b64_sha1(s){return binb2b64(core_sha1(str2binb(s),s.length * chrsz));} +function str_sha1(s){return binb2str(core_sha1(str2binb(s),s.length * chrsz));} +function hex_hmac_sha1(key, data){ return binb2hex(core_hmac_sha1(key, data));} +function b64_hmac_sha1(key, data){ return binb2b64(core_hmac_sha1(key, data));} +function str_hmac_sha1(key, data){ return binb2str(core_hmac_sha1(key, data));} + +/* + * Perform a simple self-test to see if the VM is working + */ +function sha1_vm_test() +{ + return hex_sha1("abc") == "a9993e364706816aba3e25717850c26c9cd0d89d"; +} + +/* + * Calculate the SHA-1 of an array of big-endian words, and a bit length + */ +function core_sha1(x, len) +{ + /* append padding */ + x[len >> 5] |= 0x80 << (24 - len % 32); + x[((len + 64 >> 9) << 4) + 15] = len; + + var w = new Array(80); + var a = 1732584193; + var b = -271733879; + var c = -1732584194; + var d = 271733878; + var e = -1009589776; + + var i, j, t, olda, oldb, oldc, oldd, olde; + for (i = 0; i < x.length; i += 16) + { + olda = a; + oldb = b; + oldc = c; + oldd = d; + olde = e; + + for (j = 0; j < 80; j++) + { + if (j < 16) { w[j] = x[i + j]; } + else { w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1); } + t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)), + safe_add(safe_add(e, w[j]), sha1_kt(j))); + e = d; + d = c; + c = rol(b, 30); + b = a; + a = t; + } + + a = safe_add(a, olda); + b = safe_add(b, oldb); + c = safe_add(c, oldc); + d = safe_add(d, oldd); + e = safe_add(e, olde); + } + return [a, b, c, d, e]; +} + +/* + * Perform the appropriate triplet combination function for the current + * iteration + */ +function sha1_ft(t, b, c, d) +{ + if (t < 20) { return (b & c) | ((~b) & d); } + if (t < 40) { return b ^ c ^ d; } + if (t < 60) { return (b & c) | (b & d) | (c & d); } + return b ^ c ^ d; +} + +/* + * Determine the appropriate additive constant for the current iteration + */ +function sha1_kt(t) +{ + return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 : + (t < 60) ? -1894007588 : -899497514; +} + +/* + * Calculate the HMAC-SHA1 of a key and some data + */ +function core_hmac_sha1(key, data) +{ + var bkey = str2binb(key); + if (bkey.length > 16) { bkey = core_sha1(bkey, key.length * chrsz); } + + var ipad = new Array(16), opad = new Array(16); + for (var i = 0; i < 16; i++) + { + ipad[i] = bkey[i] ^ 0x36363636; + opad[i] = bkey[i] ^ 0x5C5C5C5C; + } + + var hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * chrsz); + return core_sha1(opad.concat(hash), 512 + 160); +} + +/* + * Add integers, wrapping at 2^32. This uses 16-bit operations internally + * to work around bugs in some JS interpreters. + */ +function safe_add(x, y) +{ + var lsw = (x & 0xFFFF) + (y & 0xFFFF); + var msw = (x >> 16) + (y >> 16) + (lsw >> 16); + return (msw << 16) | (lsw & 0xFFFF); +} + +/* + * Bitwise rotate a 32-bit number to the left. + */ +function rol(num, cnt) +{ + return (num << cnt) | (num >>> (32 - cnt)); +} + +/* + * Convert an 8-bit or 16-bit string to an array of big-endian words + * In 8-bit function, characters >255 have their hi-byte silently ignored. + */ +function str2binb(str) +{ + var bin = []; + var mask = (1 << chrsz) - 1; + for (var i = 0; i < str.length * chrsz; i += chrsz) + { + bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (32 - chrsz - i%32); + } + return bin; +} + +/* + * Convert an array of big-endian words to a string + */ +function binb2str(bin) +{ + var str = ""; + var mask = (1 << chrsz) - 1; + for (var i = 0; i < bin.length * 32; i += chrsz) + { + str += String.fromCharCode((bin[i>>5] >>> (32 - chrsz - i%32)) & mask); + } + return str; +} + +/* + * Convert an array of big-endian words to a hex string. + */ +function binb2hex(binarray) +{ + var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; + var str = ""; + for (var i = 0; i < binarray.length * 4; i++) + { + str += hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8+4)) & 0xF) + + hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8 )) & 0xF); + } + return str; +} + +/* + * Convert an array of big-endian words to a base-64 string + */ +function binb2b64(binarray) +{ + var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + var str = ""; + var triplet, j; + for (var i = 0; i < binarray.length * 4; i += 3) + { + triplet = (((binarray[i >> 2] >> 8 * (3 - i %4)) & 0xFF) << 16) | + (((binarray[i+1 >> 2] >> 8 * (3 - (i+1)%4)) & 0xFF) << 8 ) | + ((binarray[i+2 >> 2] >> 8 * (3 - (i+2)%4)) & 0xFF); + for (j = 0; j < 4; j++) + { + if (i * 8 + j * 6 > binarray.length * 32) { str += b64pad; } + else { str += tab.charAt((triplet >> 6*(3-j)) & 0x3F); } + } + } + return str; +} diff --git a/mod/beechat/views/default/js/strophe.min.js.php b/mod/beechat/views/default/js/strophe.min.js.php new file mode 100644 index 000000000..f0eb17906 --- /dev/null +++ b/mod/beechat/views/default/js/strophe.min.js.php @@ -0,0 +1 @@ +var Base64=(function(){var keyStr="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";var obj={encode:function(input){var output="";var chr1,chr2,chr3;var enc1,enc2,enc3,enc4;var i=0;do{chr1=input.charCodeAt(i++);chr2=input.charCodeAt(i++);chr3=input.charCodeAt(i++);enc1=chr1>>2;enc2=((chr1&3)<<4)|(chr2>>4);enc3=((chr2&15)<<2)|(chr3>>6);enc4=chr3&63;if(isNaN(chr2)){enc3=enc4=64}else{if(isNaN(chr3)){enc4=64}}output=output+keyStr.charAt(enc1)+keyStr.charAt(enc2)+keyStr.charAt(enc3)+keyStr.charAt(enc4)}while(i<input.length);return output},decode:function(input){var output="";var chr1,chr2,chr3;var enc1,enc2,enc3,enc4;var i=0;input=input.replace(/[^A-Za-z0-9\+\/\=]/g,"");do{enc1=keyStr.indexOf(input.charAt(i++));enc2=keyStr.indexOf(input.charAt(i++));enc3=keyStr.indexOf(input.charAt(i++));enc4=keyStr.indexOf(input.charAt(i++));chr1=(enc1<<2)|(enc2>>4);chr2=((enc2&15)<<4)|(enc3>>2);chr3=((enc3&3)<<6)|enc4;output=output+String.fromCharCode(chr1);if(enc3!=64){output=output+String.fromCharCode(chr2)}if(enc4!=64){output=output+String.fromCharCode(chr3)}}while(i<input.length);return output}};return obj})();var MD5=(function(){var hexcase=0;var b64pad="";var chrsz=8;var safe_add=function(x,y){var lsw=(x&65535)+(y&65535);var msw=(x>>16)+(y>>16)+(lsw>>16);return(msw<<16)|(lsw&65535)};var bit_rol=function(num,cnt){return(num<<cnt)|(num>>>(32-cnt))};var str2binl=function(str){var bin=[];var mask=(1<<chrsz)-1;for(var i=0;i<str.length*chrsz;i+=chrsz){bin[i>>5]|=(str.charCodeAt(i/chrsz)&mask)<<(i%32)}return bin};var binl2str=function(bin){var str="";var mask=(1<<chrsz)-1;for(var i=0;i<bin.length*32;i+=chrsz){str+=String.fromCharCode((bin[i>>5]>>>(i%32))&mask)}return str};var binl2hex=function(binarray){var hex_tab=hexcase?"0123456789ABCDEF":"0123456789abcdef";var str="";for(var i=0;i<binarray.length*4;i++){str+=hex_tab.charAt((binarray[i>>2]>>((i%4)*8+4))&15)+hex_tab.charAt((binarray[i>>2]>>((i%4)*8))&15)}return str};var binl2b64=function(binarray){var tab="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";var str="";var triplet,j;for(var i=0;i<binarray.length*4;i+=3){triplet=(((binarray[i>>2]>>8*(i%4))&255)<<16)|(((binarray[i+1>>2]>>8*((i+1)%4))&255)<<8)|((binarray[i+2>>2]>>8*((i+2)%4))&255);for(j=0;j<4;j++){if(i*8+j*6>binarray.length*32){str+=b64pad}else{str+=tab.charAt((triplet>>6*(3-j))&63)}}}return str};var md5_cmn=function(q,a,b,x,s,t){return safe_add(bit_rol(safe_add(safe_add(a,q),safe_add(x,t)),s),b)};var md5_ff=function(a,b,c,d,x,s,t){return md5_cmn((b&c)|((~b)&d),a,b,x,s,t)};var md5_gg=function(a,b,c,d,x,s,t){return md5_cmn((b&d)|(c&(~d)),a,b,x,s,t)};var md5_hh=function(a,b,c,d,x,s,t){return md5_cmn(b^c^d,a,b,x,s,t)};var md5_ii=function(a,b,c,d,x,s,t){return md5_cmn(c^(b|(~d)),a,b,x,s,t)};var core_md5=function(x,len){x[len>>5]|=128<<((len)%32);x[(((len+64)>>>9)<<4)+14]=len;var a=1732584193;var b=-271733879;var c=-1732584194;var d=271733878;var olda,oldb,oldc,oldd;for(var i=0;i<x.length;i+=16){olda=a;oldb=b;oldc=c;oldd=d;a=md5_ff(a,b,c,d,x[i+0],7,-680876936);d=md5_ff(d,a,b,c,x[i+1],12,-389564586);c=md5_ff(c,d,a,b,x[i+2],17,606105819);b=md5_ff(b,c,d,a,x[i+3],22,-1044525330);a=md5_ff(a,b,c,d,x[i+4],7,-176418897);d=md5_ff(d,a,b,c,x[i+5],12,1200080426);c=md5_ff(c,d,a,b,x[i+6],17,-1473231341);b=md5_ff(b,c,d,a,x[i+7],22,-45705983);a=md5_ff(a,b,c,d,x[i+8],7,1770035416);d=md5_ff(d,a,b,c,x[i+9],12,-1958414417);c=md5_ff(c,d,a,b,x[i+10],17,-42063);b=md5_ff(b,c,d,a,x[i+11],22,-1990404162);a=md5_ff(a,b,c,d,x[i+12],7,1804603682);d=md5_ff(d,a,b,c,x[i+13],12,-40341101);c=md5_ff(c,d,a,b,x[i+14],17,-1502002290);b=md5_ff(b,c,d,a,x[i+15],22,1236535329);a=md5_gg(a,b,c,d,x[i+1],5,-165796510);d=md5_gg(d,a,b,c,x[i+6],9,-1069501632);c=md5_gg(c,d,a,b,x[i+11],14,643717713);b=md5_gg(b,c,d,a,x[i+0],20,-373897302);a=md5_gg(a,b,c,d,x[i+5],5,-701558691);d=md5_gg(d,a,b,c,x[i+10],9,38016083);c=md5_gg(c,d,a,b,x[i+15],14,-660478335);b=md5_gg(b,c,d,a,x[i+4],20,-405537848);a=md5_gg(a,b,c,d,x[i+9],5,568446438);d=md5_gg(d,a,b,c,x[i+14],9,-1019803690);c=md5_gg(c,d,a,b,x[i+3],14,-187363961);b=md5_gg(b,c,d,a,x[i+8],20,1163531501);a=md5_gg(a,b,c,d,x[i+13],5,-1444681467);d=md5_gg(d,a,b,c,x[i+2],9,-51403784);c=md5_gg(c,d,a,b,x[i+7],14,1735328473);b=md5_gg(b,c,d,a,x[i+12],20,-1926607734);a=md5_hh(a,b,c,d,x[i+5],4,-378558);d=md5_hh(d,a,b,c,x[i+8],11,-2022574463);c=md5_hh(c,d,a,b,x[i+11],16,1839030562);b=md5_hh(b,c,d,a,x[i+14],23,-35309556);a=md5_hh(a,b,c,d,x[i+1],4,-1530992060);d=md5_hh(d,a,b,c,x[i+4],11,1272893353);c=md5_hh(c,d,a,b,x[i+7],16,-155497632);b=md5_hh(b,c,d,a,x[i+10],23,-1094730640);a=md5_hh(a,b,c,d,x[i+13],4,681279174);d=md5_hh(d,a,b,c,x[i+0],11,-358537222);c=md5_hh(c,d,a,b,x[i+3],16,-722521979);b=md5_hh(b,c,d,a,x[i+6],23,76029189);a=md5_hh(a,b,c,d,x[i+9],4,-640364487);d=md5_hh(d,a,b,c,x[i+12],11,-421815835);c=md5_hh(c,d,a,b,x[i+15],16,530742520);b=md5_hh(b,c,d,a,x[i+2],23,-995338651);a=md5_ii(a,b,c,d,x[i+0],6,-198630844);d=md5_ii(d,a,b,c,x[i+7],10,1126891415);c=md5_ii(c,d,a,b,x[i+14],15,-1416354905);b=md5_ii(b,c,d,a,x[i+5],21,-57434055);a=md5_ii(a,b,c,d,x[i+12],6,1700485571);d=md5_ii(d,a,b,c,x[i+3],10,-1894986606);c=md5_ii(c,d,a,b,x[i+10],15,-1051523);b=md5_ii(b,c,d,a,x[i+1],21,-2054922799);a=md5_ii(a,b,c,d,x[i+8],6,1873313359);d=md5_ii(d,a,b,c,x[i+15],10,-30611744);c=md5_ii(c,d,a,b,x[i+6],15,-1560198380);b=md5_ii(b,c,d,a,x[i+13],21,1309151649);a=md5_ii(a,b,c,d,x[i+4],6,-145523070);d=md5_ii(d,a,b,c,x[i+11],10,-1120210379);c=md5_ii(c,d,a,b,x[i+2],15,718787259);b=md5_ii(b,c,d,a,x[i+9],21,-343485551);a=safe_add(a,olda);b=safe_add(b,oldb);c=safe_add(c,oldc);d=safe_add(d,oldd)}return[a,b,c,d]};var core_hmac_md5=function(key,data){var bkey=str2binl(key);if(bkey.length>16){bkey=core_md5(bkey,key.length*chrsz)}var ipad=new Array(16),opad=new Array(16);for(var i=0;i<16;i++){ipad[i]=bkey[i]^909522486;opad[i]=bkey[i]^1549556828}var hash=core_md5(ipad.concat(str2binl(data)),512+data.length*chrsz);return core_md5(opad.concat(hash),512+128)};var obj={hexdigest:function(s){return binl2hex(core_md5(str2binl(s),s.length*chrsz))},b64digest:function(s){return binl2b64(core_md5(str2binl(s),s.length*chrsz))},hash:function(s){return binl2str(core_md5(str2binl(s),s.length*chrsz))},hmac_hexdigest:function(key,data){return binl2hex(core_hmac_md5(key,data))},hmac_b64digest:function(key,data){return binl2b64(core_hmac_md5(key,data))},hmac_hash:function(key,data){return binl2str(core_hmac_md5(key,data))},test:function(){return MD5.hexdigest("abc")==="900150983cd24fb0d6963f7d28e17f72"}};return obj})();if(!Function.prototype.bind){Function.prototype.bind=function(obj){var func=this;return function(){return func.apply(obj,arguments)}}}if(!Function.prototype.prependArg){Function.prototype.prependArg=function(arg){var func=this;return function(){var newargs=[arg];for(var i=0;i<arguments.length;i++){newargs.push(arguments[i])}return func.apply(this,newargs)}}}if(!Array.prototype.indexOf){Array.prototype.indexOf=function(elt){var len=this.length;var from=Number(arguments[1])||0;from=(from<0)?Math.ceil(from):Math.floor(from);if(from<0){from+=len}for(;from<len;from++){if(from in this&&this[from]===elt){return from}}return -1}}(function(callback){var Strophe;function $build(name,attrs){return new Strophe.Builder(name,attrs)}function $msg(attrs){return new Strophe.Builder("message",attrs)}function $iq(attrs){return new Strophe.Builder("iq",attrs)}function $pres(attrs){return new Strophe.Builder("presence",attrs)}Strophe={VERSION:"1.0.1",NS:{HTTPBIND:"http://jabber.org/protocol/httpbind",BOSH:"urn:xmpp:xbosh",CLIENT:"jabber:client",AUTH:"jabber:iq:auth",ROSTER:"jabber:iq:roster",PROFILE:"jabber:iq:profile",DISCO_INFO:"http://jabber.org/protocol/disco#info",DISCO_ITEMS:"http://jabber.org/protocol/disco#items",MUC:"http://jabber.org/protocol/muc",SASL:"urn:ietf:params:xml:ns:xmpp-sasl",STREAM:"http://etherx.jabber.org/streams",BIND:"urn:ietf:params:xml:ns:xmpp-bind",SESSION:"urn:ietf:params:xml:ns:xmpp-session",VERSION:"jabber:iq:version",STANZAS:"urn:ietf:params:xml:ns:xmpp-stanzas"},addNamespace:function(name,value){Strophe.NS[name]=value},Status:{ERROR:0,CONNECTING:1,CONNFAIL:2,AUTHENTICATING:3,AUTHFAIL:4,CONNECTED:5,DISCONNECTED:6,DISCONNECTING:7,ATTACHED:8},LogLevel:{DEBUG:0,INFO:1,WARN:2,ERROR:3,FATAL:4},ElementType:{NORMAL:1,TEXT:3},TIMEOUT:1.1,SECONDARY_TIMEOUT:0.1,forEachChild:function(elem,elemName,func){var i,childNode;for(i=0;i<elem.childNodes.length;i++){childNode=elem.childNodes[i];if(childNode.nodeType==Strophe.ElementType.NORMAL&&(!elemName||this.isTagEqual(childNode,elemName))){func(childNode)}}},isTagEqual:function(el,name){return el.tagName.toLowerCase()==name.toLowerCase()},_xmlGenerator:null,_makeGenerator:function(){var doc;if(window.ActiveXObject){doc=new ActiveXObject("Microsoft.XMLDOM");doc.appendChild(doc.createElement("strophe"))}else{doc=document.implementation.createDocument("jabber:client","strophe",null)}return doc},xmlElement:function(name){if(!name){return null}var node=null;if(!Strophe._xmlGenerator){Strophe._xmlGenerator=Strophe._makeGenerator()}node=Strophe._xmlGenerator.createElement(name);var a,i,k;for(a=1;a<arguments.length;a++){if(!arguments[a]){continue}if(typeof(arguments[a])=="string"||typeof(arguments[a])=="number"){node.appendChild(Strophe.xmlTextNode(arguments[a]))}else{if(typeof(arguments[a])=="object"&&typeof(arguments[a].sort)=="function"){for(i=0;i<arguments[a].length;i++){if(typeof(arguments[a][i])=="object"&&typeof(arguments[a][i].sort)=="function"){node.setAttribute(arguments[a][i][0],arguments[a][i][1])}}}else{if(typeof(arguments[a])=="object"){for(k in arguments[a]){if(arguments[a].hasOwnProperty(k)){node.setAttribute(k,arguments[a][k])}}}}}}return node},xmlescape:function(text){text=text.replace(/\&/g,"&");text=text.replace(/</g,"<");text=text.replace(/>/g,">");return text},xmlTextNode:function(text){text=Strophe.xmlescape(text);if(!Strophe._xmlGenerator){Strophe._xmlGenerator=Strophe._makeGenerator()}return Strophe._xmlGenerator.createTextNode(text)},getText:function(elem){if(!elem){return null}var str="";if(elem.childNodes.length===0&&elem.nodeType==Strophe.ElementType.TEXT){str+=elem.nodeValue}for(var i=0;i<elem.childNodes.length;i++){if(elem.childNodes[i].nodeType==Strophe.ElementType.TEXT){str+=elem.childNodes[i].nodeValue}}return str},copyElement:function(elem){var i,el;if(elem.nodeType==Strophe.ElementType.NORMAL){el=Strophe.xmlElement(elem.tagName);for(i=0;i<elem.attributes.length;i++){el.setAttribute(elem.attributes[i].nodeName.toLowerCase(),elem.attributes[i].value)}for(i=0;i<elem.childNodes.length;i++){el.appendChild(Strophe.copyElement(elem.childNodes[i]))}}else{if(elem.nodeType==Strophe.ElementType.TEXT){el=Strophe.xmlTextNode(elem.nodeValue)}}return el},escapeNode:function(node){return node.replace(/^\s+|\s+$/g,"").replace(/\\/g,"\\5c").replace(/ /g,"\\20").replace(/\"/g,"\\22").replace(/\&/g,"\\26").replace(/\'/g,"\\27").replace(/\//g,"\\2f").replace(/:/g,"\\3a").replace(/</g,"\\3c").replace(/>/g,"\\3e").replace(/@/g,"\\40")},unescapeNode:function(node){return node.replace(/\\20/g," ").replace(/\\22/g,'"').replace(/\\26/g,"&").replace(/\\27/g,"'").replace(/\\2f/g,"/").replace(/\\3a/g,":").replace(/\\3c/g,"<").replace(/\\3e/g,">").replace(/\\40/g,"@").replace(/\\5c/g,"\\")},getNodeFromJid:function(jid){if(jid.indexOf("@")<0){return null}return jid.split("@")[0]},getDomainFromJid:function(jid){var bare=Strophe.getBareJidFromJid(jid);if(bare.indexOf("@")<0){return bare}else{var parts=bare.split("@");parts.splice(0,1);return parts.join("@")}},getResourceFromJid:function(jid){var s=jid.split("/");if(s.length<2){return null}s.splice(0,1);return s.join("/")},getBareJidFromJid:function(jid){return jid.split("/")[0]},log:function(level,msg){return},debug:function(msg){this.log(this.LogLevel.DEBUG,msg)},info:function(msg){this.log(this.LogLevel.INFO,msg)},warn:function(msg){this.log(this.LogLevel.WARN,msg)},error:function(msg){this.log(this.LogLevel.ERROR,msg)},fatal:function(msg){this.log(this.LogLevel.FATAL,msg)},serialize:function(elem){var result;if(!elem){return null}if(typeof(elem.tree)==="function"){elem=elem.tree()}var nodeName=elem.nodeName;var i,child;if(elem.getAttribute("_realname")){nodeName=elem.getAttribute("_realname")}result="<"+nodeName;for(i=0;i<elem.attributes.length;i++){if(elem.attributes[i].nodeName!="_realname"){result+=" "+elem.attributes[i].nodeName.toLowerCase()+"='"+elem.attributes[i].value.replace("&","&").replace("'","'").replace("<","<")+"'"}}if(elem.childNodes.length>0){result+=">";for(i=0;i<elem.childNodes.length;i++){child=elem.childNodes[i];if(child.nodeType==Strophe.ElementType.NORMAL){result+=Strophe.serialize(child)}else{if(child.nodeType==Strophe.ElementType.TEXT){result+=child.nodeValue}}}result+="</"+nodeName+">"}else{result+="/>"}return result},_requestId:0,_connectionPlugins:{},addConnectionPlugin:function(name,ptype){Strophe._connectionPlugins[name]=ptype}};Strophe.Builder=function(name,attrs){if(name=="presence"||name=="message"||name=="iq"){if(attrs&&!attrs.xmlns){attrs.xmlns=Strophe.NS.CLIENT}else{if(!attrs){attrs={xmlns:Strophe.NS.CLIENT}}}}this.nodeTree=Strophe.xmlElement(name,attrs);this.node=this.nodeTree};Strophe.Builder.prototype={tree:function(){return this.nodeTree},toString:function(){return Strophe.serialize(this.nodeTree)},up:function(){this.node=this.node.parentNode;return this},attrs:function(moreattrs){for(var k in moreattrs){if(moreattrs.hasOwnProperty(k)){this.node.setAttribute(k,moreattrs[k])}}return this},c:function(name,attrs){var child=Strophe.xmlElement(name,attrs);this.node.appendChild(child);this.node=child;return this},cnode:function(elem){this.node.appendChild(elem);this.node=elem;return this},t:function(text){var child=Strophe.xmlTextNode(text);this.node.appendChild(child);return this}};Strophe.Handler=function(handler,ns,name,type,id,from,options){this.handler=handler;this.ns=ns;this.name=name;this.type=type;this.id=id;this.options=options||{matchbare:false};if(!this.options.matchBare){this.options.matchBare=false}if(this.options.matchBare){this.from=Strophe.getBareJidFromJid(from)}else{this.from=from}this.user=true};Strophe.Handler.prototype={isMatch:function(elem){var nsMatch;var from=null;if(this.options.matchBare){from=Strophe.getBareJidFromJid(elem.getAttribute("from"))}else{from=elem.getAttribute("from")}nsMatch=false;if(!this.ns){nsMatch=true}else{var self=this;Strophe.forEachChild(elem,null,function(elem){if(elem.getAttribute("xmlns")==self.ns){nsMatch=true}});nsMatch=nsMatch||elem.getAttribute("xmlns")==this.ns}if(nsMatch&&(!this.name||Strophe.isTagEqual(elem,this.name))&&(!this.type||elem.getAttribute("type")===this.type)&&(!this.id||elem.getAttribute("id")===this.id)&&(!this.from||from===this.from)){return true}return false},run:function(elem){var result=null;try{result=this.handler(elem)}catch(e){if(e.sourceURL){Strophe.fatal("error: "+this.handler+" "+e.sourceURL+":"+e.line+" - "+e.name+": "+e.message)}else{if(e.fileName){if(typeof(console)!="undefined"){console.trace();console.error(this.handler," - error - ",e,e.message)}Strophe.fatal("error: "+this.handler+" "+e.fileName+":"+e.lineNumber+" - "+e.name+": "+e.message)}else{Strophe.fatal("error: "+this.handler)}}throw e}return result},toString:function(){return"{Handler: "+this.handler+"("+this.name+","+this.id+","+this.ns+")}"}};Strophe.TimedHandler=function(period,handler){this.period=period;this.handler=handler;this.lastCalled=new Date().getTime();this.user=true};Strophe.TimedHandler.prototype={run:function(){this.lastCalled=new Date().getTime();return this.handler()},reset:function(){this.lastCalled=new Date().getTime()},toString:function(){return"{TimedHandler: "+this.handler+"("+this.period+")}"}};Strophe.Request=function(elem,func,rid,sends){this.id=++Strophe._requestId;this.xmlData=elem;this.data=Strophe.serialize(elem);this.origFunc=func;this.func=func;this.rid=rid;this.date=NaN;this.sends=sends||0;this.abort=false;this.dead=null;this.age=function(){if(!this.date){return 0}var now=new Date();return(now-this.date)/1000};this.timeDead=function(){if(!this.dead){return 0}var now=new Date();return(now-this.dead)/1000};this.xhr=this._newXHR()};Strophe.Request.prototype={getResponse:function(){var node=null;if(this.xhr.responseXML&&this.xhr.responseXML.documentElement){node=this.xhr.responseXML.documentElement;if(node.tagName=="parsererror"){Strophe.error("invalid response received");Strophe.error("responseText: "+this.xhr.responseText);Strophe.error("responseXML: "+Strophe.serialize(this.xhr.responseXML));throw"parsererror"}}else{if(this.xhr.responseText){Strophe.error("invalid response received");Strophe.error("responseText: "+this.xhr.responseText);Strophe.error("responseXML: "+Strophe.serialize(this.xhr.responseXML))}}return node},_newXHR:function(){var xhr=null;if(window.XMLHttpRequest){xhr=new XMLHttpRequest();if(xhr.overrideMimeType){xhr.overrideMimeType("text/xml")}}else{if(window.ActiveXObject){xhr=new ActiveXObject("Microsoft.XMLHTTP")}}xhr.onreadystatechange=this.func.prependArg(this);return xhr}};Strophe.Connection=function(service){this.service=service;this.jid="";this.rid=Math.floor(Math.random()*4294967295);this.sid=null;this.streamId=null;this.do_session=false;this.do_bind=false;this.timedHandlers=[];this.handlers=[];this.removeTimeds=[];this.removeHandlers=[];this.addTimeds=[];this.addHandlers=[];this._idleTimeout=null;this._disconnectTimeout=null;this.authenticated=false;this.disconnecting=false;this.connected=false;this.errors=0;this.paused=false;this.hold=1;this.wait=60;this.window=5;this._data=[];this._requests=[];this._uniqueId=Math.round(Math.random()*10000);this._sasl_success_handler=null;this._sasl_failure_handler=null;this._sasl_challenge_handler=null;this._idleTimeout=setTimeout(this._onIdle.bind(this),100);for(var k in Strophe._connectionPlugins){if(Strophe._connectionPlugins.hasOwnProperty(k)){var ptype=Strophe._connectionPlugins[k];var F=function(){};F.prototype=ptype;this[k]=new F();this[k].init(this)}}};Strophe.Connection.prototype={reset:function(){this.rid=Math.floor(Math.random()*4294967295);this.sid=null;this.streamId=null;this.do_session=false;this.do_bind=false;this.timedHandlers=[];this.handlers=[];this.removeTimeds=[];this.removeHandlers=[];this.addTimeds=[];this.addHandlers=[];this.authenticated=false;this.disconnecting=false;this.connected=false;this.errors=0;this._requests=[];this._uniqueId=Math.round(Math.random()*10000)},pause:function(){this.paused=true},resume:function(){this.paused=false},getUniqueId:function(suffix){if(typeof(suffix)=="string"||typeof(suffix)=="number"){return ++this._uniqueId+":"+suffix}else{return ++this._uniqueId+""}},connect:function(jid,pass,callback,wait,hold){this.jid=jid;this.pass=pass;this.connect_callback=callback;this.disconnecting=false;this.connected=false;this.authenticated=false;this.errors=0;this.wait=wait||this.wait;this.hold=hold||this.hold;this.domain=Strophe.getDomainFromJid(this.jid);var body=this._buildBody().attrs({to:this.domain,"xml:lang":"en",wait:this.wait,hold:this.hold,content:"text/xml; charset=utf-8",ver:"1.6","xmpp:version":"1.0","xmlns:xmpp":Strophe.NS.BOSH});this._changeConnectStatus(Strophe.Status.CONNECTING,null);this._requests.push(new Strophe.Request(body.tree(),this._onRequestStateChange.bind(this).prependArg(this._connect_cb.bind(this)),body.tree().getAttribute("rid")));this._throttledRequestHandler()},attach:function(jid,sid,rid,callback,wait,hold,wind){this.jid=jid;this.sid=sid;this.rid=rid;this.connect_callback=callback;this.domain=Strophe.getDomainFromJid(this.jid);this.authenticated=true;this.connected=true;this.wait=wait||this.wait;this.hold=hold||this.hold;this.window=wind||this.window;this._changeConnectStatus(Strophe.Status.ATTACHED,null)},xmlInput:function(elem){return},xmlOutput:function(elem){return},rawInput:function(data){return},rawOutput:function(data){return},send:function(elem){if(elem===null){return}if(typeof(elem.sort)==="function"){for(var i=0;i<elem.length;i++){this._queueData(elem[i])}}else{if(typeof(elem.tree)==="function"){this._queueData(elem.tree())}else{this._queueData(elem)}}this._throttledRequestHandler();clearTimeout(this._idleTimeout);this._idleTimeout=setTimeout(this._onIdle.bind(this),100)},flush:function(){clearTimeout(this._idleTimeout);this._onIdle()},sendIQ:function(elem,callback,errback,timeout){var timeoutHandler=null;var that=this;if(typeof(elem.tree)==="function"){elem=elem.tree()}var id=elem.getAttribute("id");if(!id){id=this.getUniqueId("sendIQ");elem.setAttribute("id",id)}var handler=this.addHandler(function(stanza){if(timeoutHandler){that.deleteTimedHandler(timeoutHandler)}var iqtype=stanza.getAttribute("type");if(iqtype==="result"){if(callback){callback(stanza)}}else{if(iqtype==="error"){if(errback){errback(stanza)}}else{throw {name:"StropheError",message:"Got bad IQ type of "+iqtype}}}},null,"iq",null,id);if(timeout){timeoutHandler=this.addTimedHandler(timeout,function(){that.deleteHandler(handler);if(errback){errback(null)}return false})}this.send(elem);return id},_queueData:function(element){if(element===null||!element.tagName||!element.childNodes){throw {name:"StropheError",message:"Cannot queue non-DOMElement."}}this._data.push(element)},_sendRestart:function(){this._data.push("restart");this._throttledRequestHandler();clearTimeout(this._idleTimeout);this._idleTimeout=setTimeout(this._onIdle.bind(this),100)},addTimedHandler:function(period,handler){var thand=new Strophe.TimedHandler(period,handler);this.addTimeds.push(thand);return thand},deleteTimedHandler:function(handRef){this.removeTimeds.push(handRef)},addHandler:function(handler,ns,name,type,id,from,options){var hand=new Strophe.Handler(handler,ns,name,type,id,from,options);this.addHandlers.push(hand);return hand},deleteHandler:function(handRef){this.removeHandlers.push(handRef)},disconnect:function(reason){this._changeConnectStatus(Strophe.Status.DISCONNECTING,reason);Strophe.info("Disconnect was called because: "+reason);if(this.connected){this._disconnectTimeout=this._addSysTimedHandler(3000,this._onDisconnectTimeout.bind(this));this._sendTerminate()}},_changeConnectStatus:function(status,condition){for(var k in Strophe._connectionPlugins){if(Strophe._connectionPlugins.hasOwnProperty(k)){var plugin=this[k];if(plugin.statusChanged){try{plugin.statusChanged(status,condition)}catch(err){Strophe.error(""+k+" plugin caused an exception changing status: "+err)}}}}if(this.connect_callback){try{this.connect_callback(status,condition)}catch(e){Strophe.error("User connection callback caused an exception: "+e)}}},_buildBody:function(){var bodyWrap=$build("body",{rid:this.rid++,xmlns:Strophe.NS.HTTPBIND});if(this.sid!==null){bodyWrap.attrs({sid:this.sid})}return bodyWrap},_removeRequest:function(req){Strophe.debug("removing request");var i;for(i=this._requests.length-1;i>=0;i--){if(req==this._requests[i]){this._requests.splice(i,1)}}req.xhr.onreadystatechange=function(){};this._throttledRequestHandler()},_restartRequest:function(i){var req=this._requests[i];if(req.dead===null){req.dead=new Date()}this._processRequest(i)},_processRequest:function(i){var req=this._requests[i];var reqStatus=-1;try{if(req.xhr.readyState==4){reqStatus=req.xhr.status}}catch(e){Strophe.error("caught an error in _requests["+i+"], reqStatus: "+reqStatus)}if(typeof(reqStatus)=="undefined"){reqStatus=-1}var time_elapsed=req.age();var primaryTimeout=(!isNaN(time_elapsed)&&time_elapsed>Math.floor(Strophe.TIMEOUT*this.wait));var secondaryTimeout=(req.dead!==null&&req.timeDead()>Math.floor(Strophe.SECONDARY_TIMEOUT*this.wait));var requestCompletedWithServerError=(req.xhr.readyState==4&&(reqStatus<1||reqStatus>=500));if(primaryTimeout||secondaryTimeout||requestCompletedWithServerError){if(secondaryTimeout){Strophe.error("Request "+this._requests[i].id+" timed out (secondary), restarting")}req.abort=true;req.xhr.abort();req.xhr.onreadystatechange=function(){};this._requests[i]=new Strophe.Request(req.xmlData,req.origFunc,req.rid,req.sends);req=this._requests[i]}if(req.xhr.readyState===0){Strophe.debug("request id "+req.id+"."+req.sends+" posting");req.date=new Date();try{req.xhr.open("POST",this.service,true)}catch(e2){Strophe.error("XHR open failed.");if(!this.connected){this._changeConnectStatus(Strophe.Status.CONNFAIL,"bad-service")}this.disconnect();return}var sendFunc=function(){req.xhr.send(req.data)};if(req.sends>1){var backoff=Math.pow(req.sends,3)*1000;setTimeout(sendFunc,backoff)}else{sendFunc()}req.sends++;this.xmlOutput(req.xmlData);this.rawOutput(req.data)}else{Strophe.debug("_processRequest: "+(i===0?"first":"second")+" request has readyState of "+req.xhr.readyState)}},_throttledRequestHandler:function(){if(!this._requests){Strophe.debug("_throttledRequestHandler called with undefined requests")}else{Strophe.debug("_throttledRequestHandler called with "+this._requests.length+" requests")}if(!this._requests||this._requests.length===0){return}if(this._requests.length>0){this._processRequest(0)}if(this._requests.length>1&&Math.abs(this._requests[0].rid-this._requests[1].rid)<this.window-1){this._processRequest(1)}},_onRequestStateChange:function(func,req){Strophe.debug("request id "+req.id+"."+req.sends+" state changed to "+req.xhr.readyState);if(req.abort){req.abort=false;return}var reqStatus;if(req.xhr.readyState==4){reqStatus=0;try{reqStatus=req.xhr.status}catch(e){}if(typeof(reqStatus)=="undefined"){reqStatus=0}if(this.disconnecting){if(reqStatus>=400){this._hitError(reqStatus);return}}var reqIs0=(this._requests[0]==req);var reqIs1=(this._requests[1]==req);if((reqStatus>0&&reqStatus<500)||req.sends>5){this._removeRequest(req);Strophe.debug("request id "+req.id+" should now be removed")}if(reqStatus==200){if(reqIs1||(reqIs0&&this._requests.length>0&&this._requests[0].age()>Math.floor(Strophe.SECONDARY_TIMEOUT*this.wait))){this._restartRequest(0)}Strophe.debug("request id "+req.id+"."+req.sends+" got 200");func(req);this.errors=0}else{Strophe.error("request id "+req.id+"."+req.sends+" error "+reqStatus+" happened");if(reqStatus===0||(reqStatus>=400&&reqStatus<600)||reqStatus>=12000){this._hitError(reqStatus);if(reqStatus>=400&&reqStatus<500){this._changeConnectStatus(Strophe.Status.DISCONNECTING,null);this._doDisconnect()}}}if(!((reqStatus>0&&reqStatus<10000)||req.sends>5)){this._throttledRequestHandler()}}},_hitError:function(reqStatus){this.errors++;Strophe.warn("request errored, status: "+reqStatus+", number of errors: "+this.errors);if(this.errors>4){this._onDisconnectTimeout()}},_doDisconnect:function(){Strophe.info("_doDisconnect was called");this.authenticated=false;this.disconnecting=false;this.sid=null;this.streamId=null;this.rid=Math.floor(Math.random()*4294967295);if(this.connected){this._changeConnectStatus(Strophe.Status.DISCONNECTED,null);this.connected=false}this.handlers=[];this.timedHandlers=[];this.removeTimeds=[];this.removeHandlers=[];this.addTimeds=[];this.addHandlers=[]},_dataRecv:function(req){try{var elem=req.getResponse()}catch(e){if(e!="parsererror"){throw e}this.disconnect("strophe-parsererror")}if(elem===null){return}this.xmlInput(elem);this.rawInput(Strophe.serialize(elem));var i,hand;while(this.removeHandlers.length>0){hand=this.removeHandlers.pop();i=this.handlers.indexOf(hand);if(i>=0){this.handlers.splice(i,1)}}while(this.addHandlers.length>0){this.handlers.push(this.addHandlers.pop())}if(this.disconnecting&&this._requests.length===0){this.deleteTimedHandler(this._disconnectTimeout);this._disconnectTimeout=null;this._doDisconnect();return}var typ=elem.getAttribute("type");var cond,conflict;if(typ!==null&&typ=="terminate"){cond=elem.getAttribute("condition");conflict=elem.getElementsByTagName("conflict");if(cond!==null){if(cond=="remote-stream-error"&&conflict.length>0){cond="conflict"}this._changeConnectStatus(Strophe.Status.CONNFAIL,cond)}else{this._changeConnectStatus(Strophe.Status.CONNFAIL,"unknown")}this.disconnect();return}var self=this;Strophe.forEachChild(elem,null,function(child){var i,newList;newList=self.handlers;self.handlers=[];for(i=0;i<newList.length;i++){var hand=newList[i];if(hand.isMatch(child)&&(self.authenticated||!hand.user)){if(hand.run(child)){self.handlers.push(hand)}}else{self.handlers.push(hand)}}})},_sendTerminate:function(){Strophe.info("_sendTerminate was called");var body=this._buildBody().attrs({type:"terminate"});if(this.authenticated){body.c("presence",{xmlns:Strophe.NS.CLIENT,type:"unavailable"})}this.disconnecting=true;var req=new Strophe.Request(body.tree(),this._onRequestStateChange.bind(this).prependArg(this._dataRecv.bind(this)),body.tree().getAttribute("rid"));this._requests.push(req);this._throttledRequestHandler()},_connect_cb:function(req){Strophe.info("_connect_cb was called");this.connected=true;var bodyWrap=req.getResponse();if(!bodyWrap){return}this.xmlInput(bodyWrap);this.rawInput(Strophe.serialize(bodyWrap));var typ=bodyWrap.getAttribute("type");var cond,conflict;if(typ!==null&&typ=="terminate"){cond=bodyWrap.getAttribute("condition");conflict=bodyWrap.getElementsByTagName("conflict");if(cond!==null){if(cond=="remote-stream-error"&&conflict.length>0){cond="conflict"}this._changeConnectStatus(Strophe.Status.CONNFAIL,cond)}else{this._changeConnectStatus(Strophe.Status.CONNFAIL,"unknown")}return}if(!this.sid){this.sid=bodyWrap.getAttribute("sid")}if(!this.stream_id){this.stream_id=bodyWrap.getAttribute("authid")}var wind=bodyWrap.getAttribute("requests");if(wind){this.window=parseInt(wind,10)}var hold=bodyWrap.getAttribute("hold");if(hold){this.hold=parseInt(hold,10)}var wait=bodyWrap.getAttribute("wait");if(wait){this.wait=parseInt(wait,10)}var do_sasl_plain=false;var do_sasl_digest_md5=false;var do_sasl_anonymous=false;var mechanisms=bodyWrap.getElementsByTagName("mechanism");var i,mech,auth_str,hashed_auth_str;if(mechanisms.length>0){for(i=0;i<mechanisms.length;i++){mech=Strophe.getText(mechanisms[i]);if(mech=="DIGEST-MD5"){do_sasl_digest_md5=true}else{if(mech=="PLAIN"){do_sasl_plain=true}else{if(mech=="ANONYMOUS"){do_sasl_anonymous=true}}}}}else{var body=this._buildBody();this._requests.push(new Strophe.Request(body.tree(),this._onRequestStateChange.bind(this).prependArg(this._connect_cb.bind(this)),body.tree().getAttribute("rid")));this._throttledRequestHandler();return}if(Strophe.getNodeFromJid(this.jid)===null&&do_sasl_anonymous){this._changeConnectStatus(Strophe.Status.AUTHENTICATING,null);this._sasl_success_handler=this._addSysHandler(this._sasl_success_cb.bind(this),null,"success",null,null);this._sasl_failure_handler=this._addSysHandler(this._sasl_failure_cb.bind(this),null,"failure",null,null);this.send($build("auth",{xmlns:Strophe.NS.SASL,mechanism:"ANONYMOUS"}).tree())}else{if(Strophe.getNodeFromJid(this.jid)===null){this._changeConnectStatus(Strophe.Status.CONNFAIL,"x-strophe-bad-non-anon-jid");this.disconnect()}else{if(do_sasl_digest_md5){this._changeConnectStatus(Strophe.Status.AUTHENTICATING,null);this._sasl_challenge_handler=this._addSysHandler(this._sasl_challenge1_cb.bind(this),null,"challenge",null,null);this._sasl_failure_handler=this._addSysHandler(this._sasl_failure_cb.bind(this),null,"failure",null,null);this.send($build("auth",{xmlns:Strophe.NS.SASL,mechanism:"DIGEST-MD5"}).tree())}else{if(do_sasl_plain){auth_str=Strophe.getBareJidFromJid(this.jid);auth_str=auth_str+"\u0000";auth_str=auth_str+Strophe.getNodeFromJid(this.jid);auth_str=auth_str+"\u0000";auth_str=auth_str+this.pass;this._changeConnectStatus(Strophe.Status.AUTHENTICATING,null);this._sasl_success_handler=this._addSysHandler(this._sasl_success_cb.bind(this),null,"success",null,null);this._sasl_failure_handler=this._addSysHandler(this._sasl_failure_cb.bind(this),null,"failure",null,null);hashed_auth_str=Base64.encode(auth_str);this.send($build("auth",{xmlns:Strophe.NS.SASL,mechanism:"PLAIN"}).t(hashed_auth_str).tree())}else{this._changeConnectStatus(Strophe.Status.AUTHENTICATING,null);this._addSysHandler(this._auth1_cb.bind(this),null,null,null,"_auth_1");this.send($iq({type:"get",to:this.domain,id:"_auth_1"}).c("query",{xmlns:Strophe.NS.AUTH}).c("username",{}).t(Strophe.getNodeFromJid(this.jid)).tree())}}}}},_sasl_challenge1_cb:function(elem){var attribMatch=/([a-z]+)=("[^"]+"|[^,"]+)(?:,|$)/;var challenge=Base64.decode(Strophe.getText(elem));var cnonce=MD5.hexdigest(Math.random()*1234567890);var realm="";var host=null;var nonce="";var qop="";var matches;this.deleteHandler(this._sasl_failure_handler);while(challenge.match(attribMatch)){matches=challenge.match(attribMatch);challenge=challenge.replace(matches[0],"");matches[2]=matches[2].replace(/^"(.+)"$/,"$1");switch(matches[1]){case"realm":realm=matches[2];break;case"nonce":nonce=matches[2];break;case"qop":qop=matches[2];break;case"host":host=matches[2];break}}var digest_uri="xmpp/"+this.domain;if(host!==null){digest_uri=digest_uri+"/"+host}var A1=MD5.hash(Strophe.getNodeFromJid(this.jid)+":"+realm+":"+this.pass)+":"+nonce+":"+cnonce;var A2="AUTHENTICATE:"+digest_uri;var responseText="";responseText+="username="+this._quote(Strophe.getNodeFromJid(this.jid))+",";responseText+="realm="+this._quote(realm)+",";responseText+="nonce="+this._quote(nonce)+",";responseText+="cnonce="+this._quote(cnonce)+",";responseText+='nc="00000001",';responseText+='qop="auth",';responseText+="digest-uri="+this._quote(digest_uri)+",";responseText+="response="+this._quote(MD5.hexdigest(MD5.hexdigest(A1)+":"+nonce+":00000001:"+cnonce+":auth:"+MD5.hexdigest(A2)))+",";responseText+='charset="utf-8"';this._sasl_challenge_handler=this._addSysHandler(this._sasl_challenge2_cb.bind(this),null,"challenge",null,null);this._sasl_success_handler=this._addSysHandler(this._sasl_success_cb.bind(this),null,"success",null,null);this._sasl_failure_handler=this._addSysHandler(this._sasl_failure_cb.bind(this),null,"failure",null,null);this.send($build("response",{xmlns:Strophe.NS.SASL}).t(Base64.encode(responseText)).tree());return false},_quote:function(str){return'"'+str.replace(/\\/g,"\\\\").replace(/"/g,'\\"')+'"'},_sasl_challenge2_cb:function(elem){this.deleteHandler(this._sasl_success_handler);this.deleteHandler(this._sasl_failure_handler);this._sasl_success_handler=this._addSysHandler(this._sasl_success_cb.bind(this),null,"success",null,null);this._sasl_failure_handler=this._addSysHandler(this._sasl_failure_cb.bind(this),null,"failure",null,null);this.send($build("response",{xmlns:Strophe.NS.SASL}).tree());return false},_auth1_cb:function(elem){var iq=$iq({type:"set",id:"_auth_2"}).c("query",{xmlns:Strophe.NS.AUTH}).c("username",{}).t(Strophe.getNodeFromJid(this.jid)).up().c("password").t(this.pass);if(!Strophe.getResourceFromJid(this.jid)){this.jid=Strophe.getBareJidFromJid(this.jid)+"/strophe"}iq.up().c("resource",{}).t(Strophe.getResourceFromJid(this.jid));this._addSysHandler(this._auth2_cb.bind(this),null,null,null,"_auth_2");this.send(iq.tree());return false},_sasl_success_cb:function(elem){Strophe.info("SASL authentication succeeded.");this.deleteHandler(this._sasl_failure_handler);this._sasl_failure_handler=null;if(this._sasl_challenge_handler){this.deleteHandler(this._sasl_challenge_handler);this._sasl_challenge_handler=null}this._addSysHandler(this._sasl_auth1_cb.bind(this),null,"stream:features",null,null);this._sendRestart();return false},_sasl_auth1_cb:function(elem){var i,child;for(i=0;i<elem.childNodes.length;i++){child=elem.childNodes[i];if(child.nodeName=="bind"){this.do_bind=true}if(child.nodeName=="session"){this.do_session=true}}if(!this.do_bind){this._changeConnectStatus(Strophe.Status.AUTHFAIL,null);return false}else{this._addSysHandler(this._sasl_bind_cb.bind(this),null,null,null,"_bind_auth_2");var resource=Strophe.getResourceFromJid(this.jid);if(resource){this.send($iq({type:"set",id:"_bind_auth_2"}).c("bind",{xmlns:Strophe.NS.BIND}).c("resource",{}).t(resource).tree())}else{this.send($iq({type:"set",id:"_bind_auth_2"}).c("bind",{xmlns:Strophe.NS.BIND}).tree())}}return false},_sasl_bind_cb:function(elem){if(elem.getAttribute("type")=="error"){Strophe.info("SASL binding failed.");this._changeConnectStatus(Strophe.Status.AUTHFAIL,null);return false}var bind=elem.getElementsByTagName("bind");var jidNode;if(bind.length>0){jidNode=bind[0].getElementsByTagName("jid");if(jidNode.length>0){this.jid=Strophe.getText(jidNode[0]);if(this.do_session){this._addSysHandler(this._sasl_session_cb.bind(this),null,null,null,"_session_auth_2");this.send($iq({type:"set",id:"_session_auth_2"}).c("session",{xmlns:Strophe.NS.SESSION}).tree())}else{this.authenticated=true;this._changeConnectStatus(Strophe.Status.CONNECTED,null)}}}else{Strophe.info("SASL binding failed.");this._changeConnectStatus(Strophe.Status.AUTHFAIL,null);return false}},_sasl_session_cb:function(elem){if(elem.getAttribute("type")=="result"){this.authenticated=true;this._changeConnectStatus(Strophe.Status.CONNECTED,null)}else{if(elem.getAttribute("type")=="error"){Strophe.info("Session creation failed.");this._changeConnectStatus(Strophe.Status.AUTHFAIL,null);return false}}return false},_sasl_failure_cb:function(elem){if(this._sasl_success_handler){this.deleteHandler(this._sasl_success_handler);this._sasl_success_handler=null}if(this._sasl_challenge_handler){this.deleteHandler(this._sasl_challenge_handler);this._sasl_challenge_handler=null}this._changeConnectStatus(Strophe.Status.AUTHFAIL,null);return false},_auth2_cb:function(elem){if(elem.getAttribute("type")=="result"){this.authenticated=true;this._changeConnectStatus(Strophe.Status.CONNECTED,null)}else{if(elem.getAttribute("type")=="error"){this._changeConnectStatus(Strophe.Status.AUTHFAIL,null);this.disconnect()}}return false},_addSysTimedHandler:function(period,handler){var thand=new Strophe.TimedHandler(period,handler);thand.user=false;this.addTimeds.push(thand);return thand},_addSysHandler:function(handler,ns,name,type,id){var hand=new Strophe.Handler(handler,ns,name,type,id);hand.user=false;this.addHandlers.push(hand);return hand},_onDisconnectTimeout:function(){Strophe.info("_onDisconnectTimeout was called");var req;while(this._requests.length>0){req=this._requests.pop();req.abort=true;req.xhr.abort();req.xhr.onreadystatechange=function(){}}this._doDisconnect();return false},_onIdle:function(){var i,thand,since,newList;while(this.removeTimeds.length>0){thand=this.removeTimeds.pop();i=this.timedHandlers.indexOf(thand);if(i>=0){this.timedHandlers.splice(i,1)}}while(this.addTimeds.length>0){this.timedHandlers.push(this.addTimeds.pop())}var now=new Date().getTime();newList=[];for(i=0;i<this.timedHandlers.length;i++){thand=this.timedHandlers[i];if(this.authenticated||!thand.user){since=thand.lastCalled+thand.period;if(since-now<=0){if(thand.run()){newList.push(thand)}}else{newList.push(thand)}}}this.timedHandlers=newList;var body,time_elapsed;if(this.authenticated&&this._requests.length===0&&this._data.length===0&&!this.disconnecting){Strophe.info("no requests during idle cycle, sending blank request");this._data.push(null)}if(this._requests.length<2&&this._data.length>0&&!this.paused){body=this._buildBody();for(i=0;i<this._data.length;i++){if(this._data[i]!==null){if(this._data[i]==="restart"){body.attrs({to:this.domain,"xml:lang":"en","xmpp:restart":"true","xmlns:xmpp":Strophe.NS.BOSH})}else{body.cnode(this._data[i]).up()}}}delete this._data;this._data=[];this._requests.push(new Strophe.Request(body.tree(),this._onRequestStateChange.bind(this).prependArg(this._dataRecv.bind(this)),body.tree().getAttribute("rid")));this._processRequest(this._requests.length-1)}if(this._requests.length>0){time_elapsed=this._requests[0].age();if(this._requests[0].dead!==null){if(this._requests[0].timeDead()>Math.floor(Strophe.SECONDARY_TIMEOUT*this.wait)){this._throttledRequestHandler()}}if(time_elapsed>Math.floor(Strophe.TIMEOUT*this.wait)){Strophe.warn("Request "+this._requests[0].id+" timed out, over "+Math.floor(Strophe.TIMEOUT*this.wait)+" seconds since last activity");this._throttledRequestHandler()}}clearTimeout(this._idleTimeout);this._idleTimeout=setTimeout(this._onIdle.bind(this),100)}};if(callback){callback(Strophe,$build,$msg,$iq,$pres)}})(function(){window.Strophe=arguments[0];window.$build=arguments[1];window.$msg=arguments[2];window.$iq=arguments[3];window.$pres=arguments[4]});
\ No newline at end of file diff --git a/mod/beechat/views/default/js/strophe.muc.js b/mod/beechat/views/default/js/strophe.muc.js new file mode 100644 index 000000000..954ca8730 --- /dev/null +++ b/mod/beechat/views/default/js/strophe.muc.js @@ -0,0 +1,300 @@ +/* +Plugin to implement the MUC extension. http://xmpp.org/extensions/xep-0045.html +*/ +/* jslint configuration: */ +/* global document, window, setTimeout, clearTimeout, console, + XMLHttpRequest, ActiveXObject, + Base64, MD5, + Strophe, $build, $msg, $iq, $pres +*/ + +Strophe.addConnectionPlugin('muc', { + _connection: null, + // The plugin must have the init function + /***Function + Initialize the MUC plugin. Sets the correct connection object and + extends the namesace. + */ + init: function(conn) { + this._connection = conn; + /* extend name space + * NS.MUC - XMPP Multi-user chat namespace + * from XEP 45. + * + */ + Strophe.addNamespace('MUC_OWNER', Strophe.NS.MUC+"#owner"); + Strophe.addNamespace('MUC_ADMIN', Strophe.NS.MUC+"#admin"); + }, + /***Function + Join a multi-user chat room + Parameters: + (String) room - The multi-user chat room to join. + (String) nick - The nickname to use in the chat room. Optional + (Function) msg_handler_cb - The function call to handle messages from the + specified chat room. + (Function) pres_handler_cb - The function call back to handle presence + in the chat room. + (String) password - The optional password to use. (password protected + rooms only) + */ + join: function(room, nick, msg_handler_cb, pres_handler_cb, password) { + var room_nick = this.test_append_nick(room, nick); + var msg = $pres({from: this._connection.jid, + to: room_nick}) + .c("x",{xmlns: Strophe.NS.MUC}); + if (password) + { + var password_elem = Strophe.xmlElement("password", + [], + password); + msg.cnode(password_elem); + } + if (msg_handler_cb) + { + this._connection.addHandler(function(stanza) { + var from = stanza.getAttribute('from'); + var roomname = from.split("/"); + // filter on room name + if (roomname.length > 1 && roomname[0] == room) + { + return msg_handler_cb(stanza); + } + else + { + return true; + } + }, + null, + "message", + null, + null, + null); + } + if (pres_handler_cb) + { + this._connection.addHandler(function(stanza) { + var xquery = stanza.getElementsByTagName("x"); + if (xquery.length > 0) + { + //Handle only MUC user protocol + for (var i = 0; i < xquery.length; i++) + { + var xmlns = xquery[i].getAttribute("xmlns"); + + if (xmlns && xmlns.match(Strophe.NS.MUC)) + { + return pres_handler_cb(stanza); + } + } + } + return true; + }, + null, + "presence", + null, + null, + null); + } + this._connection.send(msg); + }, + /***Function + Leave a multi-user chat room + Parameters: + (String) room - The multi-user chat room to leave. + (String) nick - The nick name used in the room. + (Function) handler_cb - Optional function to handle the successful leave. + Returns: + iqid - The unique id for the room leave. + */ + leave: function(room, nick, handler_cb) { + var room_nick = this.test_append_nick(room, nick); + var presenceid = this._connection.getUniqueId(); + var presence = $pres({type: "unavailable", + id: presenceid, + from: this._connection.jid, + to: room_nick}) + .c("x",{xmlns: Strophe.NS.MUC}); + this._connection.addHandler(handler_cb, + null, + "presence", + null, + presenceid, + null); + this._connection.send(presence); + return presenceid; + }, + /***Function + Parameters: + (String) room - The multi-user chat room name. + (String) nick - The nick name used in the chat room. + (String) message - The message to send to the room. + Returns: + msgiq - the unique id used to send the message + */ + message: function(room, nick, message) { + var room_nick = this.test_append_nick(room, nick); + var msgid = this._connection.getUniqueId(); + var msg = $msg({to: room_nick, + from: this._connection.jid, + type: "groupchat", + id: msgid}).c("body", + {xmlns: Strophe.NS.CLIENT}).t(message); + msg.up().c("x", {xmlns: "jabber:x:event"}).c("composing"); + this._connection.send(msg); + return msgid; + }, + /***Function + Start a room configuration. + Parameters: + (String) room - The multi-user chat room name. + Returns: + id - the unique id used to send the configuration request + */ + configure: function(room) { + //send iq to start room configuration + var config = $iq({to:room, + type: "get"}).c("query", + {xmlns: Strophe.NS.MUC_OWNER}); + var stanza = config.tree(); + return this._connection.sendIQ(stanza, + function(){}, + function(){}); + }, + /***Function + Cancel the room configuration + Parameters: + (String) room - The multi-user chat room name. + Returns: + id - the unique id used to cancel the configuration. + */ + cancelConfigure: function(room) { + //send iq to start room configuration + var config = $iq({to: room, + type: "set"}) + .c("query", {xmlns: Strophe.NS.MUC_OWNER}) + .c("x", {xmlns: "jabber:x:data", type: "cancel"}); + var stanza = config.tree(); + return this._connection.sendIQ(stanza, + function(){}, + function(){}); + }, + /***Function + Save a room configuration. + Parameters: + (String) room - The multi-user chat room name. + (Array) configarray - an array of form elements used to configure the room. + Returns: + id - the unique id used to save the configuration. + */ + saveConfiguration: function(room, configarray) { + var config = $iq({to: room, + type: "set"}) + .c("query", {xmlns: Strophe.NS.MUC_OWNER}) + .c("x", {xmlns: "jabber:x:data", type: "submit"}); + for (var i = 0; i >= configarray.length; i++) { + config.cnode(configarray[i]); + } + var stanza = config.tree(); + return this._connection.sendIQ(stanza, + function(){}, + function(){}); + }, + /***Function + Parameters: + (String) room - The multi-user chat room name. + Returns: + id - the unique id used to create the chat room. + */ + createInstantRoom: function(room) { + var roomiq = $iq({to: room, + type: "set"}) + .c("query", {xmlns: Strophe.NS.MUC_OWNER}) + .c("x", {xmlns: "jabber:x:data", + type: "submit"}); + return this._connection.sendIQ(roomiq.tree(), + function() {}, + function() {}); + }, + /*** + Set the topic of the chat room. + Parameters: + (String) room - The multi-user chat room name. + (String) topic - Topic message. + */ + setTopic: function(room, topic) { + var msg = $msg({to: room, + from: this._connection.jid, + type: "groupchat"}) + .c("subject", {xmlns: "jabber:client"}).t(topic); + this._connection.send(msg.tree()); + }, + /***Function + Changes the role and affiliation of a member of a MUC room. + The modification can only be done by a room moderator. An error will be + returned if the user doesn't have permission. + Parameters: + (String) room - The multi-user chat room name. + (String) nick - The nick name of the user to modify. + (String) role - The new role of the user. + (String) affiliation - The new affiliation of the user. + (String) reason - The reason for the change. + Returns: + iq - the id of the mode change request. + */ + modifyUser: function(room, nick, role, affiliation, reason) { + var item_attrs = {nick: Strophe.escapeNode(nick)}; + if (role !== null) + { + item_attrs.role = role; + } + if (affiliation !== null) + { + item_attrs.affiliation = affiliation; + } + var item = $build("item", item_attrs); + if (reason !== null) + { + item.cnode(Strophe.xmlElement("reason", reason)); + } + var roomiq = $iq({to: room, + type: "set"}) + .c("query", {xmlns: Strophe.NS.MUC_OWNER}).cnode(item.tree()); + return this._connection.sendIQ(roomiq.tree(), + function() {}, + function() {}); + }, + /***Function + Change the current users nick name. + Parameters: + (String) room - The multi-user chat room name. + (String) user - The new nick name. + */ + changeNick: function(room, user) { + var room_nick = this.test_append_nick(room, user); + var presence = $pres({from: this._connection.jid, + to: room_nick}) + .c("x",{xmlns: Strophe.NS.MUC}); + this._connection.send(presence.tree()); + }, + /***Function + List all chat room available on a server. + Parameters: + (String) server - name of chat server. + (String) handle_cb - Function to call for room list return. + */ + listRooms: function(server, handle_cb) { + var iq = $iq({to: server, + from: this._connection.jid, + type: "get"}) + .c("query",{xmlns: Strophe.NS.DISCO_ITEMS}); + this._connection.sendIQ(iq, handle_cb, function(){}); + }, + test_append_nick: function(room, nick) { + var room_nick = room; + if (nick) + { + room_nick += "/" + Strophe.escapeNode(nick); + } + return room_nick; + } +});
\ No newline at end of file diff --git a/mod/beechat/views/default/js/strophe.muc.js.php b/mod/beechat/views/default/js/strophe.muc.js.php new file mode 100644 index 000000000..e10750d02 --- /dev/null +++ b/mod/beechat/views/default/js/strophe.muc.js.php @@ -0,0 +1,300 @@ +/* +Plugin to implement the MUC extension. http://xmpp.org/extensions/xep-0045.html +*/ +/* jslint configuration: */ +/* global document, window, setTimeout, clearTimeout, console, + XMLHttpRequest, ActiveXObject, + Base64, MD5, + Strophe, $build, $msg, $iq, $pres +*/ + +Strophe.addConnectionPlugin('muc', { + _connection: null, + // The plugin must have the init function + /***Function + Initialize the MUC plugin. Sets the correct connection object and + extends the namesace. + */ + init: function(conn) { + this._connection = conn; + /* extend name space + * NS.MUC - XMPP Multi-user chat namespace + * from XEP 45. + * + */ + Strophe.addNamespace('MUC_OWNER', Strophe.NS.MUC+"#owner"); + Strophe.addNamespace('MUC_ADMIN', Strophe.NS.MUC+"#admin"); + }, + /***Function + Join a multi-user chat room + Parameters: + (String) room - The multi-user chat room to join. + (String) nick - The nickname to use in the chat room. Optional + (Function) msg_handler_cb - The function call to handle messages from the + specified chat room. + (Function) pres_handler_cb - The function call back to handle presence + in the chat room. + (String) password - The optional password to use. (password protected + rooms only) + */ + join: function(room, nick, msg_handler_cb, pres_handler_cb, password) { + var room_nick = this.test_append_nick(room, nick); + var msg = $pres({from: this._connection.jid, + to: room_nick}) + .c("x",{xmlns: Strophe.NS.MUC}); + if (password) + { + var password_elem = Strophe.xmlElement("password", + [], + password); + msg.cnode(password_elem); + } + if (msg_handler_cb) + { + this._connection.addHandler(function(stanza) { + var from = stanza.getAttribute('from'); + var roomname = from.split("/"); + // filter on room name + if (roomname.length > 1 && roomname[0] == room) + { + return msg_handler_cb(stanza); + } + else + { + return true; + } + }, + null, + "message", + null, + null, + null); + } + if (pres_handler_cb) + { + this._connection.addHandler(function(stanza) { + var xquery = stanza.getElementsByTagName("x"); + if (xquery.length > 0) + { + //Handle only MUC user protocol + for (var i = 0; i < xquery.length; i++) + { + var xmlns = xquery[i].getAttribute("xmlns"); + + if (xmlns && xmlns.match(Strophe.NS.MUC)) + { + return pres_handler_cb(stanza); + } + } + } + return true; + }, + null, + "presence", + null, + null, + null); + } + this._connection.send(msg); + }, + /***Function + Leave a multi-user chat room + Parameters: + (String) room - The multi-user chat room to leave. + (String) nick - The nick name used in the room. + (Function) handler_cb - Optional function to handle the successful leave. + Returns: + iqid - The unique id for the room leave. + */ + leave: function(room, nick, handler_cb) { + var room_nick = this.test_append_nick(room, nick); + var presenceid = this._connection.getUniqueId(); + var presence = $pres({type: "unavailable", + id: presenceid, + from: this._connection.jid, + to: room_nick}) + .c("x",{xmlns: Strophe.NS.MUC}); + this._connection.addHandler(handler_cb, + null, + "presence", + null, + presenceid, + null); + this._connection.send(presence); + return presenceid; + }, + /***Function + Parameters: + (String) room - The multi-user chat room name. + (String) nick - The nick name used in the chat room. + (String) message - The message to send to the room. + Returns: + msgiq - the unique id used to send the message + */ + message: function(room, nick, message) { + var room_nick = this.test_append_nick(room, nick); + var msgid = this._connection.getUniqueId(); + var msg = $msg({to: room_nick, + from: this._connection.jid, + type: "groupchat", + id: msgid}).c("body", + {xmlns: Strophe.NS.CLIENT}).t(message); + msg.up().c("x", {xmlns: "jabber:x:event"}).c("composing"); + this._connection.send(msg); + return msgid; + }, + /***Function + Start a room configuration. + Parameters: + (String) room - The multi-user chat room name. + Returns: + id - the unique id used to send the configuration request + */ + configure: function(room) { + //send iq to start room configuration + var config = $iq({to:room, + type: "get"}).c("query", + {xmlns: Strophe.NS.MUC_OWNER}); + var stanza = config.tree(); + return this._connection.sendIQ(stanza, + function(){}, + function(){}); + }, + /***Function + Cancel the room configuration + Parameters: + (String) room - The multi-user chat room name. + Returns: + id - the unique id used to cancel the configuration. + */ + cancelConfigure: function(room) { + //send iq to start room configuration + var config = $iq({to: room, + type: "set"}) + .c("query", {xmlns: Strophe.NS.MUC_OWNER}) + .c("x", {xmlns: "jabber:x:data", type: "cancel"}); + var stanza = config.tree(); + return this._connection.sendIQ(stanza, + function(){}, + function(){}); + }, + /***Function + Save a room configuration. + Parameters: + (String) room - The multi-user chat room name. + (Array) configarray - an array of form elements used to configure the room. + Returns: + id - the unique id used to save the configuration. + */ + saveConfiguration: function(room, configarray) { + var config = $iq({to: room, + type: "set"}) + .c("query", {xmlns: Strophe.NS.MUC_OWNER}) + .c("x", {xmlns: "jabber:x:data", type: "submit"}); + for (var i = 0; i >= configarray.length; i++) { + config.cnode(configarray[i]); + } + var stanza = config.tree(); + return this._connection.sendIQ(stanza, + function(){}, + function(){}); + }, + /***Function + Parameters: + (String) room - The multi-user chat room name. + Returns: + id - the unique id used to create the chat room. + */ + createInstantRoom: function(room) { + var roomiq = $iq({to: room, + type: "set"}) + .c("query", {xmlns: Strophe.NS.MUC_OWNER}) + .c("x", {xmlns: "jabber:x:data", + type: "submit"}); + return this._connection.sendIQ(roomiq.tree(), + function() {}, + function() {}); + }, + /*** + Set the topic of the chat room. + Parameters: + (String) room - The multi-user chat room name. + (String) topic - Topic message. + */ + setTopic: function(room, topic) { + var msg = $msg({to: room, + from: this._connection.jid, + type: "groupchat"}) + .c("subject", {xmlns: "jabber:client"}).t(topic); + this._connection.send(msg.tree()); + }, + /***Function + Changes the role and affiliation of a member of a MUC room. + The modification can only be done by a room moderator. An error will be + returned if the user doesn't have permission. + Parameters: + (String) room - The multi-user chat room name. + (String) nick - The nick name of the user to modify. + (String) role - The new role of the user. + (String) affiliation - The new affiliation of the user. + (String) reason - The reason for the change. + Returns: + iq - the id of the mode change request. + */ + modifyUser: function(room, nick, role, affiliation, reason) { + var item_attrs = {nick: Strophe.escapeNode(nick)}; + if (role !== null) + { + item_attrs.role = role; + } + if (affiliation !== null) + { + item_attrs.affiliation = affiliation; + } + var item = $build("item", item_attrs); + if (reason !== null) + { + item.cnode(Strophe.xmlElement("reason", reason)); + } + var roomiq = $iq({to: room, + type: "set"}) + .c("query", {xmlns: Strophe.NS.MUC_OWNER}).cnode(item.tree()); + return this._connection.sendIQ(roomiq.tree(), + function() {}, + function() {}); + }, + /***Function + Change the current users nick name. + Parameters: + (String) room - The multi-user chat room name. + (String) user - The new nick name. + */ + changeNick: function(room, user) { + var room_nick = this.test_append_nick(room, user); + var presence = $pres({from: this._connection.jid, + to: room_nick}) + .c("x",{xmlns: Strophe.NS.MUC}); + this._connection.send(presence.tree()); + }, + /***Function + List all chat room available on a server. + Parameters: + (String) server - name of chat server. + (String) handle_cb - Function to call for room list return. + */ + listRooms: function(server, handle_cb) { + var iq = $iq({to: server, + from: this._connection.jid, + type: "get"}) + .c("query",{xmlns: Strophe.NS.DISCO_ITEMS}); + this._connection.sendIQ(iq, handle_cb, function(){}); + }, + test_append_nick: function(room, nick) { + var room_nick = room; + if (nick) + { + room_nick += "/" + Strophe.escapeNode(nick); + } + return room_nick; + } +}); diff --git a/mod/beechat/views/default/settings/beechat/edit.php b/mod/beechat/views/default/settings/beechat/edit.php new file mode 100755 index 000000000..ec4ab08de --- /dev/null +++ b/mod/beechat/views/default/settings/beechat/edit.php @@ -0,0 +1,31 @@ +<?php +/** + * Barter Plugin + * @package Barters + **/ + $domain = elgg_get_plugin_setting("domain", "beechat"); + //$group_domain = elgg_get_plugin_setting("groupdomain", "beechat"); + $xmlrpc_ip = elgg_get_plugin_setting("xmlrpcip", "beechat"); + $dbname = elgg_get_plugin_setting("dbname", "beechat"); + $dbhost = elgg_get_plugin_setting("dbhost", "beechat"); + $dbuser = elgg_get_plugin_setting("dbuser", "beechat"); + $dbpassword = elgg_get_plugin_setting("dbpassword", "beechat"); +?> +<p> + <?php echo elgg_echo('beechat:domain'); ?> + <?php echo elgg_view('input/text', array('internalname' => 'params[domain]','value' => $domain)); ?> + <!--<?php echo elgg_echo('beechat:groupdomain'); ?> + <?php echo elgg_view('input/text', array('internalname' => 'params[groupdomain]','value' => $group_domain)); ?>--> + <?php echo elgg_echo('beechat:xmlrpcip'); ?> + <?php echo elgg_view('input/text', array('internalname' => 'params[xmlrpcip]','value' => $xmlrpc_ip)); ?> + <?php echo elgg_echo('beechat:dbname'); ?> + <?php echo elgg_view('input/text', array('internalname' => 'params[dbname]','value' => $dbname)); ?> + <?php echo elgg_echo('beechat:dbhost'); ?> + <?php echo elgg_view('input/text', array('internalname' => 'params[dbhost]','value' => $dbhost)); ?> + <?php echo elgg_echo('beechat:dbuser'); ?> + <?php echo elgg_view('input/text', array('internalname' => 'params[dbuser]','value' => $dbuser)); ?> + <?php echo elgg_echo('beechat:dbpassword'); ?> + <?php echo elgg_view('input/password', array('internalname' => 'params[dbpassword]','value' => $dbpassword)); ?> + +</p> + |