support-chat/js/supportchat.js

Fri, 16 Apr 2010 18:44:53 +0100

author
matthew@heavyhorse.vm.bytemark.co.uk
date
Fri, 16 Apr 2010 18:44:53 +0100
changeset 58
c775513a5d78
parent 56
5dd3b23da0ae
child 59
603d9caeb6d5
permissions
-rw-r--r--

Remove the current assistant if they leave the room

/* Config */

var support_config = {
	login_domain: "anon.localhost",
	bosh_url: "/http-bind",
	muc_server: "support.localhost",
	team_rooms: {
		"Sales": "sales@support.localhost",
		"Technical": "technical@support.localhost"
	},
	send_invites: true,
	offline_support: "support@localhost",
	alternative_url: "http://www.google.co.uk/"
};

/*** XMPP handling */
var conn = null;

/*** Query information */
var question_type; // E.g. "Sales", "Technical"
var question_name; // Name of the submitter
var question_text; // The query itself

/*** XMPP rooms */
var team_muc; // MUC of the assistant team
var question_muc; // Temporary room for query discussion

/* Called by Strophe when status of connection changes
   (from disconnected to connected, vice-versa, etc.)
*/
function handle_connection_status(status, err)
{
	if(err)
		set_ui_state("error");
}

/* Initiate the connection to the XMPP server */
function start_connection()
{
	conn = new Strophe.Connection(support_config.bosh_url);
	var ret = true;
	try
	{
		conn.connect(support_config.login_domain, null, handle_connection_status, 50);
	}
	catch(e)
	{
		ret = false;
	}
	return ret;
}

/*** UI handling */

/* Initial UI state */
var ui_state = "question";

/* Called to change the UI state (question, wait, converse) */
function set_ui_state(new_state)
{
	if(ui_state != new_state)
	{
		$("#support-"+ui_state).hide();
		$("#support-"+(ui_state=new_state)).show();
	}
}

var current_assistant = null;
function set_assistant(new_assistant)
{
	if(new_assistant == null)
	{
		$("#support-assistant-name").text("No assistant present.");
		question_muc.send_message("{System} There is now no active assistant");
		team_muc.send_message("Query has no active assistant");
		show_message(null, current_assistant + " has left, please stand by.");
	}
	else
	{
	$("#support-assistant-name").html("<u>Assistant:</u> "+htmlescape(new_assistant));
		question_muc.send_message("{System} "+new_assistant+": You are now the selected assistant");
		team_muc.send_message("Query being handled by "+new_assistant);
		show_message(null, "You are now being assisted by " + new_assistant)
	}
	current_assistant = new_assistant;
}

function show_message(nick, message)
{
	var html = "<span class='muc-"+(nick?"message":"system")+"'>";
	if(nick)
		html += "<span class='muc-nick'>" + htmlescape(nick) + "</span>" + ": ";
	html += htmlescape(message) + "</span><br/>\n";
	$("#support-log").append(html).scrollTop($("#support-log")[0].scrollHeight);
}

/* Handle the user submitting the question form */
function on_question_submit()
{
	question_type = $("#support-question-type").val();
	question_name = $("#support-question-name").val();
	question_text = $("#support-question-text").val();
	
	set_ui_state("wait");
	
	// Create our question room
	question_muc = new MUC(conn, {
		// Handle room joins
		joined: function (stanza, muc, occupant)
		{
			if(occupant.nick == question_muc.nick)
			{
				// We joined the question room, now join the team room and tell them
				team_muc.join(support_config.team_rooms[question_type], question_muc.nick);
				// Also post our question to the question room for reference
				question_muc.send_message(question_text);
			}
			else if(current_assistant == null)
			{
				// We were waiting for an assistant, and one just joined
				set_assistant(occupant.nick);
				if(ui_state == "wait")
				{
					$("#support-send-button").click(function ()
					{
						question_muc.send_message($("#support-input").val());
						$("#support-input").val("");
					});
					set_ui_state("converse");
				}
			}
		},
		
		// Someone left the question MUC
		left: function (stanza, muc, occupant)
		{
			if(occupant.nick == current_assistant)
				set_assistant(null);
		},
		
		// Handle incoming messages
		message: function (stanza, muc, nick, message)
		{
			if(nick != question_muc.nick && message.charAt(0) == "!") // Command
			{
				if(message.indexOf("!assist") == 0)
				{
					set_assistant(nick);
				}
				else if(message.indexOf("!stop") == 0)
				{
					set_assistant(null);
				}
			}
			else if(nick != question_muc.nick || message.indexOf("{System} ") != 0) // Normal message
			{
				show_message(nick, message);
			}
		}
	});

	// Get a unique room name from the server and then join the question MUC
	conn.sendIQ($iq({to: support_config.muc_server, type: "get"})
		.c("query", { xmlns: "http://jabber.org/protocol/muc#unique" }),
		function (result) // Success
		{
			var unique = Strophe.getText(result.getElementsByTagName("unique")[0]);
			question_muc.join(unique + "@" + support_config.muc_server, question_name);
		},
		function (result) // Failure to get unique room name
		{
			var unique = "support-"+Math.floor(Math.random()*512);
			question_muc.join(unique + "@" + support_config.muc_server, question_name);
		});
	
	// Create the team MUC object (it will be joined after we join the question MUC)
	team_muc = new MUC(conn, {
		// Someone joined the team MUC
		joined: function (stanza, muc, occupant)
		{
			if(occupant.nick != team_muc.nick)
				return;
			
			var sent = false;
			for(var nick in team_muc.occupants)
			{
				if(team_muc.occupants[nick].affiliation == "none" || nick == team_muc.nick)
					continue;
				sent = true;
				if(support_config.send_invites)
					team_muc.send_invite(team_muc.jid+"/"+nick, question_text + "\n" + question_muc.jid);
				else
					team_muc.send_private_message(nick, question_text + "\n" + question_muc.jid);
			}
			if(!sent)
			{
				set_ui_state("offline");
			}
		},
		
		error: function (stanza, muc, error)
		{
			if(error == "conflict")
			{
				muc.join(support_config.team_rooms[question_type], team_muc.nick+"_");
			}
			else
				set_ui_state("error");
		}
	});
}

