summary refs log tree commit diff
diff options
context:
space:
mode:
authorErik Johnston <erik@matrix.org>2014-08-21 11:00:59 +0100
committerErik Johnston <erik@matrix.org>2014-08-21 11:00:59 +0100
commitd12a7c3939520f41387387653a32d0e7962e4b71 (patch)
treeb3a4dae2dd4be00f37179944b34ebee3d233e223
parentMake event stream storage return all membership events about the user, regard... (diff)
parentAdded final jsfiddle: an example app demonstrating most of the c2s api. (diff)
downloadsynapse-d12a7c3939520f41387387653a32d0e7962e4b71.tar.xz
Merge branch 'master' of github.com:matrix-org/synapse into develop
-rw-r--r--docs/client-server/howto.rst13
-rw-r--r--jsfiddles/example_app/demo.css43
-rw-r--r--jsfiddles/example_app/demo.html56
-rw-r--r--jsfiddles/example_app/demo.js303
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);
+};
+