aboutsummaryrefslogtreecommitdiffstats
path: root/trunk/etherpad/src/static/js/pad_chat.js
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/etherpad/src/static/js/pad_chat.js')
-rw-r--r--trunk/etherpad/src/static/js/pad_chat.js295
1 files changed, 295 insertions, 0 deletions
diff --git a/trunk/etherpad/src/static/js/pad_chat.js b/trunk/etherpad/src/static/js/pad_chat.js
new file mode 100644
index 0000000..35903c2
--- /dev/null
+++ b/trunk/etherpad/src/static/js/pad_chat.js
@@ -0,0 +1,295 @@
+/**
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS-IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+var padchat = (function(){
+
+ var numToAuthorMap = [''];
+ var authorColorArray = [null];
+ var authorToNumMap = {};
+ var chatLinesByDay = []; // {day:'2009-06-17', lines: [...]}
+ var oldestHistoricalLine = 0;
+
+ var loadingMoreHistory = false;
+ var HISTORY_LINES_TO_LOAD_AT_A_TIME = 50;
+
+ function authorToNum(author, dontAddIfAbsent) {
+ if ((typeof authorToNumMap[author]) == "number") {
+ return authorToNumMap[author];
+ }
+ else if (dontAddIfAbsent) {
+ return -1;
+ }
+ else {
+ var n = numToAuthorMap.length;
+ numToAuthorMap.push(author);
+ authorToNumMap[author] = n;
+ return n;
+ }
+ }
+ function getDateNumCSSDayString(dateNum) {
+ var d = new Date(+dateNum);
+ var year = String(d.getFullYear());
+ var month = ("0"+String(d.getMonth()+1)).slice(-2);
+ var day = ("0"+String(d.getDate())).slice(-2);
+ return year+"-"+month+"-"+day;
+ }
+ function getDateNumHumanDayString(dateNum) {
+ var d = new Date(+dateNum);
+ var monthName = (["January", "February", "March",
+ "April", "May", "June", "July", "August", "September",
+ "October", "November", "December"])[d.getMonth()];
+ var dayOfMonth = d.getDate();
+ var year = d.getFullYear();
+ return monthName+" "+dayOfMonth+", "+year;
+ }
+ function ensureChatDay(time) {
+ var day = getDateNumCSSDayString(time);
+ var dayIndex = padutils.binarySearch(chatLinesByDay.length, function(n) {
+ return chatLinesByDay[n].day >= day;
+ });
+ if (dayIndex >= chatLinesByDay.length ||
+ chatLinesByDay[dayIndex].day != day) {
+ // add new day to chat display!
+
+ chatLinesByDay.splice(dayIndex, 0, {day: day, lines: []});
+ var dayHtml = '<div class="chatday" id="chatday'+day+'">'+
+ '<h2 class="dayheader">'+getDateNumHumanDayString(time)+
+ '</h2></div>';
+ var dayDivs = $("#chatlines .chatday");
+ if (dayIndex == dayDivs.length) {
+ $("#chatlines").append(dayHtml);
+ }
+ else {
+ dayDivs.eq(dayIndex).before(dayHtml);
+ }
+ }
+
+ return dayIndex;
+ }
+ function addChatLine(userId, time, name, lineText, addBefore) {
+ var dayIndex = ensureChatDay(time);
+ var dayDiv = $("#chatday"+getDateNumCSSDayString(time));
+ var d = new Date(+time);
+ var hourmin = d.getHours()+":"+("0"+d.getMinutes()).slice(-2);
+ var nameHtml;
+ if (name) {
+ nameHtml = padutils.escapeHtml(name);
+ }
+ else {
+ nameHtml = "<i>unnamed</i>";
+ }
+ var chatlineClass = "chatline";
+ if (userId) {
+ var authorNum = authorToNum(userId);
+ chatlineClass += " chatauthor"+authorNum;
+ }
+ var textHtml = padutils.escapeHtmlWithClickableLinks(lineText, '_blank');
+ var lineNode = $('<div class="'+chatlineClass+'">'+
+ '<span class="chatlinetime">'+hourmin+' </span>'+
+ '<span class="chatlinename">'+nameHtml+': </span>'+
+ '<span class="chatlinetext">'+textHtml+'</span></div>');
+ var linesArray = chatLinesByDay[dayIndex].lines;
+ var lineObj = {userId:userId, time:time, name:name, lineText:lineText};
+ if (addBefore) {
+ dayDiv.find("h2").after(lineNode);
+ linesArray.splice(0, 0, lineObj);
+ }
+ else {
+ dayDiv.append(lineNode);
+ linesArray.push(lineObj);
+ }
+ if (userId) {
+ var color = getAuthorCSSColor(userId);
+ if (color) {
+ lineNode.css('background', color);
+ }
+ }
+
+ return {lineNode:lineNode};
+ }
+ function receiveChatHistoryBlock(block) {
+ for(var a in block.historicalAuthorData) {
+ var data = block.historicalAuthorData[a];
+ var n = authorToNum(a);
+ if (! authorColorArray[n]) {
+ // no data about this author, use historical info
+ authorColorArray[n] = { colorId: data.colorId, faded: true };
+ }
+ }
+
+ oldestHistoricalLine = block.start;
+
+ var lines = block.lines;
+ for(var i=lines.length-1; i>=0; i--) {
+ var line = lines[i];
+ addChatLine(line.userId, line.time, line.name, line.lineText, true);
+ }
+
+ if (oldestHistoricalLine > 0) {
+ $("a#chatloadmore").css('display', 'block');
+ }
+ else {
+ $("a#chatloadmore").css('display', 'none');
+ }
+ }
+ function fadeColor(colorCSS) {
+ var color = colorutils.css2triple(colorCSS);
+ color = colorutils.blend(color, [1,1,1], 0.5);
+ return colorutils.triple2css(color);
+ }
+ function getAuthorCSSColor(author) {
+ var n = authorToNum(author, true);
+ if (n < 0) {
+ return '';
+ }
+ else {
+ var cdata = authorColorArray[n];
+ if (! cdata) {
+ return '';
+ }
+ else {
+ var c = pad.getColorPalette()[cdata.colorId];
+ if (cdata.faded) {
+ c = fadeColor(c);
+ }
+ return c;
+ }
+ }
+ }
+ function changeAuthorColorData(author, cdata) {
+ var n = authorToNum(author);
+ authorColorArray[n] = cdata;
+ var cssColor = getAuthorCSSColor(author);
+ if (cssColor) {
+ $("#chatlines .chatauthor"+n).css('background',cssColor);
+ }
+ }
+
+ function sendChat() {
+ var lineText = $("#chatentrybox").val();
+ if (lineText) {
+ $("#chatentrybox").val('').focus();
+ var msg = {
+ type: 'chat',
+ userId: pad.getUserId(),
+ lineText: lineText,
+ senderName: pad.getUserName(),
+ authId: pad.getUserId()
+ };
+ pad.sendClientMessage(msg);
+ self.receiveChat(msg);
+ self.scrollToBottom();
+ }
+ }
+
+ var self = {
+ init: function(chatHistoryBlock, initialUserInfo) {
+ ensureChatDay(+new Date); // so that current date shows up right away
+
+ $("a#chatloadmore").click(self.loadMoreHistory);
+
+ self.handleUserJoinOrUpdate(initialUserInfo);
+ receiveChatHistoryBlock(chatHistoryBlock);
+
+ padutils.bindEnterAndEscape($("#chatentrybox"), function(evt) {
+ // return/enter
+ sendChat();
+ }, null);
+
+ self.scrollToBottom();
+ },
+ receiveChat: function(msg) {
+ var box = $("#chatlines").get(0);
+ var wasAtBottom = (box.scrollTop -
+ (box.scrollHeight - $(box).height()) >= -5);
+ addChatLine(msg.userId, +new Date, msg.senderName, msg.lineText, false);
+ if (wasAtBottom) {
+ window.setTimeout(function() {
+ self.scrollToBottom();
+ }, 0);
+ }
+ },
+ handleUserJoinOrUpdate: function(userInfo) {
+ changeAuthorColorData(userInfo.userId,
+ { colorId: userInfo.colorId, faded: false });
+ },
+ handleUserLeave: function(userInfo) {
+ changeAuthorColorData(userInfo.userId,
+ { colorId: userInfo.colorId, faded: true });
+ },
+ scrollToBottom: function() {
+ var box = $("#chatlines").get(0);
+ box.scrollTop = box.scrollHeight;
+ },
+ scrollToTop: function() {
+ var box = $("#chatlines").get(0);
+ box.scrollTop = 0;
+ },
+ loadMoreHistory: function() {
+ if (loadingMoreHistory) {
+ return;
+ }
+
+ var end = oldestHistoricalLine;
+ var start = Math.max(0, end - HISTORY_LINES_TO_LOAD_AT_A_TIME);
+ var padId = pad.getPadId();
+
+ loadingMoreHistory = true;
+ $("#padchat #chatloadmore").css('display', 'none');
+ $("#padchat #chatloadingmore").css('display', 'block');
+
+ $.ajax({
+ type: 'get',
+ url: '/ep/pad/chathistory',
+ data: { padId: padId, start: start, end: end },
+ success: success,
+ error: error
+ });
+
+ function success(text) {
+ notLoading();
+
+ var result = JSON.parse(text);
+
+ // try to keep scrolled to the same place...
+ var scrollBox = $("#chatlines").get(0);
+ var scrollDeterminer = function() { return 0; };
+ var topLine = $("#chatlines .chatday:first .chatline:first").children().eq(0);
+ if (topLine.length > 0) {
+ var posTop = topLine.position().top;
+ var scrollTop = scrollBox.scrollTop;
+ scrollDeterminer = function() {
+ var newPosTop = topLine.position().top;
+ return newPosTop + (scrollTop - posTop);
+ };
+ }
+ receiveChatHistoryBlock(result);
+
+ scrollBox.scrollTop = Math.max(0, Math.min(scrollBox.scrollHeight, scrollDeterminer()));
+ }
+ function error() {
+ notLoading();
+ }
+ function notLoading() {
+ loadingMoreHistory = false;
+ $("#padchat #chatloadmore").css('display', 'block');
+ $("#padchat #chatloadingmore").css('display', 'none');
+ }
+ }
+ };
+ return self;
+}()); \ No newline at end of file