function build_ui()
{
	return $(" \
	<div id='support-chat'> \
		<div id='support-question'> \
			<h2>What is the nature of your question?</h2> \
			<select id='support-question-type'> \
				<option>Sales</option> \
				<option>Technical</option> \
			</select> \
			<h2>What is your name?</h2> \
			<input id='support-question-name' type='text' /> \
			<h2>Your question:</h2> \
			<textarea id='support-question-text'></textarea><br/> \
			<input id='support-question-submit' type='submit' /> \
		</div> \
		<div id='support-wait'> \
			Please wait while we find someone to \
			answer your query... \
			<br/><br/><br/><br/> \
			<center><img src='waiting.gif' alt='Waiting' /></center> \
		</div> \
		<div id='support-converse'> \
			<div id='support-assistant-name'></div> \
			<div id='support-log'></div> \
			<div id='support-input-container'><textarea id='support-input' type='text' value=''></textarea></div> \
			<input id='support-send-button' type='submit' value='Send' /> \
			<div style='clear:right;'></div> \
		</div> \
		<div id='support-offline'> \
			<p>Sorry, there are no assistants available \
			   to answer your question at the moment. \
			</p> \
			<div id='support-offline-form'> \
				<p>To receive a reply to your question via \
				   email, please enter your email address \
				   below: \
				</p> \
				<input id='support-offline-email' type='text' /> \
				<input id='support-offline-submit-button' type='submit' value='Submit' /> \
			</div> \
			<div id='support-offline-thanks'> \
				<p>Thank you. Your question has been submitted \
				   and will be replied to as soon as an assistant \
				   becomes available.</p> \
			</div> \
		</div> \
		<div id='support-error'> \
			<p>Sorry, there is a problem with the live support \
			   service at the moment. Please see our \
			   <a href='"+support_config.alternative_url+"'>alternative \
			   support channels</a> to receive assistance. \
			</p> \
		</div> \
	</div> \
	");
}

function display_ui()
{
	// Display pop-up, showing question form
	var ui = build_ui();
	
	ui.appendTo("body");
	
	$("#support-question-submit").click(on_question_submit);
	$("#support-input").keypress(function (event) {
		if(event.keyCode == 13)
		{
			event.preventDefault();
			$("#support-send-button").click();
		}
	});
	$("#support-offline-submit-button").click(function ()
	{
		$("#support-offline-form").hide();
		conn.send($msg({to: support_config.offline_support, type: "normal"})
			.c("subject").t("Support query from " + question_name).up()
			.c("body").t(question_text + "\n\nReply via email to: "+
				$("#support-offline-email").val()));
		$("#support-offline-thanks").show();
	});

	ui.dialog({
		title:"Live Support",
		height: 400,
		width: 285
	});

	if(!start_connection())
	{
		set_ui_state("error");
	}
}

/*** Helper functions */
function htmlescape(s)
{
	return s.replace(/&/g,'&amp;').
		replace(/>/g,'&gt;').
		replace(/</g,'&lt;').
		replace(/"/g,'&quot;');
}

function activate_links()
{
	$("[href='#support-chat']").click(display_ui);
}

$(activate_links);

mercurial