mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-01-31 19:02:59 +01:00
added a Chat
This commit is contained in:
parent
51c4aff54b
commit
29878e648e
11 changed files with 506 additions and 26 deletions
|
@ -7,6 +7,7 @@ var AttributePoolFactory = require("../AttributePoolFactory");
|
|||
var db = require("../db").db;
|
||||
var async = require("async");
|
||||
var settings = require('../settings');
|
||||
var authorManager = require("../AuthorManager");
|
||||
|
||||
/**
|
||||
* Copied from the Etherpad source code. It converts Windows line breaks to Unix line breaks and convert Tabs to spaces
|
||||
|
@ -38,6 +39,11 @@ Class('Pad', {
|
|||
getterName : 'getHeadRevisionNumber'
|
||||
}, // head
|
||||
|
||||
chatHead : {
|
||||
is: 'rw',
|
||||
init: -1
|
||||
}, // chatHead
|
||||
|
||||
id : { is : 'r' }
|
||||
},
|
||||
|
||||
|
@ -52,7 +58,6 @@ Class('Pad', {
|
|||
|
||||
appendRevision : function(aChangeset, author)
|
||||
{
|
||||
|
||||
if(!author)
|
||||
author = '';
|
||||
|
||||
|
@ -77,7 +82,7 @@ Class('Pad', {
|
|||
}
|
||||
|
||||
db.set("pad:"+this.id+":revs:"+newRev, newRevData);
|
||||
db.set("pad:"+this.id, {atext: this.atext, pool: this.pool.toJsonable(), head: this.head});
|
||||
db.set("pad:"+this.id, {atext: this.atext, pool: this.pool.toJsonable(), head: this.head, chatHead: this.chatHead});
|
||||
}, //appendRevision
|
||||
|
||||
getRevisionChangeset : function(revNum, callback)
|
||||
|
@ -186,6 +191,99 @@ Class('Pad', {
|
|||
return this.atext.text;
|
||||
},
|
||||
|
||||
appendChatMessage: function(text, userId, time)
|
||||
{
|
||||
this.chatHead++;
|
||||
//save the chat entry in the database
|
||||
db.set("pad:"+this.id+":chat:"+this.chatHead, {"text": text, "userId": userId, "time": time});
|
||||
//save the new chat head
|
||||
db.setSub("pad:"+this.id, ["chatHead"], this.chatHead);
|
||||
},
|
||||
|
||||
getChatMessage: function(entryNum, withName, callback)
|
||||
{
|
||||
var _this = this;
|
||||
var entry;
|
||||
|
||||
async.series([
|
||||
//get the chat entry
|
||||
function(callback)
|
||||
{
|
||||
db.get("pad:"+_this.id+":chat:"+entryNum, function(err, _entry)
|
||||
{
|
||||
entry = _entry;
|
||||
callback(err);
|
||||
});
|
||||
},
|
||||
//add the authorName
|
||||
function(callback)
|
||||
{
|
||||
//skip if we don't need the authorName
|
||||
if(!withName)
|
||||
{
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
//get the authorName
|
||||
authorManager.getAuthorName(entry.userId, function(err, authorName)
|
||||
{
|
||||
entry.userName = authorName;
|
||||
callback(err);
|
||||
});
|
||||
}
|
||||
], function(err)
|
||||
{
|
||||
callback(err, entry);
|
||||
});
|
||||
},
|
||||
|
||||
getLastChatMessages: function(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;
|
||||
|
||||
//collect the numbers of chat entries and in which order we need them
|
||||
var neededEntries = [];
|
||||
var order = 0;
|
||||
for(var i=start;i<=end; i++)
|
||||
{
|
||||
neededEntries.push({entryNum:i, order: order});
|
||||
order++;
|
||||
}
|
||||
|
||||
//get all entries out of the database
|
||||
var entries = [];
|
||||
async.forEach(neededEntries, function(entryObject, callback)
|
||||
{
|
||||
_this.getChatMessage(entryObject.entryNum, true, function(err, entry)
|
||||
{
|
||||
entries[entryObject.order] = entry;
|
||||
callback(err);
|
||||
});
|
||||
}, function(err)
|
||||
{
|
||||
callback(err, entries);
|
||||
});
|
||||
},
|
||||
|
||||
init : function (callback)
|
||||
{
|
||||
var _this = this;
|
||||
|
@ -205,6 +303,11 @@ Class('Pad', {
|
|||
_this.head = value.head;
|
||||
_this.atext = value.atext;
|
||||
_this.pool = _this.pool.fromJsonable(value.pool);
|
||||
|
||||
if(value.chatHead != null)
|
||||
_this.chatHead = value.chatHead;
|
||||
else
|
||||
_this.chatHead = -1;
|
||||
}
|
||||
//this pad doesn't exist, so create it
|
||||
else
|
||||
|
|
|
@ -164,6 +164,11 @@ exports.handleMessage = function(client, message)
|
|||
{
|
||||
handleUserInfoUpdate(client, message);
|
||||
}
|
||||
else if(message.type == "COLLABROOM" &&
|
||||
message.data.type == "CHAT_MESSAGE")
|
||||
{
|
||||
handleChatMessage(client, message);
|
||||
}
|
||||
else if(message.type == "COLLABROOM" &&
|
||||
message.data.type == "CLIENT_MESSAGE" &&
|
||||
message.data.payload.type == "suggestUserName")
|
||||
|
@ -177,6 +182,71 @@ exports.handleMessage = function(client, message)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a Chat Message
|
||||
* @param client the client that send this message
|
||||
* @param message the message from the client
|
||||
*/
|
||||
function handleChatMessage(client, message)
|
||||
{
|
||||
var time = new Date().getTime();
|
||||
var userId = sessioninfos[client.id].author;
|
||||
var text = message.data.text;
|
||||
var padId = session2pad[client.id];
|
||||
|
||||
var pad;
|
||||
var userName;
|
||||
|
||||
async.series([
|
||||
//get the pad
|
||||
function(callback)
|
||||
{
|
||||
padManager.getPad(padId, function(err, _pad)
|
||||
{
|
||||
pad = _pad;
|
||||
callback(err);
|
||||
});
|
||||
},
|
||||
function(callback)
|
||||
{
|
||||
authorManager.getAuthorName(userId, function(err, _userName)
|
||||
{
|
||||
userName = _userName;
|
||||
callback(err);
|
||||
});
|
||||
},
|
||||
//save the chat message and broadcast it
|
||||
function(callback)
|
||||
{
|
||||
//save the chat message
|
||||
pad.appendChatMessage(text, userId, time);
|
||||
|
||||
var msg = {
|
||||
type: "COLLABROOM",
|
||||
data: {
|
||||
type: "CHAT_MESSAGE",
|
||||
userId: userId,
|
||||
userName: userName,
|
||||
time: time,
|
||||
text: text
|
||||
}
|
||||
};
|
||||
|
||||
//broadcast the chat message to everyone on the pad
|
||||
for(var i in pad2sessions[padId])
|
||||
{
|
||||
socketio.sockets.sockets[pad2sessions[padId][i]].json.send(msg);
|
||||
}
|
||||
|
||||
callback();
|
||||
}
|
||||
], function(err)
|
||||
{
|
||||
if(err) throw err;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handles a handleSuggestUserName, that means a user have suggest a userName for a other user
|
||||
* @param client the client that send this message
|
||||
|
@ -509,6 +579,7 @@ function handleClientReady(client, message)
|
|||
var pad;
|
||||
var historicalAuthorData = {};
|
||||
var readOnlyId;
|
||||
var chatMessages;
|
||||
|
||||
async.series([
|
||||
//get all authordata of this new user
|
||||
|
@ -557,19 +628,36 @@ function handleClientReady(client, message)
|
|||
], callback);
|
||||
});
|
||||
},
|
||||
//these db requests all need the pad object
|
||||
function(callback)
|
||||
{
|
||||
var authors = pad.getAllAuthors();
|
||||
|
||||
//get all author data out of the database
|
||||
async.forEach(authors, function(authorId, callback)
|
||||
{
|
||||
authorManager.getAuthor(authorId, function(err, author)
|
||||
async.parallel([
|
||||
//get all author data out of the database
|
||||
function(callback)
|
||||
{
|
||||
historicalAuthorData[authorId] = author;
|
||||
callback(err);
|
||||
});
|
||||
}, callback);
|
||||
async.forEach(authors, function(authorId, callback)
|
||||
{
|
||||
authorManager.getAuthor(authorId, function(err, author)
|
||||
{
|
||||
historicalAuthorData[authorId] = author;
|
||||
callback(err);
|
||||
});
|
||||
}, callback);
|
||||
},
|
||||
//get the latest chat messages
|
||||
function(callback)
|
||||
{
|
||||
pad.getLastChatMessages(20, function(err, _chatMessages)
|
||||
{
|
||||
chatMessages = _chatMessages;
|
||||
callback(err);
|
||||
});
|
||||
}
|
||||
], callback);
|
||||
|
||||
|
||||
},
|
||||
function(callback)
|
||||
{
|
||||
|
@ -629,12 +717,7 @@ function handleClientReady(client, message)
|
|||
"padId": message.padId,
|
||||
"initialTitle": "Pad: " + message.padId,
|
||||
"opts": {},
|
||||
"chatHistory": {
|
||||
"start": 0,
|
||||
"historicalAuthorData": historicalAuthorData,
|
||||
"end": 0,
|
||||
"lines": []
|
||||
},
|
||||
"chatHistory": chatMessages,
|
||||
"numConnectedUsers": pad2sessions[message.padId].length,
|
||||
"isProPad": false,
|
||||
"readOnlyId": readOnlyId,
|
||||
|
|
|
@ -39,7 +39,7 @@ exports.padJS = function(req, res)
|
|||
{
|
||||
res.header("Content-Type","text/javascript");
|
||||
|
||||
var jsFiles = ["jquery.min.js", "plugins.js", "undo-xpopup.js", "json2.js", "pad_utils.js", "pad_cookie.js", "pad_editor.js", "pad_editbar.js", "pad_docbar.js", "pad_modals.js", "ace.js", "collab_client.js", "pad_userlist.js", "pad_impexp.js", "pad_savedrevs.js", "pad_connectionstatus.js", "pad2.js"];
|
||||
var jsFiles = ["jquery.min.js", "plugins.js", "undo-xpopup.js", "json2.js", "pad_utils.js", "pad_cookie.js", "pad_editor.js", "pad_editbar.js", "pad_docbar.js", "pad_modals.js", "ace.js", "collab_client.js", "pad_userlist.js", "pad_impexp.js", "pad_savedrevs.js", "pad_connectionstatus.js", "pad2.js", "jquery-ui-slide.js", "chat.js"];
|
||||
|
||||
//minifying is enabled
|
||||
if(settings.minify)
|
||||
|
|
|
@ -1186,3 +1186,120 @@ padding-left:4px;
|
|||
padding-right:4px;
|
||||
padding-top:2px;
|
||||
}*/
|
||||
|
||||
#chatbox
|
||||
{
|
||||
position:absolute;
|
||||
bottom:0px;
|
||||
right: 20px;
|
||||
width: 180px;
|
||||
height: 200px;
|
||||
z-index: 400;
|
||||
background-color:#f3f7f9;
|
||||
border-left: 1px solid #999;
|
||||
border-right: 1px solid #999;
|
||||
border-top: 1px solid #999;
|
||||
padding: 3px;
|
||||
padding-bottom: 10px;
|
||||
border-top-left-radius: 5px;
|
||||
border-top-right-radius: 5px;
|
||||
display:none;
|
||||
}
|
||||
|
||||
#chattext
|
||||
{
|
||||
background-color: white;
|
||||
border: 1px solid white;
|
||||
overflow-y:scroll;
|
||||
height: 165px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
#chattext p
|
||||
{
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
#chatinputbox
|
||||
{
|
||||
padding: 3px 2px;
|
||||
}
|
||||
|
||||
#chatlabel
|
||||
{
|
||||
font-size:13px;
|
||||
line-height:16px;
|
||||
font-weight:bold;
|
||||
color:#555;
|
||||
text-decoration: none;
|
||||
position: relative;
|
||||
bottom: 3px;
|
||||
}
|
||||
|
||||
#chatinput
|
||||
{
|
||||
border: 1px solid #BBBBBB;
|
||||
width: 100%;
|
||||
float:right;
|
||||
}
|
||||
|
||||
#chaticon
|
||||
{
|
||||
z-index: 400;
|
||||
position:absolute;
|
||||
bottom:0px;
|
||||
right: 20px;
|
||||
padding: 5px;
|
||||
border-left: 1px solid #999;
|
||||
border-right: 1px solid #999;
|
||||
border-top: 1px solid #999;
|
||||
border-top-left-radius: 5px;
|
||||
border-top-right-radius: 5px;
|
||||
}
|
||||
|
||||
#chaticon a
|
||||
{
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#chatcounter
|
||||
{
|
||||
color:#555;
|
||||
font-size:9px;
|
||||
position:relative;
|
||||
bottom: 2px;
|
||||
}
|
||||
|
||||
#titlebar
|
||||
{
|
||||
line-height:16px;
|
||||
font-weight:bold;
|
||||
color:#555;
|
||||
position: relative;
|
||||
bottom: 2px;
|
||||
}
|
||||
|
||||
#titlelabel
|
||||
{
|
||||
font-size:13px;
|
||||
}
|
||||
|
||||
#titlecross
|
||||
{
|
||||
font-size:16px;
|
||||
float:right;
|
||||
text-align: right;
|
||||
text-decoration: none;
|
||||
color:#555;
|
||||
}
|
||||
|
||||
.time
|
||||
{
|
||||
float:right;
|
||||
color:#333;
|
||||
font-style:italic;
|
||||
font-size: 10px;
|
||||
margin-left: 3px;
|
||||
margin-right: 3px;
|
||||
margin-top:2px;
|
||||
}
|
||||
|
|
|
@ -138,10 +138,12 @@ function OUTER(gscope)
|
|||
}
|
||||
|
||||
var dynamicCSS = null;
|
||||
var dynamicCSSTop = null;
|
||||
|
||||
function initDynamicCSS()
|
||||
{
|
||||
dynamicCSS = makeCSSManager("dynamicsyntax");
|
||||
dynamicCSSTop = makeCSSManager("dynamicsyntax", true);
|
||||
}
|
||||
|
||||
var changesetTracker = makeChangesetTracker(scheduler, rep.apool, {
|
||||
|
@ -184,6 +186,7 @@ function OUTER(gscope)
|
|||
if (dynamicCSS)
|
||||
{
|
||||
dynamicCSS.removeSelectorStyle(getAuthorColorClassSelector(getAuthorClassName(author)));
|
||||
dynamicCSSTop.removeSelectorStyle(getAuthorColorClassSelector(getAuthorClassName(author)));
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -201,6 +204,9 @@ function OUTER(gscope)
|
|||
|
||||
dynamicCSS.selectorStyle(getAuthorColorClassSelector(
|
||||
getAuthorClassName(author))).backgroundColor = bgcolor;
|
||||
|
||||
dynamicCSSTop.selectorStyle(getAuthorColorClassSelector(
|
||||
getAuthorClassName(author))).backgroundColor = bgcolor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
94
static/js/chat.js
Normal file
94
static/js/chat.js
Normal file
|
@ -0,0 +1,94 @@
|
|||
var chat = (function()
|
||||
{
|
||||
var self = {
|
||||
show: function ()
|
||||
{
|
||||
$("#chaticon").hide("slide", { direction: "down" }, 500, function()
|
||||
{
|
||||
$("#chatbox").show("slide", { direction: "down" }, 750, self.scrollDown);
|
||||
});
|
||||
},
|
||||
hide: function ()
|
||||
{
|
||||
$("#chatcounter").text("0");
|
||||
$("#chatbox").hide("slide", { direction: "down" }, 750, function()
|
||||
{
|
||||
$("#chaticon").show("slide", { direction: "down" }, 500);
|
||||
});
|
||||
},
|
||||
scrollDown: function()
|
||||
{
|
||||
console.log($('#chatbox').css("display"));
|
||||
|
||||
if($('#chatbox').css("display") != "none")
|
||||
$('#chattext').animate({scrollTop: $('#chattext')[0].scrollHeight}, "slow");
|
||||
},
|
||||
send: function()
|
||||
{
|
||||
var text = $("#chatinput").val();
|
||||
pad.collabClient.sendMessage({"type": "CHAT_MESSAGE", "text": text});
|
||||
$("#chatinput").val("");
|
||||
},
|
||||
addMessage: function(msg, increment)
|
||||
{
|
||||
//correct the time
|
||||
msg.time += pad.clientTimeOffset;
|
||||
|
||||
//create the time string
|
||||
var minutes = "" + new Date(msg.time).getMinutes();
|
||||
var hours = "" + new Date(msg.time).getHours();
|
||||
if(minutes.length == 1)
|
||||
minutes = "0" + minutes ;
|
||||
if(hours.length == 1)
|
||||
hours = "0" + hours ;
|
||||
var timeStr = hours + ":" + minutes;
|
||||
|
||||
//create the authorclass
|
||||
var authorClass = "author-" + msg.userId.replace(/[^a-y0-9]/g, function(c)
|
||||
{
|
||||
if (c == ".") return "-";
|
||||
return 'z' + c.charCodeAt(0) + 'z';
|
||||
});
|
||||
|
||||
var text = padutils.escapeHtmlWithClickableLinks(padutils.escapeHtml(msg.text), "_blank");
|
||||
var authorName = msg.userName == null ? "unnamed" : padutils.escapeHtml(msg.userName);
|
||||
|
||||
var html = "<p class='" + authorClass + "'><b>" + authorName + ":</b><span class='time'>" + timeStr + "</span> " + text + "</p>";
|
||||
$("#chattext").append(html);
|
||||
|
||||
//should we increment the counter??
|
||||
if(increment)
|
||||
{
|
||||
var count = Number($("#chatcounter").text());
|
||||
count++;
|
||||
$("#chatcounter").text(count);
|
||||
|
||||
//animation
|
||||
$("#chatcounter").css({"font-weight": "bold"});
|
||||
setTimeout('$("#chatcounter").css({"font-weight": "normal"})', 500);
|
||||
}
|
||||
|
||||
self.scrollDown();
|
||||
},
|
||||
init: function()
|
||||
{
|
||||
$("#chatinput").keypress(function(evt)
|
||||
{
|
||||
//if the user typed enter, fire the send
|
||||
if(evt.which == 13)
|
||||
{
|
||||
evt.preventDefault();
|
||||
self.send();
|
||||
}
|
||||
});
|
||||
|
||||
for(var i in clientVars.chatHistory)
|
||||
{
|
||||
this.addMessage(clientVars.chatHistory[i], false);
|
||||
}
|
||||
$("#chatcounter").text(clientVars.chatHistory.length);
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
}());
|
|
@ -441,6 +441,10 @@ function getCollabClient(ace2editor, serverVars, initialUserInfo, options)
|
|||
{
|
||||
callbacks.onClientMessage(msg.payload);
|
||||
}
|
||||
else if (msg.type == "CHAT_MESSAGE")
|
||||
{
|
||||
chat.addMessage(msg, true);
|
||||
}
|
||||
else if (msg.type == "SERVER_MESSAGE")
|
||||
{
|
||||
callbacks.onServerMessage(msg.payload);
|
||||
|
@ -858,6 +862,7 @@ function getCollabClient(ace2editor, serverVars, initialUserInfo, options)
|
|||
handleMessageFromServer: handleMessageFromServer,
|
||||
getConnectedUsers: getConnectedUsers,
|
||||
sendClientMessage: sendClientMessage,
|
||||
sendMessage: sendMessage,
|
||||
getCurrentRevisionNumber: getCurrentRevisionNumber,
|
||||
getDiagnosticInfo: getDiagnosticInfo,
|
||||
getMissedChanges: getMissedChanges,
|
||||
|
|
|
@ -14,12 +14,16 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
function makeCSSManager(emptyStylesheetTitle)
|
||||
function makeCSSManager(emptyStylesheetTitle, top)
|
||||
{
|
||||
|
||||
function getSheetByTitle(title)
|
||||
function getSheetByTitle(title, top)
|
||||
{
|
||||
var allSheets = document.styleSheets;
|
||||
if(top)
|
||||
var allSheets = window.top.document.styleSheets;
|
||||
else
|
||||
var allSheets = document.styleSheets;
|
||||
|
||||
for (var i = 0; i < allSheets.length; i++)
|
||||
{
|
||||
var s = allSheets[i];
|
||||
|
@ -42,7 +46,7 @@ function makeCSSManager(emptyStylesheetTitle)
|
|||
return null;
|
||||
}*/
|
||||
|
||||
var browserSheet = getSheetByTitle(emptyStylesheetTitle);
|
||||
var browserSheet = getSheetByTitle(emptyStylesheetTitle, top);
|
||||
//var browserTag = getSheetTagByTitle(emptyStylesheetTitle);
|
||||
|
||||
|
||||
|
|
45
static/js/jquery-ui-slide.js
vendored
Normal file
45
static/js/jquery-ui-slide.js
vendored
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* jQuery UI Effects 1.8.14
|
||||
*
|
||||
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* http://docs.jquery.com/UI/Effects/
|
||||
*/
|
||||
jQuery.effects||function(f,j){function m(c){var a;if(c&&c.constructor==Array&&c.length==3)return c;if(a=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(c))return[parseInt(a[1],10),parseInt(a[2],10),parseInt(a[3],10)];if(a=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(c))return[parseFloat(a[1])*2.55,parseFloat(a[2])*2.55,parseFloat(a[3])*2.55];if(a=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(c))return[parseInt(a[1],
|
||||
16),parseInt(a[2],16),parseInt(a[3],16)];if(a=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(c))return[parseInt(a[1]+a[1],16),parseInt(a[2]+a[2],16),parseInt(a[3]+a[3],16)];if(/rgba\(0, 0, 0, 0\)/.exec(c))return n.transparent;return n[f.trim(c).toLowerCase()]}function s(c,a){var b;do{b=f.curCSS(c,a);if(b!=""&&b!="transparent"||f.nodeName(c,"body"))break;a="backgroundColor"}while(c=c.parentNode);return m(b)}function o(){var c=document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle,
|
||||
a={},b,d;if(c&&c.length&&c[0]&&c[c[0]])for(var e=c.length;e--;){b=c[e];if(typeof c[b]=="string"){d=b.replace(/\-(\w)/g,function(g,h){return h.toUpperCase()});a[d]=c[b]}}else for(b in c)if(typeof c[b]==="string")a[b]=c[b];return a}function p(c){var a,b;for(a in c){b=c[a];if(b==null||f.isFunction(b)||a in t||/scrollbar/.test(a)||!/color/i.test(a)&&isNaN(parseFloat(b)))delete c[a]}return c}function u(c,a){var b={_:0},d;for(d in a)if(c[d]!=a[d])b[d]=a[d];return b}function k(c,a,b,d){if(typeof c=="object"){d=
|
||||
a;b=null;a=c;c=a.effect}if(f.isFunction(a)){d=a;b=null;a={}}if(typeof a=="number"||f.fx.speeds[a]){d=b;b=a;a={}}if(f.isFunction(b)){d=b;b=null}a=a||{};b=b||a.duration;b=f.fx.off?0:typeof b=="number"?b:b in f.fx.speeds?f.fx.speeds[b]:f.fx.speeds._default;d=d||a.complete;return[c,a,b,d]}function l(c){if(!c||typeof c==="number"||f.fx.speeds[c])return true;if(typeof c==="string"&&!f.effects[c])return true;return false}f.effects={};f.each(["backgroundColor","borderBottomColor","borderLeftColor","borderRightColor",
|
||||
"borderTopColor","borderColor","color","outlineColor"],function(c,a){f.fx.step[a]=function(b){if(!b.colorInit){b.start=s(b.elem,a);b.end=m(b.end);b.colorInit=true}b.elem.style[a]="rgb("+Math.max(Math.min(parseInt(b.pos*(b.end[0]-b.start[0])+b.start[0],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[1]-b.start[1])+b.start[1],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[2]-b.start[2])+b.start[2],10),255),0)+")"}});var n={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,
|
||||
0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,
|
||||
211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0],transparent:[255,255,255]},q=["add","remove","toggle"],t={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};f.effects.animateClass=function(c,a,b,
|
||||
d){if(f.isFunction(b)){d=b;b=null}return this.queue(function(){var e=f(this),g=e.attr("style")||" ",h=p(o.call(this)),r,v=e.attr("class");f.each(q,function(w,i){c[i]&&e[i+"Class"](c[i])});r=p(o.call(this));e.attr("class",v);e.animate(u(h,r),{queue:false,duration:a,easing:b,complete:function(){f.each(q,function(w,i){c[i]&&e[i+"Class"](c[i])});if(typeof e.attr("style")=="object"){e.attr("style").cssText="";e.attr("style").cssText=g}else e.attr("style",g);d&&d.apply(this,arguments);f.dequeue(this)}})})};
|
||||
f.fn.extend({_addClass:f.fn.addClass,addClass:function(c,a,b,d){return a?f.effects.animateClass.apply(this,[{add:c},a,b,d]):this._addClass(c)},_removeClass:f.fn.removeClass,removeClass:function(c,a,b,d){return a?f.effects.animateClass.apply(this,[{remove:c},a,b,d]):this._removeClass(c)},_toggleClass:f.fn.toggleClass,toggleClass:function(c,a,b,d,e){return typeof a=="boolean"||a===j?b?f.effects.animateClass.apply(this,[a?{add:c}:{remove:c},b,d,e]):this._toggleClass(c,a):f.effects.animateClass.apply(this,
|
||||
[{toggle:c},a,b,d])},switchClass:function(c,a,b,d,e){return f.effects.animateClass.apply(this,[{add:a,remove:c},b,d,e])}});f.extend(f.effects,{version:"1.8.14",save:function(c,a){for(var b=0;b<a.length;b++)a[b]!==null&&c.data("ec.storage."+a[b],c[0].style[a[b]])},restore:function(c,a){for(var b=0;b<a.length;b++)a[b]!==null&&c.css(a[b],c.data("ec.storage."+a[b]))},setMode:function(c,a){if(a=="toggle")a=c.is(":hidden")?"show":"hide";return a},getBaseline:function(c,a){var b;switch(c[0]){case "top":b=
|
||||
0;break;case "middle":b=0.5;break;case "bottom":b=1;break;default:b=c[0]/a.height}switch(c[1]){case "left":c=0;break;case "center":c=0.5;break;case "right":c=1;break;default:c=c[1]/a.width}return{x:c,y:b}},createWrapper:function(c){if(c.parent().is(".ui-effects-wrapper"))return c.parent();var a={width:c.outerWidth(true),height:c.outerHeight(true),"float":c.css("float")},b=f("<div></div>").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0});
|
||||
c.wrap(b);b=c.parent();if(c.css("position")=="static"){b.css({position:"relative"});c.css({position:"relative"})}else{f.extend(a,{position:c.css("position"),zIndex:c.css("z-index")});f.each(["top","left","bottom","right"],function(d,e){a[e]=c.css(e);if(isNaN(parseInt(a[e],10)))a[e]="auto"});c.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})}return b.css(a).show()},removeWrapper:function(c){if(c.parent().is(".ui-effects-wrapper"))return c.parent().replaceWith(c);return c},setTransition:function(c,
|
||||
a,b,d){d=d||{};f.each(a,function(e,g){unit=c.cssUnit(g);if(unit[0]>0)d[g]=unit[0]*b+unit[1]});return d}});f.fn.extend({effect:function(c){var a=k.apply(this,arguments),b={options:a[1],duration:a[2],callback:a[3]};a=b.options.mode;var d=f.effects[c];if(f.fx.off||!d)return a?this[a](b.duration,b.callback):this.each(function(){b.callback&&b.callback.call(this)});return d.call(this,b)},_show:f.fn.show,show:function(c){if(l(c))return this._show.apply(this,arguments);else{var a=k.apply(this,arguments);
|
||||
a[1].mode="show";return this.effect.apply(this,a)}},_hide:f.fn.hide,hide:function(c){if(l(c))return this._hide.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="hide";return this.effect.apply(this,a)}},__toggle:f.fn.toggle,toggle:function(c){if(l(c)||typeof c==="boolean"||f.isFunction(c))return this.__toggle.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="toggle";return this.effect.apply(this,a)}},cssUnit:function(c){var a=this.css(c),b=[];f.each(["em","px","%",
|
||||
"pt"],function(d,e){if(a.indexOf(e)>0)b=[parseFloat(a),e]});return b}});f.easing.jswing=f.easing.swing;f.extend(f.easing,{def:"easeOutQuad",swing:function(c,a,b,d,e){return f.easing[f.easing.def](c,a,b,d,e)},easeInQuad:function(c,a,b,d,e){return d*(a/=e)*a+b},easeOutQuad:function(c,a,b,d,e){return-d*(a/=e)*(a-2)+b},easeInOutQuad:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a+b;return-d/2*(--a*(a-2)-1)+b},easeInCubic:function(c,a,b,d,e){return d*(a/=e)*a*a+b},easeOutCubic:function(c,a,b,d,e){return d*
|
||||
((a=a/e-1)*a*a+1)+b},easeInOutCubic:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a+b;return d/2*((a-=2)*a*a+2)+b},easeInQuart:function(c,a,b,d,e){return d*(a/=e)*a*a*a+b},easeOutQuart:function(c,a,b,d,e){return-d*((a=a/e-1)*a*a*a-1)+b},easeInOutQuart:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a*a+b;return-d/2*((a-=2)*a*a*a-2)+b},easeInQuint:function(c,a,b,d,e){return d*(a/=e)*a*a*a*a+b},easeOutQuint:function(c,a,b,d,e){return d*((a=a/e-1)*a*a*a*a+1)+b},easeInOutQuint:function(c,a,b,d,e){if((a/=
|
||||
e/2)<1)return d/2*a*a*a*a*a+b;return d/2*((a-=2)*a*a*a*a+2)+b},easeInSine:function(c,a,b,d,e){return-d*Math.cos(a/e*(Math.PI/2))+d+b},easeOutSine:function(c,a,b,d,e){return d*Math.sin(a/e*(Math.PI/2))+b},easeInOutSine:function(c,a,b,d,e){return-d/2*(Math.cos(Math.PI*a/e)-1)+b},easeInExpo:function(c,a,b,d,e){return a==0?b:d*Math.pow(2,10*(a/e-1))+b},easeOutExpo:function(c,a,b,d,e){return a==e?b+d:d*(-Math.pow(2,-10*a/e)+1)+b},easeInOutExpo:function(c,a,b,d,e){if(a==0)return b;if(a==e)return b+d;if((a/=
|
||||
e/2)<1)return d/2*Math.pow(2,10*(a-1))+b;return d/2*(-Math.pow(2,-10*--a)+2)+b},easeInCirc:function(c,a,b,d,e){return-d*(Math.sqrt(1-(a/=e)*a)-1)+b},easeOutCirc:function(c,a,b,d,e){return d*Math.sqrt(1-(a=a/e-1)*a)+b},easeInOutCirc:function(c,a,b,d,e){if((a/=e/2)<1)return-d/2*(Math.sqrt(1-a*a)-1)+b;return d/2*(Math.sqrt(1-(a-=2)*a)+1)+b},easeInElastic:function(c,a,b,d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e)==1)return b+d;g||(g=e*0.3);if(h<Math.abs(d)){h=d;c=g/4}else c=g/(2*Math.PI)*Math.asin(d/
|
||||
h);return-(h*Math.pow(2,10*(a-=1))*Math.sin((a*e-c)*2*Math.PI/g))+b},easeOutElastic:function(c,a,b,d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e)==1)return b+d;g||(g=e*0.3);if(h<Math.abs(d)){h=d;c=g/4}else c=g/(2*Math.PI)*Math.asin(d/h);return h*Math.pow(2,-10*a)*Math.sin((a*e-c)*2*Math.PI/g)+d+b},easeInOutElastic:function(c,a,b,d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e/2)==2)return b+d;g||(g=e*0.3*1.5);if(h<Math.abs(d)){h=d;c=g/4}else c=g/(2*Math.PI)*Math.asin(d/h);if(a<1)return-0.5*
|
||||
h*Math.pow(2,10*(a-=1))*Math.sin((a*e-c)*2*Math.PI/g)+b;return h*Math.pow(2,-10*(a-=1))*Math.sin((a*e-c)*2*Math.PI/g)*0.5+d+b},easeInBack:function(c,a,b,d,e,g){if(g==j)g=1.70158;return d*(a/=e)*a*((g+1)*a-g)+b},easeOutBack:function(c,a,b,d,e,g){if(g==j)g=1.70158;return d*((a=a/e-1)*a*((g+1)*a+g)+1)+b},easeInOutBack:function(c,a,b,d,e,g){if(g==j)g=1.70158;if((a/=e/2)<1)return d/2*a*a*(((g*=1.525)+1)*a-g)+b;return d/2*((a-=2)*a*(((g*=1.525)+1)*a+g)+2)+b},easeInBounce:function(c,a,b,d,e){return d-f.easing.easeOutBounce(c,
|
||||
e-a,0,d,e)+b},easeOutBounce:function(c,a,b,d,e){return(a/=e)<1/2.75?d*7.5625*a*a+b:a<2/2.75?d*(7.5625*(a-=1.5/2.75)*a+0.75)+b:a<2.5/2.75?d*(7.5625*(a-=2.25/2.75)*a+0.9375)+b:d*(7.5625*(a-=2.625/2.75)*a+0.984375)+b},easeInOutBounce:function(c,a,b,d,e){if(a<e/2)return f.easing.easeInBounce(c,a*2,0,d,e)*0.5+b;return f.easing.easeOutBounce(c,a*2-e,0,d,e)*0.5+d*0.5+b}})}(jQuery);
|
||||
;/*
|
||||
* jQuery UI Effects Slide 1.8.14
|
||||
*
|
||||
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* http://docs.jquery.com/UI/Effects/Slide
|
||||
*
|
||||
* Depends:
|
||||
* jquery.effects.core.js
|
||||
*/
|
||||
(function(c){c.effects.slide=function(d){return this.queue(function(){var a=c(this),h=["position","top","bottom","left","right"],f=c.effects.setMode(a,d.options.mode||"show"),b=d.options.direction||"left";c.effects.save(a,h);a.show();c.effects.createWrapper(a).css({overflow:"hidden"});var g=b=="up"||b=="down"?"top":"left";b=b=="up"||b=="left"?"pos":"neg";var e=d.options.distance||(g=="top"?a.outerHeight({margin:true}):a.outerWidth({margin:true}));if(f=="show")a.css(g,b=="pos"?isNaN(e)?"-"+e:-e:e);
|
||||
var i={};i[g]=(f=="show"?b=="pos"?"+=":"-=":b=="pos"?"-=":"+=")+e;a.animate(i,{queue:false,duration:d.duration,easing:d.options.easing,complete:function(){f=="hide"&&a.hide();c.effects.restore(a,h);c.effects.removeWrapper(a);d.callback&&d.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery);
|
||||
;
|
|
@ -74,9 +74,7 @@ function handshake()
|
|||
//create the url
|
||||
var url = loc.protocol + "//" + loc.hostname + ":" + port + "/";
|
||||
//find out in which subfolder we are
|
||||
console.log(loc.pathname);
|
||||
var resource = loc.pathname.substr(1, loc.pathname.indexOf("/p/")) + "socket.io";
|
||||
console.log(resource);
|
||||
//connect
|
||||
socket = io.connect(url, {
|
||||
resource: resource
|
||||
|
@ -150,7 +148,7 @@ var pad = {
|
|||
myUserInfo: null,
|
||||
diagnosticInfo: {},
|
||||
initTime: 0,
|
||||
clientTimeOffset: (+new Date()) - clientVars.serverTimestamp,
|
||||
clientTimeOffset: null,
|
||||
preloadedImages: false,
|
||||
padOptions: {},
|
||||
|
||||
|
@ -203,6 +201,11 @@ var pad = {
|
|||
|
||||
init: function()
|
||||
{
|
||||
pad.clientTimeOffset = new Date().getTime() - clientVars.serverTimestamp;
|
||||
|
||||
//initialize the chat
|
||||
chat.init();
|
||||
|
||||
pad.diagnosticInfo.uniqueId = padutils.uniqueId();
|
||||
pad.initTime = +(new Date());
|
||||
pad.padOptions = clientVars.initialOptions;
|
||||
|
|
|
@ -21,6 +21,7 @@ var clientVars = {}; // ]]>
|
|||
|
||||
<script type="text/javascript" src="../socket.io/socket.io.js"></script>
|
||||
<script type="text/javascript" src="../minified/pad.js"></script>
|
||||
<style type="text/css" title="dynamicsyntax"></style>
|
||||
|
||||
</head>
|
||||
|
||||
|
@ -115,12 +116,12 @@ We removed this feature cause its not worth the space it needs in the editbar
|
|||
</select>
|
||||
</li>-->
|
||||
<li class="separator"></li>
|
||||
<li>
|
||||
<!--<li>
|
||||
<a href="javascript:void (window.pad&&pad.editbarClick('chat'));"
|
||||
title="(Placeholder, not implemented so far) Open the chat for this pad">
|
||||
<img src="../static/img/editbar_chat.gif" width="16" height="16" />
|
||||
</a>
|
||||
</li>
|
||||
</li>-->
|
||||
<li>
|
||||
<a id="timesliderlink" title="Show the history of this pad">
|
||||
<script>
|
||||
|
@ -216,6 +217,25 @@ Use this link to share a read-only version of your pad:<input id="readonlyInput"
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div id="chaticon">
|
||||
<a href="javascript:chat.show();"
|
||||
title="Open the chat for this pad">
|
||||
<span id="chatlabel">Chat</span>
|
||||
<img src="../static/img/editbar_chat.gif" width="16" height="16" />
|
||||
</a>
|
||||
<span id="chatcounter">0</span>
|
||||
</div>
|
||||
|
||||
<div id="chatbox">
|
||||
<div id="titlebar"><span id ="titlelabel">Chat</span><a id="titlecross" href="javascript:chat.hide();">x </a></div>
|
||||
<div id="chattext" class="authorColors"></div>
|
||||
<div id="chatinputbox">
|
||||
<form>
|
||||
<input id="chatinput" type="text" maxlength="140"/>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- /padeditor -->
|
||||
<div id="modaloverlay">
|
||||
<div id="modaloverlay-inner">
|
||||
|
|
Loading…
Reference in a new issue