Marauroa Chat Tutorial/HTML5 Client: Difference between revisions
imported>Hendrik Brummermann layout |
imported>Hendrik Brummermann |
||
| (32 intermediate revisions by the same user not shown) | |||
| Line 37: | Line 37: | ||
<script type="text/javascript" src="chatclient.js"></script> |
<script type="text/javascript" src="chatclient.js"></script> |
||
</head> |
</head> |
||
<body> |
|||
<body> |
|||
<h1>Marautoa Chat Tutoral Client in HTML 5</h1> |
<h1>Marautoa Chat Tutoral Client in HTML 5</h1> |
||
<!-- input field for text --> |
<!-- input field for text --> |
||
<form id="form" onsubmit=" |
<form id="form" onsubmit="ui.chatBar.send(); return false"> |
||
<input type="text" name="chatbar" id="chatbar" style="width:90%"> |
<input type="text" name="chatbar" id="chatbar" style="width:90%"> |
||
<input type="submit" value="Send"> |
<input type="submit" value="Send"> |
||
| Line 53: | Line 53: | ||
== |
== Implementing the client Framework == |
||
As the first step, we want to connect to the server using the marauroa.clientFramework. Note that we use "null" for host and post which means that we connect to the same server from which the client has been downloaded from. Connecting to the server may take a second or two, therefore we give some feedback to the user. |
|||
{{TODO|Complete this section}} |
|||
<source lang="javascript"> |
|||
<!-- |
|||
function startClient() { |
|||
The design of our Client class allows us to easily use it in something more complex then Test class above. Here is the example of a simple Swing application that uses Client as a communication tool |
|||
ui.chatLog.addLine("client", "Client loaded. Connecting..."); |
|||
<source lang="java"> |
|||
var body = document.getElementById("body") |
|||
import javax.swing.*; |
|||
body.style.cursor = "wait"; |
|||
import java.awt.event.*; |
|||
marauroa.clientFramework.connect(null, null); |
|||
import java.io.IOException; |
|||
} |
|||
import java.net.URL; |
|||
</source> |
|||
import java.util.*; |
|||
import java.awt.*; |
|||
Now as we are able to connect to the server, we want to receive and handle events. In the Java word, we implemented a subclass of ClientFramework. In JavaScript, however, we can just redefine the methods, we are interested in: |
|||
public class View extends JFrame implements ActionListener { |
|||
<source lang="javascript"> |
|||
private javax.swing.JButton jSayButton; |
|||
private javax.swing.JButton jConnectButton; |
|||
private javax.swing.JScrollPane jScrollPane1; |
|||
private javax.swing.JTextArea jChatArea; |
|||
private javax.swing.JTextField jInputField; |
|||
private javax.swing.Timer timer; |
|||
/** display a message to the chat window on disconnect. */ |
|||
private Client client = null; |
|||
marauroa.clientFramework.onDisconnect = function(reason, error){ |
|||
ui.chatLog.addLine("error", "Disconnected: " + error); |
|||
} |
|||
/** on failed login, open a message box and disable the user interface */ |
|||
public View() { |
|||
marauroa.clientFramework.onLoginFailed = function(reason, text) { |
|||
initComponents(); |
|||
alert("Login failed. Please check your password and try again."); |
|||
jSayButton.addActionListener( |
|||
marauroa.clientFramework.close(); |
|||
new ActionListener() { |
|||
document.getElementById("chatbar").disabled = true; |
|||
public void actionPerformed(ActionEvent e) { |
|||
document.getElementById("chat").style.backgroundColor = "#AAA"; |
|||
String message = jInputField.getText(); |
|||
} |
|||
jInputField.setText(""); |
|||
client.SendMessage(message); |
|||
} |
|||
}); |
|||
jConnectButton.addActionListener( |
|||
new ActionListener() { |
|||
public void actionPerformed(ActionEvent e) { |
|||
try { |
|||
client = Client.get(); |
|||
client.connect("127.0.0.1", 5555); |
|||
client.login("test1", "test1"); |
|||
client.chooseCharacter("test1"); |
|||
jSayButton.setEnabled(true); |
|||
jInputField.setEnabled(true); |
|||
} catch (Exception exception) { |
|||
JOptionPane.showMessageDialog( |
|||
View.this, "Error", exception.toString(), JOptionPane.WARNING_MESSAGE); |
|||
client = null; |
|||
} |
|||
} |
|||
}); |
|||
timer = new javax.swing.Timer(300, this); |
|||
timer.setInitialDelay(500); |
|||
timer.start(); |
|||
setVisible(true); |
|||
} |
|||
/** Automatically pick the first character associated with this account and enable the chat controls */ |
|||
public void actionPerformed(ActionEvent e) { |
|||
marauroa.clientFramework.onAvailableCharacterDetails = function(characters) { |
|||
if (client != null) { |
|||
marauroa.clientFramework.chooseCharacter(marauroa.util.first(characters).a.name); |
|||
client.loop(0); |
|||
String s = client.popQuote(); |
|||
while (s != null) { |
|||
jChatArea.append(s + "\n"); |
|||
s = client.popQuote(); |
|||
} |
|||
} |
|||
} |
|||
private void initComponents() { |
|||
jScrollPane1 = new javax.swing.JScrollPane(); |
|||
jChatArea = new javax.swing.JTextArea(); |
|||
jSayButton = new javax.swing.JButton(); |
|||
jConnectButton = new javax.swing.JButton(); |
|||
jInputField = new javax.swing.JTextField(); |
|||
var body = document.getElementById("body") |
|||
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); |
|||
body.style.cursor = "auto"; |
|||
setTitle("Chat 0.5"); |
|||
ui.chatLog.addLine("client", "Ready..."); |
|||
setName("main"); |
|||
} |
|||
jChatArea.setColumns(20); |
|||
</source> |
|||
jChatArea.setEditable(false); |
|||
jChatArea.setRows(5); |
|||
jScrollPane1.setViewportView(jChatArea); |
|||
== Handling actions == |
|||
jSayButton.setText("Say"); |
|||
jSayButton.setEnabled(false); |
|||
So far, our client is able to connect to a Marauroa based server and display some basic feedback. There is an input field for chat message. Now we want to send those message to the server. |
|||
jConnectButton.setText("Connect"); |
|||
In order to keep our code well structures, we create an object called "ui" and a subobject called "chatbar". For Java developers: While Java is a class based programming languages, JavaScript is prototype based. |
|||
jInputField.setEnabled(false); |
|||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); |
|||
<source lang="javascript"> |
|||
getContentPane().setLayout(layout); |
|||
/** user interface package */ |
|||
layout.setHorizontalGroup( |
|||
ui = { |
|||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) |
|||
/** methods for the chat input box */ |
|||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() |
|||
chatBar: { |
|||
.addContainerGap() |
|||
/** clear the chat window */ |
|||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) |
|||
clear: function() { |
|||
.addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 394, Short.MAX_VALUE) |
|||
document.getElementById('chatbar').value = ''; |
|||
.addGroup(layout.createSequentialGroup() |
|||
}, |
|||
.addComponent(jInputField, javax.swing.GroupLayout.PREFERRED_SIZE, 236, javax.swing.GroupLayout.PREFERRED_SIZE) |
|||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) |
|||
/** send a message to the server */ |
|||
.addComponent(jSayButton, javax.swing.GroupLayout.DEFAULT_SIZE, 73, Short.MAX_VALUE) |
|||
send: function() { |
|||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) |
|||
var val = document.getElementById('chatbar').value; |
|||
.addComponent(jConnectButton))) |
|||
.addContainerGap()) |
|||
// create an RPAction object of type "chat" with the message. |
|||
); |
|||
var action = { |
|||
layout.setVerticalGroup( |
|||
"type": "chat", |
|||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) |
|||
"text": val; |
|||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() |
|||
}; |
|||
.addContainerGap() |
|||
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 249, Short.MAX_VALUE) |
|||
// send the message to the server and clear the input field |
|||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) |
|||
marauroa.clientFramework.sendAction(action); |
|||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) |
|||
this.clear(); |
|||
.addComponent(jConnectButton) |
|||
} |
|||
.addComponent(jSayButton) |
|||
} |
|||
.addComponent(jInputField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) |
|||
.addContainerGap()) |
|||
); |
|||
pack(); |
|||
} |
|||
} |
} |
||
</source> |
</source> |
||
== Handling perceptions == |
|||
To create the layout of the elements NetBeans was used, but we concentrate just on the source code here. |
|||
Before we can put it all together, there is one remaining piece: We need to listen to perceptions sent by the server and display the chat in our log window. |
|||
The client establishes a connection to a hard-coded location upon Connect button is pressed. There is no "Create new account" functionality, so account should be created beforehand. |
|||
In this tutorial the chat message are not just events, but objects. This allows us to store them to the database and allow late client to read the history. Normally we'd use an marauroa.rpobjectFactory to create those objects with the correct prototype ("Player", "Item", "Creature", ...) as they are transferred from the server. You can have a look at this [http://arianne.cvs.sf.net/viewvc/arianne/stendhal/srcjs/stendhal-entities.js?revision=1.14&view=markup file of the experimental Stendhal HTML5 client], to learn how the rpobjectFactory is used. |
|||
We use timer to regularly check for the new messages in the Client queue. If there are some - they are put to the large text box. Sending the new message also relies on the Client facilities. |
|||
For this really simple chat client, we are only interested in chat objects. Therefore we skip this step for now and work directly on the perception event for new objects: |
|||
The only thing left for the Swing client now is a main method. Here is the source code |
|||
<source lang="java"> |
|||
final class Chat { |
|||
private Chat() {} |
|||
<source lang="javascript"> |
|||
public static void main( String[] args ) { |
|||
marauroa.perceptionListener.onAdded = function(object) { |
|||
new View(); |
|||
if (object.has("text")) { |
|||
} |
|||
ui.chatLog.addLine("text", object.get("from") + "* : " + object.get("text")); |
|||
} |
|||
} |
|||
ui: { |
|||
chatLog: { |
|||
addLine: function(type, msg) { |
|||
var e = document.createElement('p'); |
|||
e.className = "log" + ui.escapeHTML(type); |
|||
e.innerHTML = ui.escapeHTML(msg); |
|||
document.getElementById('chat').appendChild(e); |
|||
document.getElementById('chat').scrollTop = 1000000; |
|||
}, |
|||
clear: function() { |
|||
document.getElementById("chat").innerHTML = ""; |
|||
} |
|||
/** HTML code escaping */ |
|||
escapeHTML: function(msg){ |
|||
return msg.replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace("\n", "<br>"); |
|||
} |
|||
} |
|||
} |
} |
||
</source> |
</source> |
||
Note: When putting all together, you need to merge the "ui" package from the previous section with the one defined here. |
|||
== Deployment == |
== Deployment == |
||
You still use the same command for compilation |
|||
<pre> |
|||
javac -cp marauroa.jar;log4j.jar;. *.java |
|||
</pre> |
|||
'''Sorry, this part is still a bit messy. We promise to make it as easy as the traditional Marauroa version in the future.''' |
|||
Make sure that source files with code for Swing client are in the same directory with jars mentioned and Client.java file. You can run the client with the following command |
|||
<pre> |
|||
Instead of the official download version of marauroa, you need to download the current development version directly from git. |
|||
java -cp marauroa.jar;log4j.jar;. Chat |
|||
</pre> |
|||
Check out Marauroa, Branch ''perception_json'' into a new project: |
|||
* File -> Import |
|||
* Git -> Projects from Git |
|||
* Clone URI: git://arianne.git.sourceforge.net/gitroot/arianne/marauroa |
|||
* Make sure that both "src" and "srcexternal" are marked as source code folders. |
|||
Follow the instructions from the previous pages to setup your Marauroa server, with these little changes: |
|||
* Add all the additional libraries to the classpath. |
|||
* Create a Run Configuration, that launches ''marauroa.server.net.web.WebSocketServer'' |
|||
Create or reuse your server.ini |
|||
* Edit server.ini to add these lines, replacing "accountname" with the name of your account for testing: |
|||
<source lang="ini"> |
|||
http_port=8080 |
|||
debug_fake_web_username=accountname |
|||
</source> |
|||
* Launch the WebSocketServer run configuration |
|||
--> |
|||
* Visit <nowiki>http://localhost:8080/chat.html</nowiki> |
|||
* Best to do this using firefox, with firebug extension installed (if you will be developing or studying the client) |
|||
== Next Steps == |
== Next Steps == |
||
Latest revision as of 22:29, 15 December 2011
Marauroa Tutorial
HTML5 support in Marauroa is in development. We are looking for feedback to stabilize the API and improve the documentation on it.
The HTML 5 client works in a modern browser without requiring any plugins or other software to be installed locally. It is therefore not written in Java but JavaScript. While JavaScript has a similar name, it has some basic concepts that are very different from Java.
HTML Code
We start our HTML 5 client by creating a HTML page consisting of an output area for the chat log and a small input field to enter text. We use CSS rules to make the page look nicely. We are using a development version of Marauroa, which consists of several JS files. The final version will consists of one file to reduce startup time.
<source lang="html4strict"> <!doctype html> <html><head>
<title>Marautoa Chat Tutoral Client in HTML 5</title>
<style type="text/css">
body {font-family: "Arial"}
#chat {border: 1px solid #000; padding:0.5em; overflow-y: scroll}
#chat p {margin: 0}
p.logclient {color: #888}
p.logerror {color: #F00}
</style>
<script src="json.js"></script> <script src="/socket.io/socket.io.js"></script> <script type="text/javascript" src="marauroa.js"></script> <script type="text/javascript" src="client-framework.js"></script> <script type="text/javascript" src="message-factory.js"></script> <script type="text/javascript" src="perception.js"></script> <script type="text/javascript" src="rpfactory.js"></script> <script type="text/javascript" src="chatclient.js"></script>
</head>
<body>
Marautoa Chat Tutoral Client in HTML 5
<form id="form" onsubmit="ui.chatBar.send(); return false">
<input type="text" name="chatbar" id="chatbar" style="width:90%">
<input type="submit" value="Send">
</form>
<noscript>JavaScript is required by the Web Client.</noscript>
</body></html> </source>
Implementing the client Framework
As the first step, we want to connect to the server using the marauroa.clientFramework. Note that we use "null" for host and post which means that we connect to the same server from which the client has been downloaded from. Connecting to the server may take a second or two, therefore we give some feedback to the user.
<source lang="javascript"> function startClient() { ui.chatLog.addLine("client", "Client loaded. Connecting..."); var body = document.getElementById("body") body.style.cursor = "wait"; marauroa.clientFramework.connect(null, null); } </source>
Now as we are able to connect to the server, we want to receive and handle events. In the Java word, we implemented a subclass of ClientFramework. In JavaScript, however, we can just redefine the methods, we are interested in: <source lang="javascript">
/** display a message to the chat window on disconnect. */ marauroa.clientFramework.onDisconnect = function(reason, error){ ui.chatLog.addLine("error", "Disconnected: " + error); }
/** on failed login, open a message box and disable the user interface */ marauroa.clientFramework.onLoginFailed = function(reason, text) { alert("Login failed. Please check your password and try again."); marauroa.clientFramework.close(); document.getElementById("chatbar").disabled = true; document.getElementById("chat").style.backgroundColor = "#AAA"; }
/** Automatically pick the first character associated with this account and enable the chat controls */
marauroa.clientFramework.onAvailableCharacterDetails = function(characters) { marauroa.clientFramework.chooseCharacter(marauroa.util.first(characters).a.name);
var body = document.getElementById("body") body.style.cursor = "auto"; ui.chatLog.addLine("client", "Ready..."); } </source>
Handling actions
So far, our client is able to connect to a Marauroa based server and display some basic feedback. There is an input field for chat message. Now we want to send those message to the server.
In order to keep our code well structures, we create an object called "ui" and a subobject called "chatbar". For Java developers: While Java is a class based programming languages, JavaScript is prototype based.
<source lang="javascript">
/** user interface package */
ui = {
/** methods for the chat input box */
chatBar: {
/** clear the chat window */
clear: function() { document.getElementById('chatbar').value = ; },
/** send a message to the server */
send: function() { var val = document.getElementById('chatbar').value;
// create an RPAction object of type "chat" with the message. var action = { "type": "chat", "text": val; };
// send the message to the server and clear the input field marauroa.clientFramework.sendAction(action); this.clear(); } } } </source>
Handling perceptions
Before we can put it all together, there is one remaining piece: We need to listen to perceptions sent by the server and display the chat in our log window.
In this tutorial the chat message are not just events, but objects. This allows us to store them to the database and allow late client to read the history. Normally we'd use an marauroa.rpobjectFactory to create those objects with the correct prototype ("Player", "Item", "Creature", ...) as they are transferred from the server. You can have a look at this file of the experimental Stendhal HTML5 client, to learn how the rpobjectFactory is used.
For this really simple chat client, we are only interested in chat objects. Therefore we skip this step for now and work directly on the perception event for new objects:
<source lang="javascript"> marauroa.perceptionListener.onAdded = function(object) { if (object.has("text")) { ui.chatLog.addLine("text", object.get("from") + "* : " + object.get("text")); } }
ui: { chatLog: { addLine: function(type, msg) { var e = document.createElement('p'); e.className = "log" + ui.escapeHTML(type); e.innerHTML = ui.escapeHTML(msg); document.getElementById('chat').appendChild(e); document.getElementById('chat').scrollTop = 1000000; },
clear: function() { document.getElementById("chat").innerHTML = ""; }
/** HTML code escaping */
escapeHTML: function(msg){
return msg.replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace("\n", "
");
}
}
}
</source>
Note: When putting all together, you need to merge the "ui" package from the previous section with the one defined here.
Deployment
Sorry, this part is still a bit messy. We promise to make it as easy as the traditional Marauroa version in the future.
Instead of the official download version of marauroa, you need to download the current development version directly from git.
Check out Marauroa, Branch perception_json into a new project:
- File -> Import
- Git -> Projects from Git
- Clone URI: git://arianne.git.sourceforge.net/gitroot/arianne/marauroa
- Make sure that both "src" and "srcexternal" are marked as source code folders.
Follow the instructions from the previous pages to setup your Marauroa server, with these little changes:
- Add all the additional libraries to the classpath.
- Create a Run Configuration, that launches marauroa.server.net.web.WebSocketServer
Create or reuse your server.ini
- Edit server.ini to add these lines, replacing "accountname" with the name of your account for testing:
<source lang="ini"> http_port=8080 debug_fake_web_username=accountname </source>
- Launch the WebSocketServer run configuration
- Visit http://localhost:8080/chat.html
- Best to do this using firefox, with firebug extension installed (if you will be developing or studying the client)
Next Steps
Congratulations, you completed this tutorial. The final sections will list some ideas for further steps to improve. {{#breadcrumbs: Marauroa | Using | Tutorial | Swing Client}}