diff options
-rw-r--r-- | docs/client-server/howto.rst | 13 | ||||
-rw-r--r-- | jsfiddles/example_app/demo.css | 43 | ||||
-rw-r--r-- | jsfiddles/example_app/demo.html | 56 | ||||
-rw-r--r-- | jsfiddles/example_app/demo.js | 303 |
4 files changed, 415 insertions, 0 deletions
diff --git a/docs/client-server/howto.rst b/docs/client-server/howto.rst index 433277000d..9ef4cb5f78 100644 --- a/docs/client-server/howto.rst +++ b/docs/client-server/howto.rst @@ -121,6 +121,8 @@ these rules may specify if you require an **invitation** from someone already in the room in order to **join the room**. In addition, you may also be able to join a room **via a room alias** if one was set up. +**Try out the fiddle: http://jsfiddle.net/og1xokcr/** + Inviting a user to a room ------------------------- You can directly invite a user to a room like so:: @@ -164,6 +166,8 @@ An event is some interesting piece of data that a client may be interested in. It can be a message in a room, a room invite, etc. There are many different ways of getting events, depending on what the client already knows. +**Try out the fiddle: http://jsfiddle.net/5uk4dqe2/** + Getting all state ----------------- If the client doesn't know any information on the rooms the user is @@ -288,3 +292,12 @@ and then resume getting live state from a newer end token. NB: The timeout can be changed by adding a ``timeout`` query parameter, which is in milliseconds. A timeout of 0 will not block. + +Example application +------------------- +The following example demonstrates registration and login, live event streaming, +creating and joining rooms, sending messages, getting member lists and getting +historical messages for a room. This covers most functionality of a messaging +application. + +**Try out the fiddle: http://jsfiddle.net/L8r3o1wr/** diff --git a/jsfiddles/example_app/demo.css b/jsfiddles/example_app/demo.css new file mode 100644 index 0000000000..4c1e157cc8 --- /dev/null +++ b/jsfiddles/example_app/demo.css @@ -0,0 +1,43 @@ +.roomListDashboard, .roomContents, .sendMessageForm { + visibility: hidden; +} + +.roomList { + background-color: #909090; +} + +.messageWrapper { + background-color: #EEEEEE; + height: 400px; + overflow: scroll; +} + +.membersWrapper { + background-color: #EEEEEE; + height: 200px; + width: 50%; + overflow: scroll; +} + +.textEntry { + width: 100% +} + +p { + font-family: monospace; +} + +table +{ + border-spacing:5px; +} + +th,td +{ + padding:5px; +} + +.roomList tr:not(:first-child):hover { + background-color: orange; + cursor: pointer; +} diff --git a/jsfiddles/example_app/demo.html b/jsfiddles/example_app/demo.html new file mode 100644 index 0000000000..0af946f6bc --- /dev/null +++ b/jsfiddles/example_app/demo.html @@ -0,0 +1,56 @@ +<div class="signUp"> + <p>Matrix example application: Requires a local home server running at http://localhost:8080</p> + <form class="registrationForm"> + <p>No account? Register:</p> + <input type="text" id="userReg" placeholder="Username"></input> + <input type="password" id="passwordReg" placeholder="Password"></input> + <input type="button" class="register" value="Register"></input> + </form> + <form class="loginForm"> + <p>Got an account? Login:</p> + <input type="text" id="userLogin" placeholder="Username"></input> + <input type="password" id="passwordLogin" placeholder="Password"></input> + <input type="button" class="login" value="Login"></input> + </form> +</div> + +<div class="roomListDashboard"> + <form class="createRoomForm"> + <input type="text" id="roomAlias" placeholder="Room alias"></input> + <input type="button" class="createRoom" value="Create Room"></input> + </form> + <table id="rooms" class="roomList"> + <tbody> + <tr> + <th>Room</th> + <th>My state</th> + <th>Latest message</th> + </tr> + </tbody> + </table> +</div> + +<div class="roomContents"> + <p id="roomName">Select a room</p> + <div class="messageWrapper"> + <table id="messages"> + <tbody> + </tbody> + </table> + </div> + <form class="sendMessageForm"> + <input type="text" class="textEntry" id="body" placeholder="Enter text here..." onkeydown="javascript:if (event.keyCode == 13) document.getElementById('sendMsg').focus()"></input> + <input type="button" class="sendMessage" id="sendMsg" value="Send"></input> + </form> +</div> + +<div> + <p>Member list:</p> + <div class="membersWrapper"> + <table id="members"> + <tbody> + </tbody> + </table> + </div> +</div> + diff --git a/jsfiddles/example_app/demo.js b/jsfiddles/example_app/demo.js new file mode 100644 index 0000000000..295597f0f7 --- /dev/null +++ b/jsfiddles/example_app/demo.js @@ -0,0 +1,303 @@ +var accountInfo = {}; + +var eventStreamInfo = { + from: "END" +}; + +var roomInfo = []; +var memberInfo = []; +var viewingRoomId; + +// ************** Event Streaming ************** +var longpollEventStream = function() { + var url = "http://localhost:8080/matrix/client/api/v1/events?access_token=$token&from=$from"; + url = url.replace("$token", accountInfo.access_token); + url = url.replace("$from", eventStreamInfo.from); + + $.getJSON(url, function(data) { + eventStreamInfo.from = data.end; + + var hasNewLatestMessage = false; + var updatedMemberList = false; + var i=0; + var j=0; + for (i=0; i<data.chunk.length; ++i) { + if (data.chunk[i].type === "m.room.message") { + console.log("Got new message: " + JSON.stringify(data.chunk[i])); + if (viewingRoomId === data.chunk[i].room_id) { + addMessage(data.chunk[i]); + } + + for (j=0; j<roomInfo.length; ++j) { + if (roomInfo[j].room_id === data.chunk[i].room_id) { + roomInfo[j].latest_message = data.chunk[i].content.body; + hasNewLatestMessage = true; + } + } + } + else if (data.chunk[i].type === "m.room.member") { + if (viewingRoomId === data.chunk[i].room_id) { + console.log("Got new member: " + JSON.stringify(data.chunk[i])); + for (j=0; j<memberInfo.length; ++j) { + if (memberInfo[j].target_user_id === data.chunk[i].target_user_id) { + memberInfo[j] = data.chunk[i]; + updatedMemberList = true; + break; + } + } + if (!updatedMemberList) { + memberInfo.push(data.chunk[i]); + updatedMemberList = true; + } + } + if (data.chunk[i].target_user_id === accountInfo.user_id) { + getCurrentRoomList(); // update our join/invite list + } + } + else { + console.log("Discarding: " + JSON.stringify(data.chunk[i])); + } + } + + if (hasNewLatestMessage) { + setRooms(roomInfo); + } + if (updatedMemberList) { + $("#members").empty(); + for (i=0; i<memberInfo.length; ++i) { + addMember(memberInfo[i]); + } + } + longpollEventStream(); + }).fail(function(err) { + setTimeout(longpollEventStream, 5000); + }); +}; + +// ************** Registration and Login ************** +var onLoggedIn = function(data) { + accountInfo = data; + longpollEventStream(); + getCurrentRoomList(); + $(".roomListDashboard").css({visibility: "visible"}); + $(".roomContents").css({visibility: "visible"}); + $(".signUp").css({display: "none"}); +}; + +$('.login').live('click', function() { + var user = $("#userLogin").val(); + var password = $("#passwordLogin").val(); + $.ajax({ + url: "http://localhost:8080/matrix/client/api/v1/login", + type: "POST", + contentType: "application/json; charset=utf-8", + data: JSON.stringify({ user: user, password: password, type: "m.login.password" }), + dataType: "json", + success: function(data) { + onLoggedIn(data); + }, + error: function(err) { + alert("Unable to login: is the home server running?"); + } + }); +}); + +$('.register').live('click', function() { + var user = $("#userReg").val(); + var password = $("#passwordReg").val(); + $.ajax({ + url: "http://localhost:8080/matrix/client/api/v1/register", + type: "POST", + contentType: "application/json; charset=utf-8", + data: JSON.stringify({ user_id: user, password: password }), + dataType: "json", + success: function(data) { + onLoggedIn(data); + }, + error: function(err) { + var msg = "Is the home server running?"; + var errJson = $.parseJSON(err.responseText); + if (errJson !== null) { + msg = errJson.error; + } + alert("Unable to register: "+msg); + } + }); +}); + +// ************** Creating a room ****************** +$('.createRoom').live('click', function() { + var roomAlias = $("#roomAlias").val(); + var data = {}; + if (roomAlias.length > 0) { + data.room_alias_name = roomAlias; + } + $.ajax({ + url: "http://localhost:8080/matrix/client/api/v1/rooms?access_token="+accountInfo.access_token, + type: "POST", + contentType: "application/json; charset=utf-8", + data: JSON.stringify(data), + dataType: "json", + success: function(response) { + $("#roomAlias").val(""); + response.membership = "join"; // you are automatically joined into every room you make. + response.latest_message = ""; + + roomInfo.push(response); + setRooms(roomInfo); + }, + error: function(err) { + alert(JSON.stringify($.parseJSON(err.responseText))); + } + }); +}); + +// ************** Getting current state ************** +var getCurrentRoomList = function() { + var url = "http://localhost:8080/matrix/client/api/v1/im/sync?access_token=" + accountInfo.access_token + "&from=END&to=START&limit=1"; + $.getJSON(url, function(data) { + for (var i=0; i<data.length; ++i) { + if ("messages" in data[i]) { + data[i].latest_message = data[i].messages.chunk[0].content.body; + } + } + roomInfo = data; + setRooms(roomInfo); + }).fail(function(err) { + alert(JSON.stringify($.parseJSON(err.responseText))); + }); +}; + +var loadRoomContent = function(roomId) { + console.log("loadRoomContent " + roomId); + viewingRoomId = roomId; + $("#roomName").text("Room: "+roomId); + $(".sendMessageForm").css({visibility: "visible"}); + getMessages(roomId); + getMemberList(roomId); +}; + +var getMessages = function(roomId) { + $("#messages").empty(); + var url = "http://localhost:8080/matrix/client/api/v1/rooms/" + roomId + "/messages/list?access_token=" + accountInfo.access_token + "&from=END&to=START&limit=10"; + $.getJSON(url, function(data) { + for (var i=data.chunk.length-1; i>=0; --i) { + addMessage(data.chunk[i]); + } + }); +}; + +var getMemberList = function(roomId) { + $("#members").empty(); + memberInfo = []; + var url = "http://localhost:8080/matrix/client/api/v1/rooms/" + roomId + "/members/list?access_token=" + accountInfo.access_token; + $.getJSON(url, function(data) { + for (var i=0; i<data.chunk.length; ++i) { + memberInfo.push(data.chunk[i]); + addMember(data.chunk[i]); + } + }); +}; + +// ************** Sending messages ************** +$('.sendMessage').live('click', function() { + if (viewingRoomId === undefined) { + alert("There is no room to send a message to!"); + return; + } + var body = $("#body").val(); + sendMessage(viewingRoomId, body); +}); + +var sendMessage = function(roomId, body) { + var msgId = $.now(); + + var url = "http://localhost:8080/matrix/client/api/v1/rooms/$roomid/messages/$user/$msgid?access_token=$token"; + url = url.replace("$token", accountInfo.access_token); + url = url.replace("$roomid", encodeURIComponent(roomId)); + url = url.replace("$user", encodeURIComponent(accountInfo.user_id)); + url = url.replace("$msgid", msgId); + + var data = { + msgtype: "m.text", + body: body + }; + + $.ajax({ + url: url, + type: "PUT", + contentType: "application/json; charset=utf-8", + data: JSON.stringify(data), + dataType: "json", + success: function(data) { + $("#body").val(""); + }, + error: function(err) { + alert(JSON.stringify($.parseJSON(err.responseText))); + } + }); +}; + +// ************** Navigation and DOM manipulation ************** +var setRooms = function(roomList) { + // wipe existing entries + $("#rooms").find("tr:gt(0)").remove(); + + var rows = ""; + for (var i=0; i<roomList.length; ++i) { + row = "<tr>" + + "<td>"+roomList[i].room_id+"</td>" + + "<td>"+roomList[i].membership+"</td>" + + "<td>"+roomList[i].latest_message+"</td>" + + "</tr>"; + rows += row; + } + + $("#rooms").append(rows); + + $('#rooms').find("tr").click(function(){ + var roomId = $(this).find('td:eq(0)').text(); + var membership = $(this).find('td:eq(1)').text(); + if (membership !== "join") { + console.log("Joining room " + roomId); + var url = "http://localhost:8080/matrix/client/api/v1/rooms/$roomid/members/$user/state?access_token=$token"; + url = url.replace("$token", accountInfo.access_token); + url = url.replace("$roomid", encodeURIComponent(roomId)); + url = url.replace("$user", encodeURIComponent(accountInfo.user_id)); + $.ajax({ + url: url, + type: "PUT", + contentType: "application/json; charset=utf-8", + data: JSON.stringify({membership: "join"}), + dataType: "json", + success: function(data) { + loadRoomContent(roomId); + getCurrentRoomList(); + }, + error: function(err) { + alert(JSON.stringify($.parseJSON(err.responseText))); + } + }); + } + else { + loadRoomContent(roomId); + } + }); +}; + +var addMessage = function(data) { + var row = "<tr>" + + "<td>"+data.user_id+"</td>" + + "<td>"+data.content.body+"</td>" + + "</tr>"; + $("#messages").append(row); +}; + +var addMember = function(data) { + var row = "<tr>" + + "<td>"+data.target_user_id+"</td>" + + "<td>"+data.content.membership+"</td>" + + "</tr>"; + $("#members").append(row); +}; + |