summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn McLear <john@mclear.co.uk>2013-01-13 10:31:45 -0800
committerJohn McLear <john@mclear.co.uk>2013-01-13 10:31:45 -0800
commit33e0ec209779ed04960718782ac32f122ad42726 (patch)
tree90852901d26379fef7bf3d4a05160bfe47906cb6
parent6104987a4bae71f23fc237ac1651af195ce323b8 (diff)
parent21b99ccd53623439739929cc389e7330c66e7ede (diff)
downloadetherpad-lite-33e0ec209779ed04960718782ac32f122ad42726.zip
Merge pull request #1334 from mluto/load-more-chat-messages
Load more than 100 chat messages using a 'load more'-link
-rw-r--r--src/locales/de.json1
-rw-r--r--src/locales/en.json2
-rw-r--r--src/node/db/Pad.js26
-rw-r--r--src/node/handler/PadMessageHandler.js106
-rw-r--r--src/static/css/pad.css16
-rw-r--r--src/static/js/chat.js36
-rw-r--r--src/static/js/collab_client.js24
-rw-r--r--src/static/js/pad.js12
-rw-r--r--src/templates/pad.html5
-rw-r--r--tests/frontend/specs/chat_load_messages.js85
10 files changed, 256 insertions, 57 deletions
diff --git a/src/locales/de.json b/src/locales/de.json
index 5ede40f0..1bdbdaf3 100644
--- a/src/locales/de.json
+++ b/src/locales/de.json
@@ -81,6 +81,7 @@
"pad.share.emebdcode": "In Webseite einbetten",
"pad.chat": "Chat",
"pad.chat.title": "Den Chat dieses Pads \u00f6ffnen",
+ "pad.chat.loadmessages": "Weitere Nachrichten laden",
"timeslider.pageTitle": "{{appTitle}} Pad-Versionsgeschichte",
"timeslider.toolbar.returnbutton": "Zur\u00fcck zum Pad",
"timeslider.toolbar.authors": "Autoren:",
diff --git a/src/locales/en.json b/src/locales/en.json
index c3ab8c58..37e07a15 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -1 +1 @@
-{"index.newPad":"New Pad","index.createOpenPad":"or create/open a Pad with the name:","pad.toolbar.bold.title":"Bold (Ctrl-B)","pad.toolbar.italic.title":"Italic (Ctrl-I)","pad.toolbar.underline.title":"Underline (Ctrl-U)","pad.toolbar.strikethrough.title":"Strikethrough","pad.toolbar.ol.title":"Ordered list","pad.toolbar.ul.title":"Unordered List","pad.toolbar.indent.title":"Indent","pad.toolbar.unindent.title":"Outdent","pad.toolbar.undo.title":"Undo (Ctrl-Z)","pad.toolbar.redo.title":"Redo (Ctrl-Y)","pad.toolbar.clearAuthorship.title":"Clear Authorship Colors","pad.toolbar.import_export.title":"Import/Export from/to different file formats","pad.toolbar.timeslider.title":"Timeslider","pad.toolbar.savedRevision.title":"Saved Revisions","pad.toolbar.settings.title":"Settings","pad.toolbar.embed.title":"Embed this pad","pad.toolbar.showusers.title":"Show the users on this pad","pad.colorpicker.save":"Save","pad.colorpicker.cancel":"Cancel","pad.loading":"Loading...","pad.passwordRequired":"You need a password to access this pad","pad.permissionDenied":"You do not have permission to access this pad","pad.wrongPassword":"Your password was wrong","pad.settings.padSettings":"Pad Settings","pad.settings.myView":"My View","pad.settings.stickychat":"Chat always on screen","pad.settings.colorcheck":"Authorship colors","pad.settings.linenocheck":"Line numbers","pad.settings.fontType":"Font type:","pad.settings.fontType.normal":"Normal","pad.settings.fontType.monospaced":"Monospace","pad.settings.globalView":"Global View","pad.settings.language":"Language:","pad.importExport.import_export":"Import/Export","pad.importExport.import":"Upload any text file or document","pad.importExport.importSuccessful":"Successful!","pad.importExport.export":"Export current pad as:","pad.importExport.exporthtml":"HTML","pad.importExport.exportplain":"Plain text","pad.importExport.exportword":"Microsoft Word","pad.importExport.exportpdf":"PDF","pad.importExport.exportopen":"ODF (Open Document Format)","pad.importExport.exportdokuwiki":"DokuWiki","pad.importExport.abiword.innerHTML":"You only can import from plain text or html formats. For more advanced import features please <a href=\"https://github.com/ether/etherpad-lite/wiki/How-to-enable-importing-and-exporting-different-file-formats-in-Ubuntu-or-OpenSuse-or-SLES-with-AbiWord\">install abiword</a>.","pad.modals.connected":"Connected.","pad.modals.reconnecting":"Reconnecting to your pad..","pad.modals.forcereconnect":"Force reconnect","pad.modals.userdup":"Opened in another window","pad.modals.userdup.explanation":"This pad seems to be opened in more than one browser window on this computer.","pad.modals.userdup.advice":"Reconnect to use this window instead.","pad.modals.unauth":"Not authorized","pad.modals.unauth.explanation":"Your permissions have changed while viewing this page. Try to reconnect.","pad.modals.looping":"Disconnected.","pad.modals.looping.explanation":"There are communication problems with the synchronization server.","pad.modals.looping.cause":"Perhaps you connected through an incompatible firewall or proxy.","pad.modals.initsocketfail":"Server is unreachable.","pad.modals.initsocketfail.explanation":"Couldn't connect to the synchronization server.","pad.modals.initsocketfail.cause":"This is probably due to a problem with your browser or your internet connection.","pad.modals.slowcommit":"Disconnected.","pad.modals.slowcommit.explanation":"The server is not responding.","pad.modals.slowcommit.cause":"This could be due to problems with network connectivity.","pad.modals.deleted":"Deleted.","pad.modals.deleted.explanation":"This pad has been removed.","pad.modals.disconnected":"You have been disconnected.","pad.modals.disconnected.explanation":"The connection to the server was lost","pad.modals.disconnected.cause":"The server may be unavailable. Please notify us if this continues to happen.","pad.share":"Share this pad","pad.share.readonly":"Read only","pad.share.link":"Link","pad.share.emebdcode":"Embed URL","pad.chat":"Chat","pad.chat.title":"Open the chat for this pad.","timeslider.pageTitle":"{{appTitle}} Timeslider","timeslider.toolbar.returnbutton":"Return to pad","timeslider.toolbar.authors":"Authors:","timeslider.toolbar.authorsList":"No Authors","timeslider.toolbar.exportlink.title":"Export","timeslider.exportCurrent":"Export current version as:","timeslider.version":"Version {{version}}","timeslider.saved":"Saved {{month}} {{day}}, {{year}}","timeslider.dateformat":"{{month}}/{{day}}/{{year}} {{hours}}:{{minutes}}:{{seconds}}","timeslider.month.january":"January","timeslider.month.february":"February","timeslider.month.march":"March","timeslider.month.april":"April","timeslider.month.may":"May","timeslider.month.june":"June","timeslider.month.july":"July","timeslider.month.august":"August","timeslider.month.september":"September","timeslider.month.october":"October","timeslider.month.november":"November","timeslider.month.december":"December","pad.savedrevs.marked":"This revision is now marked as a saved revision","pad.userlist.entername":"Enter your name","pad.userlist.unnamed":"unnamed","pad.userlist.guest":"Guest","pad.userlist.deny":"Deny","pad.userlist.approve":"Approve","pad.editbar.clearcolors":"Clear authorship colors on entire document?","pad.impexp.importbutton":"Import Now","pad.impexp.importing":"Importing...","pad.impexp.confirmimport":"Importing a file will overwrite the current text of the pad. Are you sure you want to proceed?","pad.impexp.convertFailed":"We were not able to import this file. Please use a different document format or copy paste manually","pad.impexp.uploadFailed":"The upload failed, please try again","pad.impexp.importfailed":"Import failed","pad.impexp.copypaste":"Please copy paste","pad.impexp.exportdisabled":"Exporting as {{type}} format is disabled. Please contact your system administrator for details."} \ No newline at end of file
+{"index.newPad":"New Pad","index.createOpenPad":"or create/open a Pad with the name:","pad.toolbar.bold.title":"Bold (Ctrl-B)","pad.toolbar.italic.title":"Italic (Ctrl-I)","pad.toolbar.underline.title":"Underline (Ctrl-U)","pad.toolbar.strikethrough.title":"Strikethrough","pad.toolbar.ol.title":"Ordered list","pad.toolbar.ul.title":"Unordered List","pad.toolbar.indent.title":"Indent","pad.toolbar.unindent.title":"Outdent","pad.toolbar.undo.title":"Undo (Ctrl-Z)","pad.toolbar.redo.title":"Redo (Ctrl-Y)","pad.toolbar.clearAuthorship.title":"Clear Authorship Colors","pad.toolbar.import_export.title":"Import/Export from/to different file formats","pad.toolbar.timeslider.title":"Timeslider","pad.toolbar.savedRevision.title":"Saved Revisions","pad.toolbar.settings.title":"Settings","pad.toolbar.embed.title":"Embed this pad","pad.toolbar.showusers.title":"Show the users on this pad","pad.colorpicker.save":"Save","pad.colorpicker.cancel":"Cancel","pad.loading":"Loading...","pad.passwordRequired":"You need a password to access this pad","pad.permissionDenied":"You do not have permission to access this pad","pad.wrongPassword":"Your password was wrong","pad.settings.padSettings":"Pad Settings","pad.settings.myView":"My View","pad.settings.stickychat":"Chat always on screen","pad.settings.colorcheck":"Authorship colors","pad.settings.linenocheck":"Line numbers","pad.settings.fontType":"Font type:","pad.settings.fontType.normal":"Normal","pad.settings.fontType.monospaced":"Monospace","pad.settings.globalView":"Global View","pad.settings.language":"Language:","pad.importExport.import_export":"Import/Export","pad.importExport.import":"Upload any text file or document","pad.importExport.importSuccessful":"Successful!","pad.importExport.export":"Export current pad as:","pad.importExport.exporthtml":"HTML","pad.importExport.exportplain":"Plain text","pad.importExport.exportword":"Microsoft Word","pad.importExport.exportpdf":"PDF","pad.importExport.exportopen":"ODF (Open Document Format)","pad.importExport.exportdokuwiki":"DokuWiki","pad.importExport.abiword.innerHTML":"You only can import from plain text or html formats. For more advanced import features please <a href=\"https://github.com/ether/etherpad-lite/wiki/How-to-enable-importing-and-exporting-different-file-formats-in-Ubuntu-or-OpenSuse-or-SLES-with-AbiWord\">install abiword</a>.","pad.modals.connected":"Connected.","pad.modals.reconnecting":"Reconnecting to your pad..","pad.modals.forcereconnect":"Force reconnect","pad.modals.userdup":"Opened in another window","pad.modals.userdup.explanation":"This pad seems to be opened in more than one browser window on this computer.","pad.modals.userdup.advice":"Reconnect to use this window instead.","pad.modals.unauth":"Not authorized","pad.modals.unauth.explanation":"Your permissions have changed while viewing this page. Try to reconnect.","pad.modals.looping":"Disconnected.","pad.modals.looping.explanation":"There are communication problems with the synchronization server.","pad.modals.looping.cause":"Perhaps you connected through an incompatible firewall or proxy.","pad.modals.initsocketfail":"Server is unreachable.","pad.modals.initsocketfail.explanation":"Couldn't connect to the synchronization server.","pad.modals.initsocketfail.cause":"This is probably due to a problem with your browser or your internet connection.","pad.modals.slowcommit":"Disconnected.","pad.modals.slowcommit.explanation":"The server is not responding.","pad.modals.slowcommit.cause":"This could be due to problems with network connectivity.","pad.modals.deleted":"Deleted.","pad.modals.deleted.explanation":"This pad has been removed.","pad.modals.disconnected":"You have been disconnected.","pad.modals.disconnected.explanation":"The connection to the server was lost","pad.modals.disconnected.cause":"The server may be unavailable. Please notify us if this continues to happen.","pad.share":"Share this pad","pad.share.readonly":"Read only","pad.share.link":"Link","pad.share.emebdcode":"Embed URL","pad.chat":"Chat","pad.chat.title":"Open the chat for this pad.","pad.chat.loadmessages": "Load more messages","timeslider.pageTitle":"{{appTitle}} Timeslider","timeslider.toolbar.returnbutton":"Return to pad","timeslider.toolbar.authors":"Authors:","timeslider.toolbar.authorsList":"No Authors","timeslider.toolbar.exportlink.title":"Export","timeslider.exportCurrent":"Export current version as:","timeslider.version":"Version {{version}}","timeslider.saved":"Saved {{month}} {{day}}, {{year}}","timeslider.dateformat":"{{month}}/{{day}}/{{year}} {{hours}}:{{minutes}}:{{seconds}}","timeslider.month.january":"January","timeslider.month.february":"February","timeslider.month.march":"March","timeslider.month.april":"April","timeslider.month.may":"May","timeslider.month.june":"June","timeslider.month.july":"July","timeslider.month.august":"August","timeslider.month.september":"September","timeslider.month.october":"October","timeslider.month.november":"November","timeslider.month.december":"December","pad.savedrevs.marked":"This revision is now marked as a saved revision","pad.userlist.entername":"Enter your name","pad.userlist.unnamed":"unnamed","pad.userlist.guest":"Guest","pad.userlist.deny":"Deny","pad.userlist.approve":"Approve","pad.editbar.clearcolors":"Clear authorship colors on entire document?","pad.impexp.importbutton":"Import Now","pad.impexp.importing":"Importing...","pad.impexp.confirmimport":"Importing a file will overwrite the current text of the pad. Are you sure you want to proceed?","pad.impexp.convertFailed":"We were not able to import this file. Please use a different document format or copy paste manually","pad.impexp.uploadFailed":"The upload failed, please try again","pad.impexp.importfailed":"Import failed","pad.impexp.copypaste":"Please copy paste","pad.impexp.exportdisabled":"Exporting as {{type}} format is disabled. Please contact your system administrator for details."} \ No newline at end of file
diff --git a/src/node/db/Pad.js b/src/node/db/Pad.js
index dba791fd..0914c175 100644
--- a/src/node/db/Pad.js
+++ b/src/node/db/Pad.js
@@ -281,27 +281,7 @@ Pad.prototype.getChatMessage = function getChatMessage(entryNum, callback) {
});
};
-Pad.prototype.getLastChatMessages = function getLastChatMessages(count, callback) {
- //return an empty array if there are no chat messages
- if(this.chatHead == -1)
- {
- callback(null, []);
- return;
- }
-
- var _this = this;
-
- //works only if we decrement the amount, for some reason
- count--;
-
- //set the startpoint
- var start = this.chatHead-count;
- if(start < 0)
- start = 0;
-
- //set the endpoint
- var end = this.chatHead;
-
+Pad.prototype.getChatMessages = function getChatMessages(start, end, callback) {
//collect the numbers of chat entries and in which order we need them
var neededEntries = [];
var order = 0;
@@ -310,7 +290,9 @@ Pad.prototype.getLastChatMessages = function getLastChatMessages(count, callback
neededEntries.push({entryNum:i, order: order});
order++;
}
-
+
+ var _this = this;
+
//get all entries out of the database
var entries = [];
async.forEach(neededEntries, function(entryObject, callback)
diff --git a/src/node/handler/PadMessageHandler.js b/src/node/handler/PadMessageHandler.js
index a0bccfc5..a013f220 100644
--- a/src/node/handler/PadMessageHandler.js
+++ b/src/node/handler/PadMessageHandler.js
@@ -205,6 +205,8 @@ exports.handleMessage = function(client, message)
handleUserInfoUpdate(client, message);
} else if (message.data.type == "CHAT_MESSAGE") {
handleChatMessage(client, message);
+ } else if (message.data.type == "GET_CHAT_MESSAGES") {
+ handleGetChatMessages(client, message);
} else if (message.data.type == "SAVE_REVISION") {
handleSaveRevisionMessage(client, message);
} else if (message.data.type == "CLIENT_MESSAGE" &&
@@ -362,6 +364,74 @@ function handleChatMessage(client, message)
});
}
+/**
+ * Handles the clients request for more chat-messages
+ * @param client the client that send this message
+ * @param message the message from the client
+ */
+function handleGetChatMessages(client, message)
+{
+ if(message.data.start == null)
+ {
+ messageLogger.warn("Dropped message, GetChatMessages Message has no start!");
+ return;
+ }
+ if(message.data.end == null)
+ {
+ messageLogger.warn("Dropped message, GetChatMessages Message has no start!");
+ return;
+ }
+
+ var start = message.data.start;
+ var end = message.data.end;
+ var count = start - count;
+
+ if(count < 0 && count > 100)
+ {
+ messageLogger.warn("Dropped message, GetChatMessages Message, client requested invalid amout of messages!");
+ return;
+ }
+
+ var padId = sessioninfos[client.id].padId;
+ var pad;
+
+ async.series([
+ //get the pad
+ function(callback)
+ {
+ padManager.getPad(padId, function(err, _pad)
+ {
+ if(ERR(err, callback)) return;
+ pad = _pad;
+ callback();
+ });
+ },
+ function(callback)
+ {
+ pad.getChatMessages(start, end, function(err, chatMessages)
+ {
+ if(ERR(err, callback)) return;
+
+ var infoMsg = {
+ type: "COLLABROOM",
+ data: {
+ type: "CHAT_MESSAGES",
+ messages: chatMessages
+ }
+ };
+
+ // send the messages back to the client
+ for(var i in pad2sessions[padId])
+ {
+ if(pad2sessions[padId][i] == client.id)
+ {
+ socketio.sockets.sockets[pad2sessions[padId][i]].json.send(infoMsg);
+ break;
+ }
+ }
+ });
+ }]);
+}
/**
* Handles a handleSuggestUserName, that means a user have suggest a userName for a other user
@@ -778,19 +848,18 @@ function handleClientReady(client, message)
var pad;
var historicalAuthorData = {};
var currentTime;
- var chatMessages;
var padIds;
async.series([
- // Get ro/rw id:s
- function (callback) {
+ //Get ro/rw id:s
+ function (callback)
+ {
readOnlyManager.getIds(message.padId, function(err, value) {
if(ERR(err, callback)) return;
padIds = value;
callback();
});
},
-
//check permissions
function(callback)
{
@@ -816,7 +885,7 @@ function handleClientReady(client, message)
}
});
},
- //get all authordata of this new user
+ //get all authordata of this new user, and load the pad-object from the database
function(callback)
{
async.parallel([
@@ -840,6 +909,7 @@ function handleClientReady(client, message)
callback();
});
},
+ //get pad
function(callback)
{
padManager.getPad(padIds.padId, function(err, value)
@@ -851,7 +921,7 @@ function handleClientReady(client, message)
}
], callback);
},
- //these db requests all need the pad object
+ //these db requests all need the pad object (timestamp of latest revission, author data)
function(callback)
{
var authors = pad.getAllAuthors();
@@ -880,20 +950,11 @@ function handleClientReady(client, message)
callback();
});
}, callback);
- },
- //get the latest chat messages
- function(callback)
- {
- pad.getLastChatMessages(100, function(err, _chatMessages)
- {
- if(ERR(err, callback)) return;
- chatMessages = _chatMessages;
- callback();
- });
}
], callback);
},
+ //glue the clientVars together, send them and tell the other clients that a new one is there
function(callback)
{
//Check that the client is still here. It might have disconnected between callbacks.
@@ -966,7 +1027,9 @@ function handleClientReady(client, message)
"padId": message.padId,
"initialTitle": "Pad: " + message.padId,
"opts": {},
- "chatHistory": chatMessages,
+ // tell the client the number of the latest chat-message, which will be
+ // used to request the latest 100 chat-messages later (GET_CHAT_MESSAGES)
+ "chatHead": pad.chatHead,
"numConnectedUsers": pad2sessions[padIds.padId].length,
"isProPad": false,
"readOnlyId": padIds.readOnlyPadId,
@@ -980,11 +1043,10 @@ function handleClientReady(client, message)
},
"abiwordAvailable": settings.abiwordAvailable(),
"plugins": {
- "plugins": plugins.plugins,
- "parts": plugins.parts,
- },
- "initialChangesets": [] // FIXME: REMOVE THIS SHIT
-
+ "plugins": plugins.plugins,
+ "parts": plugins.parts,
+ },
+ "initialChangesets": [] // FIXME: REMOVE THIS SHIT
}
//Add a username to the clientVars if one avaiable
diff --git a/src/static/css/pad.css b/src/static/css/pad.css
index bb8da99b..bbbadbc1 100644
--- a/src/static/css/pad.css
+++ b/src/static/css/pad.css
@@ -488,6 +488,22 @@ table#otheruserstable {
-ms-overflow-x: hidden;
overflow-x: hidden;
}
+.chatloadmessages
+{
+ margin-bottom: 5px;
+ margin-top: 5px;
+ margin-left: auto;
+ margin-right: auto;
+ display: block;
+}
+#chatloadmessagesbutton
+{
+ line-height: 1.8em;
+}
+#chatloadmessagesball
+{
+ display: none;
+}
#chatinputbox {
padding: 3px 2px;
position: absolute;
diff --git a/src/static/js/chat.js b/src/static/js/chat.js
index 79224e80..01adc34e 100644
--- a/src/static/js/chat.js
+++ b/src/static/js/chat.js
@@ -28,6 +28,8 @@ var Tinycon = require('tinycon/tinycon');
var chat = (function()
{
var isStuck = false;
+ var gotInitialMessages = false;
+ var historyPointer = 0;
var chatMentions = 0;
var self = {
show: function ()
@@ -76,7 +78,7 @@ var chat = (function()
this._pad.collabClient.sendMessage({"type": "CHAT_MESSAGE", "text": text});
$("#chatinput").val("");
},
- addMessage: function(msg, increment)
+ addMessage: function(msg, increment, isHistoryAdd)
{
//correct the time
msg.time += this._pad.clientTimeOffset;
@@ -112,7 +114,10 @@ var chat = (function()
var authorName = msg.userName == null ? _('pad.userlist.unnamed') : padutils.escapeHtml(msg.userName);
var html = "<p class='" + authorClass + "'><b>" + authorName + ":</b><span class='time " + authorClass + "'>" + timeStr + "</span> " + text + "</p>";
- $("#chattext").append(html);
+ if(isHistoryAdd)
+ $(html).insertAfter('#chatloadmessagesbutton');
+ else
+ $("#chattext").append(html);
//should we increment the counter??
if(increment)
@@ -125,7 +130,7 @@ var chat = (function()
$("#chatcounter").text(count);
// chat throb stuff -- Just make it throw for twice as long
- if(wasMentioned && !alreadyFocused)
+ if(wasMentioned && !alreadyFocused && !isHistoryAdd)
{ // If the user was mentioned show for twice as long and flash the browser window
$('#chatthrob').html("<b>"+authorName+"</b>" + ": " + text).show().delay(4000).hide(400);
chatMentions++;
@@ -141,8 +146,8 @@ var chat = (function()
chatMentions = 0;
Tinycon.setBubble(0);
});
- self.scrollDown();
-
+ if(!isHistoryAdd)
+ self.scrollDown();
},
init: function(pad)
{
@@ -157,12 +162,23 @@ var chat = (function()
}
});
- var that = this;
- $.each(clientVars.chatHistory, function(i, o){
- that.addMessage(o, false);
- })
+ // initial messages are loaded in pad.js' _afterHandshake
+
+ $("#chatcounter").text(0);
+ $("#chatloadmessagesbutton").click(function()
+ {
+ var start = Math.max(self.historyPointer - 20, 0);
+ var end = self.historyPointer;
+
+ if(start == end) // nothing to load
+ return;
+
+ $("#chatloadmessagesbutton").css("display", "none");
+ $("#chatloadmessagesball").css("display", "block");
- $("#chatcounter").text(clientVars.chatHistory.length);
+ pad.collabClient.sendMessage({"type": "GET_CHAT_MESSAGES", "start": start, "end": end});
+ self.historyPointer = start;
+ });
}
}
diff --git a/src/static/js/collab_client.js b/src/static/js/collab_client.js
index b700fc49..7df0b711 100644
--- a/src/static/js/collab_client.js
+++ b/src/static/js/collab_client.js
@@ -400,7 +400,29 @@ function getCollabClient(ace2editor, serverVars, initialUserInfo, options, _pad)
}
else if (msg.type == "CHAT_MESSAGE")
{
- chat.addMessage(msg, true);
+ chat.addMessage(msg, true, false);
+ }
+ else if (msg.type == "CHAT_MESSAGES")
+ {
+ for(var i = msg.messages.length - 1; i >= 0; i--)
+ {
+ chat.addMessage(msg.messages[i], true, true);
+ }
+ if(!chat.gotInitalMessages)
+ {
+ chat.scrollDown();
+ chat.gotInitalMessages = true;
+ chat.historyPointer = clientVars.chatHead - msg.messages.length;
+ }
+
+ // messages are loaded, so hide the loading-ball
+ $("#chatloadmessagesball").css("display", "none");
+
+ // there are less than 100 messages or we reached the top
+ if(chat.historyPointer <= 0)
+ $("#chatloadmessagesbutton").css("display", "none");
+ else // there are still more messages, re-show the load-button
+ $("#chatloadmessagesbutton").css("display", "block");
}
else if (msg.type == "SERVER_MESSAGE")
{
diff --git a/src/static/js/pad.js b/src/static/js/pad.js
index a02d7abb..64d8b42b 100644
--- a/src/static/js/pad.js
+++ b/src/static/js/pad.js
@@ -555,6 +555,18 @@ var pad = {
pad.collabClient.setOnChannelStateChange(pad.handleChannelStateChange);
pad.collabClient.setOnInternalAction(pad.handleCollabAction);
+ // load initial chat-messages
+ if(clientVars.chatHead != -1)
+ {
+ var chatHead = clientVars.chatHead;
+ var start = Math.max(chatHead - 100, 0);
+ pad.collabClient.sendMessage({"type": "GET_CHAT_MESSAGES", "start": start, "end": chatHead});
+ }
+ else // there are no messages
+ {
+ $("#chatloadmessagesbutton").css("display", "none");
+ }
+
function postAceInit()
{
padeditbar.init();
diff --git a/src/templates/pad.html b/src/templates/pad.html
index 92f6c1ae..a4de8ed8 100644
--- a/src/templates/pad.html
+++ b/src/templates/pad.html
@@ -368,7 +368,10 @@
<div id="chatbox">
<div id="titlebar"><span id ="titlelabel" data-l10n-id="pad.chat"></span><a id="titlecross" onClick="chat.hide();return false;">-&nbsp;</a></div>
- <div id="chattext" class="authorColors"></div>
+ <div id="chattext" class="authorColors">
+ <img alt="loading.." id="chatloadmessagesball" class="chatloadmessages" src="../static/img/loading.gif" align="top">
+ <button id="chatloadmessagesbutton" class="chatloadmessages" data-l10n-id="pad.chat.loadmessages"></button>
+ </div>
<div id="chatinputbox">
<form>
<input id="chatinput" type="text" maxlength="999">
diff --git a/tests/frontend/specs/chat_load_messages.js b/tests/frontend/specs/chat_load_messages.js
new file mode 100644
index 00000000..8dc98691
--- /dev/null
+++ b/tests/frontend/specs/chat_load_messages.js
@@ -0,0 +1,85 @@
+describe("chat-load-messages", function(){
+ it("creates a pad", function(done) {
+ helper.newPad(done);
+ });
+
+ it("adds a lot of messages", function(done) {
+ var inner$ = helper.padInner$;
+ var chrome$ = helper.padChrome$;
+ var chatButton = chrome$("#chaticon");
+ chatButton.click();
+ var chatInput = chrome$("#chatinput");
+ var chatText = chrome$("#chattext");
+
+ var messages = 140;
+ for(var i=1; i <= messages; i++) {
+ var num = ''+i;
+ if(num.length == 1)
+ num = '00'+num;
+ if(num.length == 2)
+ num = '0'+num;
+ chatInput.sendkeys('msg' + num);
+ chatInput.sendkeys('{enter}');
+ }
+ helper.waitFor(function(){
+ return chatText.children("p").length == messages;
+ }).always(function(){
+ expect(chatText.children("p").length).to.be(messages);
+ $('#iframe-container iframe')[0].contentWindow.location.reload();
+ done();
+ });
+ });
+
+ it("checks initial message count", function(done) {
+ var chatText;
+ var expectedCount = 101;
+ helper.waitFor(function(){
+ // wait for the frame to load
+ var chrome$ = $('#iframe-container iframe')[0].contentWindow.$;
+ if(!chrome$) // page not fully loaded
+ return false;
+
+ var chatButton = chrome$("#chaticon");
+ chatButton.click();
+ chatText = chrome$("#chattext");
+ return chatText.children("p").length == expectedCount;
+ }).always(function(){
+ expect(chatText.children("p").length).to.be(expectedCount);
+ done();
+ });
+ });
+
+ it("loads more messages", function(done) {
+ var expectedCount = 122;
+ var chrome$ = $('#iframe-container iframe')[0].contentWindow.$;
+ var chatButton = chrome$("#chaticon");
+ chatButton.click();
+ var chatText = chrome$("#chattext");
+ var loadMsgBtn = chrome$("#chatloadmessagesbutton");
+
+ loadMsgBtn.click();
+ helper.waitFor(function(){
+ return chatText.children("p").length == expectedCount;
+ }).always(function(){
+ expect(chatText.children("p").length).to.be(expectedCount);
+ done();
+ });
+ });
+
+ it("checks for button vanishing", function(done) {
+ var expectedDisplay = 'none';
+ var chrome$ = $('#iframe-container iframe')[0].contentWindow.$;
+ var chatButton = chrome$("#chaticon");
+ chatButton.click();
+ var chatText = chrome$("#chattext");
+ var loadMsgBtn = chrome$("#chatloadmessagesbutton");
+
+ loadMsgBtn.click();
+ helper.waitFor(function(){
+ return loadMsgBtn.css('display') == expectedDisplay;
+ }).always(function(){
+ expect(loadMsgBtn.css('display')).to.be(expectedDisplay);
+ done();
+ });
+ });
+});