Merge branch 'develop' of https://github.com/Pita/etherpad-lite into develop
This commit is contained in:
commit
de90f0db4e
|
@ -72,3 +72,33 @@ exports.getPadId = function(readOnlyId, callback)
|
||||||
{
|
{
|
||||||
db.get("readonly2pad:" + readOnlyId, callback);
|
db.get("readonly2pad:" + readOnlyId, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns a the padId and readonlyPadId in an object for any id
|
||||||
|
* @param {String} padIdOrReadonlyPadId read only id or real pad id
|
||||||
|
*/
|
||||||
|
exports.getIds = function(padIdOrReadonlyPadId, callback) {
|
||||||
|
var handleRealPadId = function () {
|
||||||
|
exports.getReadOnlyId(padIdOrReadonlyPadId, function (err, value) {
|
||||||
|
callback(null, {
|
||||||
|
readOnlyPadId: value,
|
||||||
|
padId: padIdOrReadonlyPadId,
|
||||||
|
readonly: false
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (padIdOrReadonlyPadId.indexOf("r.") != 0)
|
||||||
|
return handleRealPadId();
|
||||||
|
|
||||||
|
exports.getPadId(padIdOrReadonlyPadId, function (err, value) {
|
||||||
|
if(ERR(err, callback)) return;
|
||||||
|
if (value == null)
|
||||||
|
return handleRealPadId();
|
||||||
|
callback(null, {
|
||||||
|
readOnlyPadId: padIdOrReadonlyPadId,
|
||||||
|
padId: value,
|
||||||
|
readonly: true
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -34,19 +34,18 @@ var log4js = require('log4js');
|
||||||
var messageLogger = log4js.getLogger("message");
|
var messageLogger = log4js.getLogger("message");
|
||||||
var _ = require('underscore');
|
var _ = require('underscore');
|
||||||
|
|
||||||
/**
|
|
||||||
* A associative array that translates a session to a pad
|
|
||||||
*/
|
|
||||||
var session2pad = {};
|
|
||||||
/**
|
/**
|
||||||
* A associative array that saves which sessions belong to a pad
|
* A associative array that saves which sessions belong to a pad
|
||||||
*/
|
*/
|
||||||
var pad2sessions = {};
|
var pad2sessions = {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A associative array that saves some general informations about a session
|
* A associative array that saves informations about a session
|
||||||
* key = sessionId
|
* key = sessionId
|
||||||
* values = author, rev
|
* values = padId, readonlyPadId, readonly, author, rev
|
||||||
|
* padId = the real padId of the pad
|
||||||
|
* readonlyPadId = The readonly pad id of the pad
|
||||||
|
* readonly = Wether the client has only read access (true) or read/write access (false)
|
||||||
* rev = That last revision that was send to this client
|
* rev = That last revision that was send to this client
|
||||||
* author = the author name of this session
|
* author = the author name of this session
|
||||||
*/
|
*/
|
||||||
|
@ -72,8 +71,7 @@ exports.setSocketIO = function(socket_io)
|
||||||
*/
|
*/
|
||||||
exports.handleConnect = function(client)
|
exports.handleConnect = function(client)
|
||||||
{
|
{
|
||||||
//Initalize session2pad and sessioninfos for this new session
|
//Initalize sessioninfos for this new session
|
||||||
session2pad[client.id]=null;
|
|
||||||
sessioninfos[client.id]={};
|
sessioninfos[client.id]={};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,7 +99,7 @@ exports.kickSessionsFromPad = function(padID)
|
||||||
exports.handleDisconnect = function(client)
|
exports.handleDisconnect = function(client)
|
||||||
{
|
{
|
||||||
//save the padname of this session
|
//save the padname of this session
|
||||||
var sessionPad=session2pad[client.id];
|
var sessionPad=sessioninfos[client.id].padId;
|
||||||
|
|
||||||
//if this connection was already etablished with a handshake, send a disconnect message to the others
|
//if this connection was already etablished with a handshake, send a disconnect message to the others
|
||||||
if(sessioninfos[client.id] && sessioninfos[client.id].author)
|
if(sessioninfos[client.id] && sessioninfos[client.id].author)
|
||||||
|
@ -149,8 +147,7 @@ exports.handleDisconnect = function(client)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Delete the session2pad and sessioninfos entrys of this session
|
//Delete the sessioninfos entrys of this session
|
||||||
delete session2pad[client.id];
|
|
||||||
delete sessioninfos[client.id];
|
delete sessioninfos[client.id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,44 +170,40 @@ exports.handleMessage = function(client, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
//Check what type of message we get and delegate to the other methodes
|
//Check what type of message we get and delegate to the other methodes
|
||||||
if(message.type == "CLIENT_READY")
|
if(message.type == "CLIENT_READY") {
|
||||||
{
|
|
||||||
handleClientReady(client, message);
|
handleClientReady(client, message);
|
||||||
}
|
} else if(message.type == "CHANGESET_REQ") {
|
||||||
else if(message.type == "COLLABROOM" && typeof message.data == 'object'){
|
handleChangesetRequest(client, message);
|
||||||
if (message.data.type == "USER_CHANGES")
|
} else if(message.type == "COLLABROOM") {
|
||||||
{
|
if (sessioninfos[client.id].readonly) {
|
||||||
|
messageLogger.warn("Dropped message, COLLABROOM for readonly pad");
|
||||||
|
} else if (message.data.type == "USER_CHANGES") {
|
||||||
handleUserChanges(client, message);
|
handleUserChanges(client, message);
|
||||||
}
|
} else if (message.data.type == "USERINFO_UPDATE") {
|
||||||
else if (message.data.type == "USERINFO_UPDATE")
|
|
||||||
{
|
|
||||||
handleUserInfoUpdate(client, message);
|
handleUserInfoUpdate(client, message);
|
||||||
}
|
} else if (message.data.type == "CHAT_MESSAGE") {
|
||||||
else if(message.data.type == "CHAT_MESSAGE")
|
|
||||||
{
|
|
||||||
handleChatMessage(client, message);
|
handleChatMessage(client, message);
|
||||||
}
|
} else if (message.data.type == "SAVE_REVISION") {
|
||||||
else if(message.data.type == "CLIENT_MESSAGE" &&
|
handleSaveRevisionMessage(client, message);
|
||||||
typeof message.data.payload == 'object' &&
|
} else if (message.data.type == "CLIENT_MESSAGE" &&
|
||||||
message.data.payload.type == "suggestUserName")
|
message.data.payload.type == "suggestUserName") {
|
||||||
{
|
|
||||||
handleSuggestUserName(client, message);
|
handleSuggestUserName(client, message);
|
||||||
|
} else {
|
||||||
|
messageLogger.warn("Dropped message, unknown COLLABROOM Data Type " + message.data.type);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
//if the message type is unknown, throw an exception
|
|
||||||
else
|
|
||||||
{
|
|
||||||
messageLogger.warn("Dropped message, unknown Message Type " + message.type);
|
messageLogger.warn("Dropped message, unknown Message Type " + message.type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles a save revision message
|
* Handles a save revision message
|
||||||
* @param client the client that send this message
|
* @param client the client that send this message
|
||||||
* @param message the message from the client
|
* @param message the message from the client
|
||||||
*/
|
*/
|
||||||
function handleSaveRevisionMessage(client, message){
|
function handleSaveRevisionMessage(client, message){
|
||||||
var padId = session2pad[client.id];
|
var padId = sessioninfos[client.id].padId;
|
||||||
var userId = sessioninfos[client.id].author;
|
var userId = sessioninfos[client.id].author;
|
||||||
|
|
||||||
padManager.getPad(padId, function(err, pad)
|
padManager.getPad(padId, function(err, pad)
|
||||||
|
@ -231,7 +224,7 @@ function handleChatMessage(client, message)
|
||||||
var time = new Date().getTime();
|
var time = new Date().getTime();
|
||||||
var userId = sessioninfos[client.id].author;
|
var userId = sessioninfos[client.id].author;
|
||||||
var text = message.data.text;
|
var text = message.data.text;
|
||||||
var padId = session2pad[client.id];
|
var padId = sessioninfos[client.id].padId;
|
||||||
|
|
||||||
var pad;
|
var pad;
|
||||||
var userName;
|
var userName;
|
||||||
|
@ -307,7 +300,7 @@ function handleSuggestUserName(client, message)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var padId = session2pad[client.id];
|
var padId = sessioninfos[client.id].padId;
|
||||||
|
|
||||||
//search the author and send him this message
|
//search the author and send him this message
|
||||||
for(var i in pad2sessions[padId])
|
for(var i in pad2sessions[padId])
|
||||||
|
@ -341,7 +334,7 @@ function handleUserInfoUpdate(client, message)
|
||||||
authorManager.setAuthorColorId(author, message.data.userInfo.colorId);
|
authorManager.setAuthorColorId(author, message.data.userInfo.colorId);
|
||||||
authorManager.setAuthorName(author, message.data.userInfo.name);
|
authorManager.setAuthorName(author, message.data.userInfo.name);
|
||||||
|
|
||||||
var padId = session2pad[client.id];
|
var padId = sessioninfos[client.id].padId;
|
||||||
|
|
||||||
//set a null name, when there is no name set. cause the client wants it null
|
//set a null name, when there is no name set. cause the client wants it null
|
||||||
if(message.data.userInfo.name == null)
|
if(message.data.userInfo.name == null)
|
||||||
|
@ -387,7 +380,7 @@ function handleUserChanges(client, message)
|
||||||
messageLogger.warn("Dropped message, USER_CHANGES Message has no changeset!");
|
messageLogger.warn("Dropped message, USER_CHANGES Message has no changeset!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//get all Vars we need
|
//get all Vars we need
|
||||||
var baseRev = message.data.baseRev;
|
var baseRev = message.data.baseRev;
|
||||||
var wireApool = (new AttributePool()).fromJsonable(message.data.apool);
|
var wireApool = (new AttributePool()).fromJsonable(message.data.apool);
|
||||||
|
@ -399,7 +392,7 @@ function handleUserChanges(client, message)
|
||||||
//get the pad
|
//get the pad
|
||||||
function(callback)
|
function(callback)
|
||||||
{
|
{
|
||||||
padManager.getPad(session2pad[client.id], function(err, value)
|
padManager.getPad(sessioninfos[client.id].padId, function(err, value)
|
||||||
{
|
{
|
||||||
if(ERR(err, callback)) return;
|
if(ERR(err, callback)) return;
|
||||||
pad = value;
|
pad = value;
|
||||||
|
@ -506,17 +499,15 @@ exports.updatePadClients = function(pad, callback)
|
||||||
//go trough all sessions on this pad
|
//go trough all sessions on this pad
|
||||||
async.forEach(pad2sessions[pad.id], function(session, callback)
|
async.forEach(pad2sessions[pad.id], function(session, callback)
|
||||||
{
|
{
|
||||||
var lastRev = sessioninfos[session].rev;
|
|
||||||
|
|
||||||
//https://github.com/caolan/async#whilst
|
//https://github.com/caolan/async#whilst
|
||||||
//send them all new changesets
|
//send them all new changesets
|
||||||
async.whilst(
|
async.whilst(
|
||||||
function (){ return lastRev < pad.getHeadRevisionNumber()},
|
function (){ return sessioninfos[session].rev < pad.getHeadRevisionNumber()},
|
||||||
function(callback)
|
function(callback)
|
||||||
{
|
{
|
||||||
var author, revChangeset;
|
var author, revChangeset, currentTime;
|
||||||
|
var r = sessioninfos[session].rev + 1;
|
||||||
var r = ++lastRev;
|
|
||||||
|
|
||||||
async.parallel([
|
async.parallel([
|
||||||
function (callback)
|
function (callback)
|
||||||
|
@ -536,6 +527,15 @@ exports.updatePadClients = function(pad, callback)
|
||||||
revChangeset = value;
|
revChangeset = value;
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
function (callback)
|
||||||
|
{
|
||||||
|
pad.getRevisionDate(r, function(err, date)
|
||||||
|
{
|
||||||
|
if(ERR(err, callback)) return;
|
||||||
|
currentTime = date;
|
||||||
|
callback();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
], function(err)
|
], function(err)
|
||||||
{
|
{
|
||||||
|
@ -553,24 +553,30 @@ exports.updatePadClients = function(pad, callback)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var forWire = Changeset.prepareForWire(revChangeset, pad.pool);
|
var forWire = Changeset.prepareForWire(revChangeset, pad.pool);
|
||||||
var wireMsg = {"type":"COLLABROOM","data":{type:"NEW_CHANGES", newRev:r,
|
var wireMsg = {"type":"COLLABROOM",
|
||||||
changeset: forWire.translated,
|
"data":{type:"NEW_CHANGES",
|
||||||
apool: forWire.pool,
|
newRev:r,
|
||||||
author: author}};
|
changeset: forWire.translated,
|
||||||
|
apool: forWire.pool,
|
||||||
|
author: author,
|
||||||
|
currentTime: currentTime,
|
||||||
|
timeDelta: currentTime - sessioninfos[session].time
|
||||||
|
}};
|
||||||
|
|
||||||
socketio.sockets.sockets[session].json.send(wireMsg);
|
socketio.sockets.sockets[session].json.send(wireMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(sessioninfos[session] != null)
|
||||||
|
{
|
||||||
|
sessioninfos[session].time = currentTime;
|
||||||
|
sessioninfos[session].rev = r;
|
||||||
|
}
|
||||||
|
|
||||||
callback(null);
|
callback(null);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
callback
|
callback
|
||||||
);
|
);
|
||||||
|
|
||||||
if(sessioninfos[session] != null)
|
|
||||||
{
|
|
||||||
sessioninfos[session].rev = pad.getHeadRevisionNumber();
|
|
||||||
}
|
|
||||||
},callback);
|
},callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -655,14 +661,29 @@ function handleClientReady(client, message)
|
||||||
var authorColorId;
|
var authorColorId;
|
||||||
var pad;
|
var pad;
|
||||||
var historicalAuthorData = {};
|
var historicalAuthorData = {};
|
||||||
var readOnlyId;
|
var currentTime;
|
||||||
var chatMessages;
|
var chatMessages;
|
||||||
|
var padIds;
|
||||||
|
|
||||||
async.series([
|
async.series([
|
||||||
|
// Get ro/rw id:s
|
||||||
|
function (callback) {
|
||||||
|
readOnlyManager.getIds(message.padId, function(err, value) {
|
||||||
|
if(ERR(err, callback)) return;
|
||||||
|
padIds = value;
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
//check permissions
|
//check permissions
|
||||||
function(callback)
|
function(callback)
|
||||||
{
|
{
|
||||||
securityManager.checkAccess (message.padId, message.sessionID, message.token, message.password, function(err, statusObject)
|
// Note: message.sessionID is an entierly different kind of
|
||||||
|
// session from the sessions we use here! Beware! FIXME: Call
|
||||||
|
// our "sessions" "connections".
|
||||||
|
// FIXME: Use a hook instead
|
||||||
|
// FIXME: Allow to override readwrite access with readonly
|
||||||
|
securityManager.checkAccess (padIds.padId, message.sessionID, message.token, message.password, function(err, statusObject)
|
||||||
{
|
{
|
||||||
if(ERR(err, callback)) return;
|
if(ERR(err, callback)) return;
|
||||||
|
|
||||||
|
@ -705,21 +726,12 @@ function handleClientReady(client, message)
|
||||||
},
|
},
|
||||||
function(callback)
|
function(callback)
|
||||||
{
|
{
|
||||||
padManager.getPad(message.padId, function(err, value)
|
padManager.getPad(padIds.padId, function(err, value)
|
||||||
{
|
{
|
||||||
if(ERR(err, callback)) return;
|
if(ERR(err, callback)) return;
|
||||||
pad = value;
|
pad = value;
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
},
|
|
||||||
function(callback)
|
|
||||||
{
|
|
||||||
readOnlyManager.getReadOnlyId(message.padId, function(err, value)
|
|
||||||
{
|
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
readOnlyId = value;
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
], callback);
|
], callback);
|
||||||
},
|
},
|
||||||
|
@ -729,6 +741,16 @@ function handleClientReady(client, message)
|
||||||
var authors = pad.getAllAuthors();
|
var authors = pad.getAllAuthors();
|
||||||
|
|
||||||
async.parallel([
|
async.parallel([
|
||||||
|
//get timestamp of latest revission needed for timeslider
|
||||||
|
function(callback)
|
||||||
|
{
|
||||||
|
pad.getRevisionDate(pad.getHeadRevisionNumber(), function(err, date)
|
||||||
|
{
|
||||||
|
if(ERR(err, callback)) return;
|
||||||
|
currentTime = date;
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
},
|
||||||
//get all author data out of the database
|
//get all author data out of the database
|
||||||
function(callback)
|
function(callback)
|
||||||
{
|
{
|
||||||
|
@ -755,35 +777,36 @@ function handleClientReady(client, message)
|
||||||
}
|
}
|
||||||
], callback);
|
], callback);
|
||||||
|
|
||||||
|
|
||||||
},
|
},
|
||||||
function(callback)
|
function(callback)
|
||||||
{
|
{
|
||||||
//Check if this author is already on the pad, if yes, kick the other sessions!
|
//Check if this author is already on the pad, if yes, kick the other sessions!
|
||||||
if(pad2sessions[message.padId])
|
if(pad2sessions[padIds.padId])
|
||||||
{
|
{
|
||||||
for(var i in pad2sessions[message.padId])
|
for(var i in pad2sessions[padIds.padId])
|
||||||
{
|
{
|
||||||
if(sessioninfos[pad2sessions[message.padId][i]] && sessioninfos[pad2sessions[message.padId][i]].author == author)
|
if(sessioninfos[pad2sessions[padIds.padId][i]] && sessioninfos[pad2sessions[padIds.padId][i]].author == author)
|
||||||
{
|
{
|
||||||
var socket = socketio.sockets.sockets[pad2sessions[message.padId][i]];
|
var socket = socketio.sockets.sockets[pad2sessions[padIds.padId][i]];
|
||||||
if(socket) socket.json.send({disconnect:"userdup"});
|
if(socket) socket.json.send({disconnect:"userdup"});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Save in session2pad that this session belonges to this pad
|
//Save in sessioninfos that this session belonges to this pad
|
||||||
var sessionId=String(client.id);
|
var sessionId=String(client.id);
|
||||||
session2pad[sessionId] = message.padId;
|
sessioninfos[sessionId].padId = padIds.padId;
|
||||||
|
sessioninfos[sessionId].readOnlyPadId = padIds.readOnlyPadId;
|
||||||
|
sessioninfos[sessionId].readonly = padIds.readonly;
|
||||||
|
|
||||||
//check if there is already a pad2sessions entry, if not, create one
|
//check if there is already a pad2sessions entry, if not, create one
|
||||||
if(!pad2sessions[message.padId])
|
if(!pad2sessions[padIds.padId])
|
||||||
{
|
{
|
||||||
pad2sessions[message.padId] = [];
|
pad2sessions[padIds.padId] = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
//Saves in pad2sessions that this session belongs to this pad
|
//Saves in pad2sessions that this session belongs to this pad
|
||||||
pad2sessions[message.padId].push(sessionId);
|
pad2sessions[padIds.padId].push(sessionId);
|
||||||
|
|
||||||
//prepare all values for the wire
|
//prepare all values for the wire
|
||||||
var atext = Changeset.cloneAText(pad.atext);
|
var atext = Changeset.cloneAText(pad.atext);
|
||||||
|
@ -791,6 +814,9 @@ function handleClientReady(client, message)
|
||||||
var apool = attribsForWire.pool.toJsonable();
|
var apool = attribsForWire.pool.toJsonable();
|
||||||
atext.attribs = attribsForWire.translated;
|
atext.attribs = attribsForWire.translated;
|
||||||
|
|
||||||
|
// Warning: never ever send padIds.padId to the client. If the
|
||||||
|
// client is read only you would open a security hole 1 swedish
|
||||||
|
// mile wide...
|
||||||
var clientVars = {
|
var clientVars = {
|
||||||
"accountPrivs": {
|
"accountPrivs": {
|
||||||
"maxRevisions": 100
|
"maxRevisions": 100
|
||||||
|
@ -799,6 +825,7 @@ function handleClientReady(client, message)
|
||||||
"initialOptions": {
|
"initialOptions": {
|
||||||
"guestPolicy": "deny"
|
"guestPolicy": "deny"
|
||||||
},
|
},
|
||||||
|
"savedRevisions": pad.getSavedRevisions(),
|
||||||
"collab_client_vars": {
|
"collab_client_vars": {
|
||||||
"initialAttributedText": atext,
|
"initialAttributedText": atext,
|
||||||
"clientIp": "127.0.0.1",
|
"clientIp": "127.0.0.1",
|
||||||
|
@ -807,7 +834,8 @@ function handleClientReady(client, message)
|
||||||
"historicalAuthorData": historicalAuthorData,
|
"historicalAuthorData": historicalAuthorData,
|
||||||
"apool": apool,
|
"apool": apool,
|
||||||
"rev": pad.getHeadRevisionNumber(),
|
"rev": pad.getHeadRevisionNumber(),
|
||||||
"globalPadId": message.padId
|
"globalPadId": message.padId,
|
||||||
|
"time": currentTime,
|
||||||
},
|
},
|
||||||
"colorPalette": ["#ffc7c7", "#fff1c7", "#e3ffc7", "#c7ffd5", "#c7ffff", "#c7d5ff", "#e3c7ff", "#ffc7f1", "#ff8f8f", "#ffe38f", "#c7ff8f", "#8fffab", "#8fffff", "#8fabff", "#c78fff", "#ff8fe3", "#d97979", "#d9c179", "#a9d979", "#79d991", "#79d9d9", "#7991d9", "#a979d9", "#d979c1", "#d9a9a9", "#d9cda9", "#c1d9a9", "#a9d9b5", "#a9d9d9", "#a9b5d9", "#c1a9d9", "#d9a9cd", "#4c9c82", "#12d1ad", "#2d8e80", "#7485c3", "#a091c7", "#3185ab", "#6818b4", "#e6e76d", "#a42c64", "#f386e5", "#4ecc0c", "#c0c236", "#693224", "#b5de6a", "#9b88fd", "#358f9b", "#496d2f", "#e267fe", "#d23056", "#1a1a64", "#5aa335", "#d722bb", "#86dc6c", "#b5a714", "#955b6a", "#9f2985", "#4b81c8", "#3d6a5b", "#434e16", "#d16084", "#af6a0e", "#8c8bd8"],
|
"colorPalette": ["#ffc7c7", "#fff1c7", "#e3ffc7", "#c7ffd5", "#c7ffff", "#c7d5ff", "#e3c7ff", "#ffc7f1", "#ff8f8f", "#ffe38f", "#c7ff8f", "#8fffab", "#8fffff", "#8fabff", "#c78fff", "#ff8fe3", "#d97979", "#d9c179", "#a9d979", "#79d991", "#79d9d9", "#7991d9", "#a979d9", "#d979c1", "#d9a9a9", "#d9cda9", "#c1d9a9", "#a9d9b5", "#a9d9d9", "#a9b5d9", "#c1a9d9", "#d9a9cd", "#4c9c82", "#12d1ad", "#2d8e80", "#7485c3", "#a091c7", "#3185ab", "#6818b4", "#e6e76d", "#a42c64", "#f386e5", "#4ecc0c", "#c0c236", "#693224", "#b5de6a", "#9b88fd", "#358f9b", "#496d2f", "#e267fe", "#d23056", "#1a1a64", "#5aa335", "#d722bb", "#86dc6c", "#b5a714", "#955b6a", "#9f2985", "#4b81c8", "#3d6a5b", "#434e16", "#d16084", "#af6a0e", "#8c8bd8"],
|
||||||
"clientIp": "127.0.0.1",
|
"clientIp": "127.0.0.1",
|
||||||
|
@ -817,9 +845,10 @@ function handleClientReady(client, message)
|
||||||
"initialTitle": "Pad: " + message.padId,
|
"initialTitle": "Pad: " + message.padId,
|
||||||
"opts": {},
|
"opts": {},
|
||||||
"chatHistory": chatMessages,
|
"chatHistory": chatMessages,
|
||||||
"numConnectedUsers": pad2sessions[message.padId].length,
|
"numConnectedUsers": pad2sessions[padIds.padId].length,
|
||||||
"isProPad": false,
|
"isProPad": false,
|
||||||
"readOnlyId": readOnlyId,
|
"readOnlyId": padIds.readOnlyPadId,
|
||||||
|
"readonly": padIds.readonly,
|
||||||
"serverTimestamp": new Date().getTime(),
|
"serverTimestamp": new Date().getTime(),
|
||||||
"globalPadId": message.padId,
|
"globalPadId": message.padId,
|
||||||
"userId": author,
|
"userId": author,
|
||||||
|
@ -831,7 +860,9 @@ function handleClientReady(client, message)
|
||||||
"plugins": {
|
"plugins": {
|
||||||
"plugins": plugins.plugins,
|
"plugins": plugins.plugins,
|
||||||
"parts": plugins.parts,
|
"parts": plugins.parts,
|
||||||
}
|
},
|
||||||
|
"initialChangesets": [] // FIXME: REMOVE THIS SHIT
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Add a username to the clientVars if one avaiable
|
//Add a username to the clientVars if one avaiable
|
||||||
|
@ -852,7 +883,7 @@ function handleClientReady(client, message)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//Send the clientVars to the Client
|
//Send the clientVars to the Client
|
||||||
client.json.send(clientVars);
|
client.json.send({type: "CLIENT_VARS", data: clientVars});
|
||||||
//Save the revision in sessioninfos
|
//Save the revision in sessioninfos
|
||||||
sessioninfos[client.id].rev = pad.getHeadRevisionNumber();
|
sessioninfos[client.id].rev = pad.getHeadRevisionNumber();
|
||||||
}
|
}
|
||||||
|
@ -882,7 +913,7 @@ function handleClientReady(client, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
//Run trough all sessions of this pad
|
//Run trough all sessions of this pad
|
||||||
async.forEach(pad2sessions[message.padId], function(sessionID, callback)
|
async.forEach(pad2sessions[padIds.padId], function(sessionID, callback)
|
||||||
{
|
{
|
||||||
var author, socket, sessionAuthorName, sessionAuthorColorId;
|
var author, socket, sessionAuthorName, sessionAuthorColorId;
|
||||||
|
|
||||||
|
@ -955,3 +986,325 @@ function handleClientReady(client, message)
|
||||||
ERR(err);
|
ERR(err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles a request for a rough changeset, the timeslider client needs it
|
||||||
|
*/
|
||||||
|
function handleChangesetRequest(client, message)
|
||||||
|
{
|
||||||
|
//check if all ok
|
||||||
|
if(message.data == null)
|
||||||
|
{
|
||||||
|
messageLogger.warn("Dropped message, changeset request has no data!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(message.padId == null)
|
||||||
|
{
|
||||||
|
messageLogger.warn("Dropped message, changeset request has no padId!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(message.data.granularity == null)
|
||||||
|
{
|
||||||
|
messageLogger.warn("Dropped message, changeset request has no granularity!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(message.data.start == null)
|
||||||
|
{
|
||||||
|
messageLogger.warn("Dropped message, changeset request has no start!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(message.data.requestID == null)
|
||||||
|
{
|
||||||
|
messageLogger.warn("Dropped message, changeset request has no requestID!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var granularity = message.data.granularity;
|
||||||
|
var start = message.data.start;
|
||||||
|
var end = start + (100 * granularity);
|
||||||
|
var padId = message.padId;
|
||||||
|
|
||||||
|
//build the requested rough changesets and send them back
|
||||||
|
getChangesetInfo(padId, start, end, granularity, function(err, changesetInfo)
|
||||||
|
{
|
||||||
|
ERR(err);
|
||||||
|
|
||||||
|
var data = changesetInfo;
|
||||||
|
data.requestID = message.data.requestID;
|
||||||
|
|
||||||
|
client.json.send({type: "CHANGESET_REQ", data: data});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to rebuild the getChangestInfo function of the original Etherpad
|
||||||
|
* https://github.com/ether/pad/blob/master/etherpad/src/etherpad/control/pad/pad_changeset_control.js#L144
|
||||||
|
*/
|
||||||
|
function getChangesetInfo(padId, startNum, endNum, granularity, callback)
|
||||||
|
{
|
||||||
|
var forwardsChangesets = [];
|
||||||
|
var backwardsChangesets = [];
|
||||||
|
var timeDeltas = [];
|
||||||
|
var apool = new AttributePool();
|
||||||
|
var pad;
|
||||||
|
var composedChangesets = {};
|
||||||
|
var revisionDate = [];
|
||||||
|
var lines;
|
||||||
|
|
||||||
|
async.series([
|
||||||
|
//get the pad from the database
|
||||||
|
function(callback)
|
||||||
|
{
|
||||||
|
padManager.getPad(padId, function(err, _pad)
|
||||||
|
{
|
||||||
|
if(ERR(err, callback)) return;
|
||||||
|
pad = _pad;
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
function(callback)
|
||||||
|
{
|
||||||
|
//calculate the last full endnum
|
||||||
|
var lastRev = pad.getHeadRevisionNumber();
|
||||||
|
if (endNum > lastRev+1) {
|
||||||
|
endNum = lastRev+1;
|
||||||
|
}
|
||||||
|
endNum = Math.floor(endNum / granularity)*granularity;
|
||||||
|
|
||||||
|
var compositesChangesetNeeded = [];
|
||||||
|
var revTimesNeeded = [];
|
||||||
|
|
||||||
|
//figure out which composite Changeset and revTimes we need, to load them in bulk
|
||||||
|
var compositeStart = startNum;
|
||||||
|
while (compositeStart < endNum)
|
||||||
|
{
|
||||||
|
var compositeEnd = compositeStart + granularity;
|
||||||
|
|
||||||
|
//add the composite Changeset we needed
|
||||||
|
compositesChangesetNeeded.push({start: compositeStart, end: compositeEnd});
|
||||||
|
|
||||||
|
//add the t1 time we need
|
||||||
|
revTimesNeeded.push(compositeStart == 0 ? 0 : compositeStart - 1);
|
||||||
|
//add the t2 time we need
|
||||||
|
revTimesNeeded.push(compositeEnd - 1);
|
||||||
|
|
||||||
|
compositeStart += granularity;
|
||||||
|
}
|
||||||
|
|
||||||
|
//get all needed db values parallel
|
||||||
|
async.parallel([
|
||||||
|
function(callback)
|
||||||
|
{
|
||||||
|
//get all needed composite Changesets
|
||||||
|
async.forEach(compositesChangesetNeeded, function(item, callback)
|
||||||
|
{
|
||||||
|
composePadChangesets(padId, item.start, item.end, function(err, changeset)
|
||||||
|
{
|
||||||
|
if(ERR(err, callback)) return;
|
||||||
|
composedChangesets[item.start + "/" + item.end] = changeset;
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
}, callback);
|
||||||
|
},
|
||||||
|
function(callback)
|
||||||
|
{
|
||||||
|
//get all needed revision Dates
|
||||||
|
async.forEach(revTimesNeeded, function(revNum, callback)
|
||||||
|
{
|
||||||
|
pad.getRevisionDate(revNum, function(err, revDate)
|
||||||
|
{
|
||||||
|
if(ERR(err, callback)) return;
|
||||||
|
revisionDate[revNum] = Math.floor(revDate/1000);
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
}, callback);
|
||||||
|
},
|
||||||
|
//get the lines
|
||||||
|
function(callback)
|
||||||
|
{
|
||||||
|
getPadLines(padId, startNum-1, function(err, _lines)
|
||||||
|
{
|
||||||
|
if(ERR(err, callback)) return;
|
||||||
|
lines = _lines;
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
], callback);
|
||||||
|
},
|
||||||
|
//doesn't know what happens here excatly :/
|
||||||
|
function(callback)
|
||||||
|
{
|
||||||
|
var compositeStart = startNum;
|
||||||
|
|
||||||
|
while (compositeStart < endNum)
|
||||||
|
{
|
||||||
|
if (compositeStart + granularity > endNum)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var compositeEnd = compositeStart + granularity;
|
||||||
|
|
||||||
|
var forwards = composedChangesets[compositeStart + "/" + compositeEnd];
|
||||||
|
var backwards = Changeset.inverse(forwards, lines.textlines, lines.alines, pad.apool());
|
||||||
|
|
||||||
|
Changeset.mutateAttributionLines(forwards, lines.alines, pad.apool());
|
||||||
|
Changeset.mutateTextLines(forwards, lines.textlines);
|
||||||
|
|
||||||
|
var forwards2 = Changeset.moveOpsToNewPool(forwards, pad.apool(), apool);
|
||||||
|
var backwards2 = Changeset.moveOpsToNewPool(backwards, pad.apool(), apool);
|
||||||
|
|
||||||
|
var t1, t2;
|
||||||
|
if (compositeStart == 0)
|
||||||
|
{
|
||||||
|
t1 = revisionDate[0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
t1 = revisionDate[compositeStart - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
t2 = revisionDate[compositeEnd - 1];
|
||||||
|
|
||||||
|
timeDeltas.push(t2 - t1);
|
||||||
|
forwardsChangesets.push(forwards2);
|
||||||
|
backwardsChangesets.push(backwards2);
|
||||||
|
|
||||||
|
compositeStart += granularity;
|
||||||
|
}
|
||||||
|
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
], function(err)
|
||||||
|
{
|
||||||
|
if(ERR(err, callback)) return;
|
||||||
|
|
||||||
|
callback(null, {forwardsChangesets: forwardsChangesets,
|
||||||
|
backwardsChangesets: backwardsChangesets,
|
||||||
|
apool: apool.toJsonable(),
|
||||||
|
actualEndNum: endNum,
|
||||||
|
timeDeltas: timeDeltas,
|
||||||
|
start: startNum,
|
||||||
|
granularity: granularity });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to rebuild the getPadLines function of the original Etherpad
|
||||||
|
* https://github.com/ether/pad/blob/master/etherpad/src/etherpad/control/pad/pad_changeset_control.js#L263
|
||||||
|
*/
|
||||||
|
function getPadLines(padId, revNum, callback)
|
||||||
|
{
|
||||||
|
var atext;
|
||||||
|
var result = {};
|
||||||
|
var pad;
|
||||||
|
|
||||||
|
async.series([
|
||||||
|
//get the pad from the database
|
||||||
|
function(callback)
|
||||||
|
{
|
||||||
|
padManager.getPad(padId, function(err, _pad)
|
||||||
|
{
|
||||||
|
if(ERR(err, callback)) return;
|
||||||
|
pad = _pad;
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
//get the atext
|
||||||
|
function(callback)
|
||||||
|
{
|
||||||
|
if(revNum >= 0)
|
||||||
|
{
|
||||||
|
pad.getInternalRevisionAText(revNum, function(err, _atext)
|
||||||
|
{
|
||||||
|
if(ERR(err, callback)) return;
|
||||||
|
atext = _atext;
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
atext = Changeset.makeAText("\n");
|
||||||
|
callback(null);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
function(callback)
|
||||||
|
{
|
||||||
|
result.textlines = Changeset.splitTextLines(atext.text);
|
||||||
|
result.alines = Changeset.splitAttributionLines(atext.attribs, atext.text);
|
||||||
|
callback(null);
|
||||||
|
}
|
||||||
|
], function(err)
|
||||||
|
{
|
||||||
|
if(ERR(err, callback)) return;
|
||||||
|
callback(null, result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to rebuild the composePadChangeset function of the original Etherpad
|
||||||
|
* https://github.com/ether/pad/blob/master/etherpad/src/etherpad/control/pad/pad_changeset_control.js#L241
|
||||||
|
*/
|
||||||
|
function composePadChangesets(padId, startNum, endNum, callback)
|
||||||
|
{
|
||||||
|
var pad;
|
||||||
|
var changesets = [];
|
||||||
|
var changeset;
|
||||||
|
|
||||||
|
async.series([
|
||||||
|
//get the pad from the database
|
||||||
|
function(callback)
|
||||||
|
{
|
||||||
|
padManager.getPad(padId, function(err, _pad)
|
||||||
|
{
|
||||||
|
if(ERR(err, callback)) return;
|
||||||
|
pad = _pad;
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
//fetch all changesets we need
|
||||||
|
function(callback)
|
||||||
|
{
|
||||||
|
var changesetsNeeded=[];
|
||||||
|
|
||||||
|
//create a array for all changesets, we will
|
||||||
|
//replace the values with the changeset later
|
||||||
|
for(var r=startNum;r<endNum;r++)
|
||||||
|
{
|
||||||
|
changesetsNeeded.push(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
//get all changesets
|
||||||
|
async.forEach(changesetsNeeded, function(revNum,callback)
|
||||||
|
{
|
||||||
|
pad.getRevisionChangeset(revNum, function(err, value)
|
||||||
|
{
|
||||||
|
if(ERR(err, callback)) return;
|
||||||
|
changesets[revNum] = value;
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
},callback);
|
||||||
|
},
|
||||||
|
//compose Changesets
|
||||||
|
function(callback)
|
||||||
|
{
|
||||||
|
changeset = changesets[startNum];
|
||||||
|
var pool = pad.apool();
|
||||||
|
|
||||||
|
for(var r=startNum+1;r<endNum;r++)
|
||||||
|
{
|
||||||
|
var cs = changesets[r];
|
||||||
|
changeset = Changeset.compose(changeset, cs, pool);
|
||||||
|
}
|
||||||
|
|
||||||
|
callback(null);
|
||||||
|
}
|
||||||
|
],
|
||||||
|
//return err and changeset
|
||||||
|
function(err)
|
||||||
|
{
|
||||||
|
if(ERR(err, callback)) return;
|
||||||
|
callback(null, changeset);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -1,534 +0,0 @@
|
||||||
/**
|
|
||||||
* The MessageHandler handles all Messages that comes from Socket.IO and controls the sessions
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright 2009 Google Inc., 2011 Peter 'Pita' Martischka (Primary Technology Ltd)
|
|
||||||
*
|
|
||||||
* 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 ERR = require("async-stacktrace");
|
|
||||||
var async = require("async");
|
|
||||||
var padManager = require("../db/PadManager");
|
|
||||||
var Changeset = require("ep_etherpad-lite/static/js/Changeset");
|
|
||||||
var AttributePool = require("ep_etherpad-lite/static/js/AttributePool");
|
|
||||||
var settings = require('../utils/Settings');
|
|
||||||
var authorManager = require("../db/AuthorManager");
|
|
||||||
var log4js = require('log4js');
|
|
||||||
var messageLogger = log4js.getLogger("message");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Saves the Socket class we need to send and recieve data from the client
|
|
||||||
*/
|
|
||||||
var socketio;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This Method is called by server.js to tell the message handler on which socket it should send
|
|
||||||
* @param socket_io The Socket
|
|
||||||
*/
|
|
||||||
exports.setSocketIO = function(socket_io)
|
|
||||||
{
|
|
||||||
socketio=socket_io;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles the connection of a new user
|
|
||||||
* @param client the new client
|
|
||||||
*/
|
|
||||||
exports.handleConnect = function(client)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles the disconnection of a user
|
|
||||||
* @param client the client that leaves
|
|
||||||
*/
|
|
||||||
exports.handleDisconnect = function(client)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles a message from a user
|
|
||||||
* @param client the client that send this message
|
|
||||||
* @param message the message from the client
|
|
||||||
*/
|
|
||||||
exports.handleMessage = function(client, message)
|
|
||||||
{
|
|
||||||
//Check what type of message we get and delegate to the other methodes
|
|
||||||
if(message.type == "CLIENT_READY")
|
|
||||||
{
|
|
||||||
handleClientReady(client, message);
|
|
||||||
}
|
|
||||||
else if(message.type == "CHANGESET_REQ")
|
|
||||||
{
|
|
||||||
handleChangesetRequest(client, message);
|
|
||||||
}
|
|
||||||
//if the message type is unkown, throw an exception
|
|
||||||
else
|
|
||||||
{
|
|
||||||
messageLogger.warn("Dropped message, unknown Message Type: '" + message.type + "'");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleClientReady(client, message)
|
|
||||||
{
|
|
||||||
if(message.padId == null)
|
|
||||||
{
|
|
||||||
messageLogger.warn("Dropped message, changeset request has no padId!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//send the timeslider client the clientVars, with this values its able to start
|
|
||||||
createTimesliderClientVars (message.padId, function(err, clientVars)
|
|
||||||
{
|
|
||||||
ERR(err);
|
|
||||||
|
|
||||||
client.json.send({type: "CLIENT_VARS", data: clientVars});
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles a request for a rough changeset, the timeslider client needs it
|
|
||||||
*/
|
|
||||||
function handleChangesetRequest(client, message)
|
|
||||||
{
|
|
||||||
//check if all ok
|
|
||||||
if(message.data == null)
|
|
||||||
{
|
|
||||||
messageLogger.warn("Dropped message, changeset request has no data!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(message.padId == null)
|
|
||||||
{
|
|
||||||
messageLogger.warn("Dropped message, changeset request has no padId!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(message.data.granularity == null)
|
|
||||||
{
|
|
||||||
messageLogger.warn("Dropped message, changeset request has no granularity!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(message.data.start == null)
|
|
||||||
{
|
|
||||||
messageLogger.warn("Dropped message, changeset request has no start!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(message.data.requestID == null)
|
|
||||||
{
|
|
||||||
messageLogger.warn("Dropped message, changeset request has no requestID!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var granularity = message.data.granularity;
|
|
||||||
var start = message.data.start;
|
|
||||||
var end = start + (100 * granularity);
|
|
||||||
var padId = message.padId;
|
|
||||||
|
|
||||||
//build the requested rough changesets and send them back
|
|
||||||
getChangesetInfo(padId, start, end, granularity, function(err, changesetInfo)
|
|
||||||
{
|
|
||||||
ERR(err);
|
|
||||||
|
|
||||||
var data = changesetInfo;
|
|
||||||
data.requestID = message.data.requestID;
|
|
||||||
|
|
||||||
client.json.send({type: "CHANGESET_REQ", data: data});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function createTimesliderClientVars (padId, callback)
|
|
||||||
{
|
|
||||||
var clientVars = {
|
|
||||||
viewId: padId,
|
|
||||||
colorPalette: ["#ffc7c7", "#fff1c7", "#e3ffc7", "#c7ffd5", "#c7ffff", "#c7d5ff", "#e3c7ff", "#ffc7f1", "#ff8f8f", "#ffe38f", "#c7ff8f", "#8fffab", "#8fffff", "#8fabff", "#c78fff", "#ff8fe3", "#d97979", "#d9c179", "#a9d979", "#79d991", "#79d9d9", "#7991d9", "#a979d9", "#d979c1", "#d9a9a9", "#d9cda9", "#c1d9a9", "#a9d9b5", "#a9d9d9", "#a9b5d9", "#c1a9d9", "#d9a9cd"],
|
|
||||||
savedRevisions: [],
|
|
||||||
padIdForUrl: padId,
|
|
||||||
fullWidth: false,
|
|
||||||
disableRightBar: false,
|
|
||||||
initialChangesets: [],
|
|
||||||
abiwordAvailable: settings.abiwordAvailable(),
|
|
||||||
hooks: [],
|
|
||||||
initialStyledContents: {}
|
|
||||||
};
|
|
||||||
|
|
||||||
var pad;
|
|
||||||
var initialChangesets = [];
|
|
||||||
|
|
||||||
async.series([
|
|
||||||
//get the pad from the database
|
|
||||||
function(callback)
|
|
||||||
{
|
|
||||||
padManager.getPad(padId, function(err, _pad)
|
|
||||||
{
|
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
pad = _pad;
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
//get all saved revisions and add them
|
|
||||||
function(callback)
|
|
||||||
{
|
|
||||||
clientVars.savedRevisions = pad.getSavedRevisions();
|
|
||||||
callback();
|
|
||||||
},
|
|
||||||
//get all authors and add them to
|
|
||||||
function(callback)
|
|
||||||
{
|
|
||||||
var historicalAuthorData = {};
|
|
||||||
//get all authors out of the attribut pool
|
|
||||||
var authors = pad.getAllAuthors();
|
|
||||||
|
|
||||||
//get all author data out of the database
|
|
||||||
async.forEach(authors, function(authorId, callback)
|
|
||||||
{
|
|
||||||
authorManager.getAuthor(authorId, function(err, author)
|
|
||||||
{
|
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
historicalAuthorData[authorId] = author;
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
}, function(err)
|
|
||||||
{
|
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
//add historicalAuthorData to the clientVars and continue
|
|
||||||
clientVars.historicalAuthorData = historicalAuthorData;
|
|
||||||
clientVars.initialStyledContents.historicalAuthorData = historicalAuthorData;
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
//get the timestamp of the last revision
|
|
||||||
function(callback)
|
|
||||||
{
|
|
||||||
pad.getRevisionDate(pad.getHeadRevisionNumber(), function(err, date)
|
|
||||||
{
|
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
clientVars.currentTime = date;
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
function(callback)
|
|
||||||
{
|
|
||||||
//get the head revision Number
|
|
||||||
var lastRev = pad.getHeadRevisionNumber();
|
|
||||||
|
|
||||||
//add the revNum to the client Vars
|
|
||||||
clientVars.revNum = lastRev;
|
|
||||||
clientVars.totalRevs = lastRev;
|
|
||||||
|
|
||||||
var atext = Changeset.cloneAText(pad.atext);
|
|
||||||
var attribsForWire = Changeset.prepareForWire(atext.attribs, pad.pool);
|
|
||||||
var apool = attribsForWire.pool.toJsonable();
|
|
||||||
atext.attribs = attribsForWire.translated;
|
|
||||||
|
|
||||||
clientVars.initialStyledContents.apool = apool;
|
|
||||||
clientVars.initialStyledContents.atext = atext;
|
|
||||||
|
|
||||||
var granularities = [100, 10, 1];
|
|
||||||
|
|
||||||
//get the latest rough changesets
|
|
||||||
async.forEach(granularities, function(granularity, callback)
|
|
||||||
{
|
|
||||||
var topGranularity = granularity*10;
|
|
||||||
|
|
||||||
getChangesetInfo(padId, Math.floor(lastRev / topGranularity)*topGranularity,
|
|
||||||
Math.floor(lastRev / topGranularity)*topGranularity+topGranularity, granularity,
|
|
||||||
function(err, changeset)
|
|
||||||
{
|
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
clientVars.initialChangesets.push(changeset);
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
}, callback);
|
|
||||||
}
|
|
||||||
], function(err)
|
|
||||||
{
|
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
callback(null, clientVars);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tries to rebuild the getChangestInfo function of the original Etherpad
|
|
||||||
* https://github.com/ether/pad/blob/master/etherpad/src/etherpad/control/pad/pad_changeset_control.js#L144
|
|
||||||
*/
|
|
||||||
function getChangesetInfo(padId, startNum, endNum, granularity, callback)
|
|
||||||
{
|
|
||||||
var forwardsChangesets = [];
|
|
||||||
var backwardsChangesets = [];
|
|
||||||
var timeDeltas = [];
|
|
||||||
var apool = new AttributePool();
|
|
||||||
var pad;
|
|
||||||
var composedChangesets = {};
|
|
||||||
var revisionDate = [];
|
|
||||||
var lines;
|
|
||||||
|
|
||||||
async.series([
|
|
||||||
//get the pad from the database
|
|
||||||
function(callback)
|
|
||||||
{
|
|
||||||
padManager.getPad(padId, function(err, _pad)
|
|
||||||
{
|
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
pad = _pad;
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
function(callback)
|
|
||||||
{
|
|
||||||
//calculate the last full endnum
|
|
||||||
var lastRev = pad.getHeadRevisionNumber();
|
|
||||||
if (endNum > lastRev+1) {
|
|
||||||
endNum = lastRev+1;
|
|
||||||
}
|
|
||||||
endNum = Math.floor(endNum / granularity)*granularity;
|
|
||||||
|
|
||||||
var compositesChangesetNeeded = [];
|
|
||||||
var revTimesNeeded = [];
|
|
||||||
|
|
||||||
//figure out which composite Changeset and revTimes we need, to load them in bulk
|
|
||||||
var compositeStart = startNum;
|
|
||||||
while (compositeStart < endNum)
|
|
||||||
{
|
|
||||||
var compositeEnd = compositeStart + granularity;
|
|
||||||
|
|
||||||
//add the composite Changeset we needed
|
|
||||||
compositesChangesetNeeded.push({start: compositeStart, end: compositeEnd});
|
|
||||||
|
|
||||||
//add the t1 time we need
|
|
||||||
revTimesNeeded.push(compositeStart == 0 ? 0 : compositeStart - 1);
|
|
||||||
//add the t2 time we need
|
|
||||||
revTimesNeeded.push(compositeEnd - 1);
|
|
||||||
|
|
||||||
compositeStart += granularity;
|
|
||||||
}
|
|
||||||
|
|
||||||
//get all needed db values parallel
|
|
||||||
async.parallel([
|
|
||||||
function(callback)
|
|
||||||
{
|
|
||||||
//get all needed composite Changesets
|
|
||||||
async.forEach(compositesChangesetNeeded, function(item, callback)
|
|
||||||
{
|
|
||||||
composePadChangesets(padId, item.start, item.end, function(err, changeset)
|
|
||||||
{
|
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
composedChangesets[item.start + "/" + item.end] = changeset;
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
}, callback);
|
|
||||||
},
|
|
||||||
function(callback)
|
|
||||||
{
|
|
||||||
//get all needed revision Dates
|
|
||||||
async.forEach(revTimesNeeded, function(revNum, callback)
|
|
||||||
{
|
|
||||||
pad.getRevisionDate(revNum, function(err, revDate)
|
|
||||||
{
|
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
revisionDate[revNum] = Math.floor(revDate/1000);
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
}, callback);
|
|
||||||
},
|
|
||||||
//get the lines
|
|
||||||
function(callback)
|
|
||||||
{
|
|
||||||
getPadLines(padId, startNum-1, function(err, _lines)
|
|
||||||
{
|
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
lines = _lines;
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
], callback);
|
|
||||||
},
|
|
||||||
//doesn't know what happens here excatly :/
|
|
||||||
function(callback)
|
|
||||||
{
|
|
||||||
var compositeStart = startNum;
|
|
||||||
|
|
||||||
while (compositeStart < endNum)
|
|
||||||
{
|
|
||||||
if (compositeStart + granularity > endNum)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
var compositeEnd = compositeStart + granularity;
|
|
||||||
|
|
||||||
var forwards = composedChangesets[compositeStart + "/" + compositeEnd];
|
|
||||||
var backwards = Changeset.inverse(forwards, lines.textlines, lines.alines, pad.apool());
|
|
||||||
|
|
||||||
Changeset.mutateAttributionLines(forwards, lines.alines, pad.apool());
|
|
||||||
Changeset.mutateTextLines(forwards, lines.textlines);
|
|
||||||
|
|
||||||
var forwards2 = Changeset.moveOpsToNewPool(forwards, pad.apool(), apool);
|
|
||||||
var backwards2 = Changeset.moveOpsToNewPool(backwards, pad.apool(), apool);
|
|
||||||
|
|
||||||
var t1, t2;
|
|
||||||
if (compositeStart == 0)
|
|
||||||
{
|
|
||||||
t1 = revisionDate[0];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
t1 = revisionDate[compositeStart - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
t2 = revisionDate[compositeEnd - 1];
|
|
||||||
|
|
||||||
timeDeltas.push(t2 - t1);
|
|
||||||
forwardsChangesets.push(forwards2);
|
|
||||||
backwardsChangesets.push(backwards2);
|
|
||||||
|
|
||||||
compositeStart += granularity;
|
|
||||||
}
|
|
||||||
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
], function(err)
|
|
||||||
{
|
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
|
|
||||||
callback(null, {forwardsChangesets: forwardsChangesets,
|
|
||||||
backwardsChangesets: backwardsChangesets,
|
|
||||||
apool: apool.toJsonable(),
|
|
||||||
actualEndNum: endNum,
|
|
||||||
timeDeltas: timeDeltas,
|
|
||||||
start: startNum,
|
|
||||||
granularity: granularity });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tries to rebuild the getPadLines function of the original Etherpad
|
|
||||||
* https://github.com/ether/pad/blob/master/etherpad/src/etherpad/control/pad/pad_changeset_control.js#L263
|
|
||||||
*/
|
|
||||||
function getPadLines(padId, revNum, callback)
|
|
||||||
{
|
|
||||||
var atext;
|
|
||||||
var result = {};
|
|
||||||
var pad;
|
|
||||||
|
|
||||||
async.series([
|
|
||||||
//get the pad from the database
|
|
||||||
function(callback)
|
|
||||||
{
|
|
||||||
padManager.getPad(padId, function(err, _pad)
|
|
||||||
{
|
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
pad = _pad;
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
//get the atext
|
|
||||||
function(callback)
|
|
||||||
{
|
|
||||||
if(revNum >= 0)
|
|
||||||
{
|
|
||||||
pad.getInternalRevisionAText(revNum, function(err, _atext)
|
|
||||||
{
|
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
atext = _atext;
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
atext = Changeset.makeAText("\n");
|
|
||||||
callback(null);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
function(callback)
|
|
||||||
{
|
|
||||||
result.textlines = Changeset.splitTextLines(atext.text);
|
|
||||||
result.alines = Changeset.splitAttributionLines(atext.attribs, atext.text);
|
|
||||||
callback(null);
|
|
||||||
}
|
|
||||||
], function(err)
|
|
||||||
{
|
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
callback(null, result);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tries to rebuild the composePadChangeset function of the original Etherpad
|
|
||||||
* https://github.com/ether/pad/blob/master/etherpad/src/etherpad/control/pad/pad_changeset_control.js#L241
|
|
||||||
*/
|
|
||||||
function composePadChangesets(padId, startNum, endNum, callback)
|
|
||||||
{
|
|
||||||
var pad;
|
|
||||||
var changesets = [];
|
|
||||||
var changeset;
|
|
||||||
|
|
||||||
async.series([
|
|
||||||
//get the pad from the database
|
|
||||||
function(callback)
|
|
||||||
{
|
|
||||||
padManager.getPad(padId, function(err, _pad)
|
|
||||||
{
|
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
pad = _pad;
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
//fetch all changesets we need
|
|
||||||
function(callback)
|
|
||||||
{
|
|
||||||
var changesetsNeeded=[];
|
|
||||||
|
|
||||||
//create a array for all changesets, we will
|
|
||||||
//replace the values with the changeset later
|
|
||||||
for(var r=startNum;r<endNum;r++)
|
|
||||||
{
|
|
||||||
changesetsNeeded.push(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
//get all changesets
|
|
||||||
async.forEach(changesetsNeeded, function(revNum,callback)
|
|
||||||
{
|
|
||||||
pad.getRevisionChangeset(revNum, function(err, value)
|
|
||||||
{
|
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
changesets[revNum] = value;
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
},callback);
|
|
||||||
},
|
|
||||||
//compose Changesets
|
|
||||||
function(callback)
|
|
||||||
{
|
|
||||||
changeset = changesets[startNum];
|
|
||||||
var pool = pad.apool();
|
|
||||||
|
|
||||||
for(var r=startNum+1;r<endNum;r++)
|
|
||||||
{
|
|
||||||
var cs = changesets[r];
|
|
||||||
changeset = Changeset.compose(changeset, cs, pool);
|
|
||||||
}
|
|
||||||
|
|
||||||
callback(null);
|
|
||||||
}
|
|
||||||
],
|
|
||||||
//return err and changeset
|
|
||||||
function(err)
|
|
||||||
{
|
|
||||||
if(ERR(err, callback)) return;
|
|
||||||
callback(null, changeset);
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -5,7 +5,6 @@ var socketIORouter = require("../../handler/SocketIORouter");
|
||||||
var hooks = require("ep_etherpad-lite/static/js/pluginfw/hooks");
|
var hooks = require("ep_etherpad-lite/static/js/pluginfw/hooks");
|
||||||
|
|
||||||
var padMessageHandler = require("../../handler/PadMessageHandler");
|
var padMessageHandler = require("../../handler/PadMessageHandler");
|
||||||
var timesliderMessageHandler = require("../../handler/TimesliderMessageHandler");
|
|
||||||
|
|
||||||
var connect = require('connect');
|
var connect = require('connect');
|
||||||
|
|
||||||
|
@ -59,7 +58,6 @@ exports.expressCreateServer = function (hook_name, args, cb) {
|
||||||
//Initalize the Socket.IO Router
|
//Initalize the Socket.IO Router
|
||||||
socketIORouter.setSocketIO(io);
|
socketIORouter.setSocketIO(io);
|
||||||
socketIORouter.addComponent("pad", padMessageHandler);
|
socketIORouter.addComponent("pad", padMessageHandler);
|
||||||
socketIORouter.addComponent("timeslider", timesliderMessageHandler);
|
|
||||||
|
|
||||||
hooks.callAll("socketio", {"app": args.app, "io": io});
|
hooks.callAll("socketio", {"app": args.app, "io": io});
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,11 +40,9 @@
|
||||||
]
|
]
|
||||||
, "ace2_inner.js": [
|
, "ace2_inner.js": [
|
||||||
"ace2_inner.js"
|
"ace2_inner.js"
|
||||||
, "underscore.js"
|
|
||||||
, "AttributePool.js"
|
, "AttributePool.js"
|
||||||
, "Changeset.js"
|
, "Changeset.js"
|
||||||
, "ChangesetUtils.js"
|
, "ChangesetUtils.js"
|
||||||
, "security.js"
|
|
||||||
, "skiplist.js"
|
, "skiplist.js"
|
||||||
, "virtual_lines.js"
|
, "virtual_lines.js"
|
||||||
, "cssmanager.js"
|
, "cssmanager.js"
|
||||||
|
|
|
@ -19,6 +19,9 @@ textarea {
|
||||||
iframe {
|
iframe {
|
||||||
position: absolute
|
position: absolute
|
||||||
}
|
}
|
||||||
|
.readonly .acl-write {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
#users {
|
#users {
|
||||||
background: #f7f7f7;
|
background: #f7f7f7;
|
||||||
background: -webkit-linear-gradient( #F7F7F7,#EEE);
|
background: -webkit-linear-gradient( #F7F7F7,#EEE);
|
||||||
|
@ -992,4 +995,7 @@ input[type=checkbox] {
|
||||||
.toolbar ul li .separator {
|
.toolbar ul li .separator {
|
||||||
display: none
|
display: none
|
||||||
}
|
}
|
||||||
|
#online_count {
|
||||||
|
line-height: 24px
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -177,10 +177,10 @@ require.setGlobalKeyPath("require");\n\
|
||||||
}
|
}
|
||||||
function pushScriptsTo(buffer) {
|
function pushScriptsTo(buffer) {
|
||||||
/* Folling is for packaging regular expression. */
|
/* Folling is for packaging regular expression. */
|
||||||
/* $$INCLUDE_JS("../javascripts/src/ace2_inner.js?callback=require.define"); */
|
/* $$INCLUDE_JS("../javascripts/lib/ep_etherpad-lite/static/js/ace2_inner.js?callback=require.define"); */
|
||||||
/* $$INCLUDE_JS("../javascripts/src/ace2_common.js?callback=require.define"); */
|
/* $$INCLUDE_JS("../javascripts/lib/ep_etherpad-lite/static/js/ace2_common.js?callback=require.define"); */
|
||||||
var ACE_SOURCE = '../javascripts/src/ace2_inner.js?callback=require.define';
|
var ACE_SOURCE = '../javascripts/lib/ep_etherpad-lite/static/js/ace2_inner.js?callback=require.define';
|
||||||
var ACE_COMMON = '../javascripts/src/ace2_common.js?callback=require.define';
|
var ACE_COMMON = '../javascripts/lib/ep_etherpad-lite/static/js/ace2_common.js?callback=require.define';
|
||||||
if (Ace2Editor.EMBEDED && Ace2Editor.EMBEDED[ACE_SOURCE]) {
|
if (Ace2Editor.EMBEDED && Ace2Editor.EMBEDED[ACE_SOURCE]) {
|
||||||
buffer.push('<script type="text/javascript">');
|
buffer.push('<script type="text/javascript">');
|
||||||
buffer.push(Ace2Editor.EMBEDED[ACE_SOURCE]);
|
buffer.push(Ace2Editor.EMBEDED[ACE_SOURCE]);
|
||||||
|
@ -238,11 +238,6 @@ require.setGlobalKeyPath("require");\n\
|
||||||
|
|
||||||
iframeHTML.push(doctype);
|
iframeHTML.push(doctype);
|
||||||
iframeHTML.push("<html><head>");
|
iframeHTML.push("<html><head>");
|
||||||
iframeHTML.push('<script type="text/javascript" src="../static/js/jquery.js"></script>');
|
|
||||||
|
|
||||||
hooks.callAll("aceInitInnerdocbodyHead", {
|
|
||||||
iframeHTML: iframeHTML
|
|
||||||
});
|
|
||||||
|
|
||||||
// calls to these functions ($$INCLUDE_...) are replaced when this file is processed
|
// calls to these functions ($$INCLUDE_...) are replaced when this file is processed
|
||||||
// and compressed, putting the compressed code from the named file directly into the
|
// and compressed, putting the compressed code from the named file directly into the
|
||||||
|
@ -266,23 +261,23 @@ require.setGlobalKeyPath("require");\n\
|
||||||
// Inject my plugins into my child.
|
// Inject my plugins into my child.
|
||||||
iframeHTML.push('\
|
iframeHTML.push('\
|
||||||
<script type="text/javascript">\
|
<script type="text/javascript">\
|
||||||
parent_req = require("./pluginfw/parent_require.js");\
|
parent_req = require("ep_etherpad-lite/static/js/pluginfw/parent_require");\
|
||||||
parent_req.getRequirementFromParent(require, "ep_etherpad-lite/static/js/pluginfw/hooks");\
|
parent_req.getRequirementFromParent(require, "ep_etherpad-lite/static/js/pluginfw/hooks");\
|
||||||
parent_req.getRequirementFromParent(require, "ep_etherpad-lite/static/js/pluginfw/plugins");\
|
parent_req.getRequirementFromParent(require, "ep_etherpad-lite/static/js/pluginfw/plugins");\
|
||||||
parent_req.getRequirementFromParent(require, "./pluginfw/hooks");\
|
|
||||||
parent_req.getRequirementFromParent(require, "./pluginfw/plugins");\
|
|
||||||
require.define("/plugins", null);\n\
|
|
||||||
require.define("/plugins.js", function (require, exports, module) {\
|
|
||||||
module.exports = require("ep_etherpad-lite/static/js/plugins");\
|
|
||||||
});\
|
|
||||||
</script>\
|
</script>\
|
||||||
');
|
');
|
||||||
|
|
||||||
iframeHTML.push('<script type="text/javascript">');
|
iframeHTML.push('<script type="text/javascript">');
|
||||||
|
iframeHTML.push('$ = jQuery = require("ep_etherpad-lite/static/js/rjquery").jQuery; // Expose jQuery #HACK');
|
||||||
iframeHTML.push('require("ep_etherpad-lite/static/js/ace2_inner");');
|
iframeHTML.push('require("ep_etherpad-lite/static/js/ace2_inner");');
|
||||||
iframeHTML.push('<\/script>');
|
iframeHTML.push('<\/script>');
|
||||||
|
|
||||||
iframeHTML.push('<style type="text/css" title="dynamicsyntax"></style>');
|
iframeHTML.push('<style type="text/css" title="dynamicsyntax"></style>');
|
||||||
|
|
||||||
|
hooks.callAll("aceInitInnerdocbodyHead", {
|
||||||
|
iframeHTML: iframeHTML
|
||||||
|
});
|
||||||
|
|
||||||
iframeHTML.push('</head><body id="innerdocbody" class="syntax" spellcheck="false"> </body></html>');
|
iframeHTML.push('</head><body id="innerdocbody" class="syntax" spellcheck="false"> </body></html>');
|
||||||
|
|
||||||
// Expose myself to global for my child frame.
|
// Expose myself to global for my child frame.
|
||||||
|
|
|
@ -84,14 +84,14 @@ function loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, Bro
|
||||||
var appLevelDisconnectReason = null;
|
var appLevelDisconnectReason = null;
|
||||||
|
|
||||||
var padContents = {
|
var padContents = {
|
||||||
currentRevision: clientVars.revNum,
|
currentRevision: clientVars.collab_client_vars.rev,
|
||||||
currentTime: clientVars.currentTime,
|
currentTime: clientVars.collab_client_vars.time,
|
||||||
currentLines: Changeset.splitTextLines(clientVars.initialStyledContents.atext.text),
|
currentLines: Changeset.splitTextLines(clientVars.collab_client_vars.initialAttributedText.text),
|
||||||
currentDivs: null,
|
currentDivs: null,
|
||||||
// to be filled in once the dom loads
|
// to be filled in once the dom loads
|
||||||
apool: (new AttribPool()).fromJsonable(clientVars.initialStyledContents.apool),
|
apool: (new AttribPool()).fromJsonable(clientVars.collab_client_vars.apool),
|
||||||
alines: Changeset.splitAttributionLines(
|
alines: Changeset.splitAttributionLines(
|
||||||
clientVars.initialStyledContents.atext.attribs, clientVars.initialStyledContents.atext.text),
|
clientVars.collab_client_vars.initialAttributedText.attribs, clientVars.collab_client_vars.initialAttributedText.text),
|
||||||
|
|
||||||
// generates a jquery element containing HTML for a line
|
// generates a jquery element containing HTML for a line
|
||||||
lineToElement: function(line, aline)
|
lineToElement: function(line, aline)
|
||||||
|
@ -271,7 +271,7 @@ function loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, Bro
|
||||||
|
|
||||||
Changeset.mutateTextLines(changeset, padContents);
|
Changeset.mutateTextLines(changeset, padContents);
|
||||||
padContents.currentRevision = revision;
|
padContents.currentRevision = revision;
|
||||||
padContents.currentTime += timeDelta * 1000;
|
padContents.currentTime += timeDelta;
|
||||||
debugLog('Time Delta: ', timeDelta)
|
debugLog('Time Delta: ', timeDelta)
|
||||||
updateTimer();
|
updateTimer();
|
||||||
|
|
||||||
|
@ -432,19 +432,6 @@ function loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, Bro
|
||||||
var start = request.rev;
|
var start = request.rev;
|
||||||
var requestID = Math.floor(Math.random() * 100000);
|
var requestID = Math.floor(Math.random() * 100000);
|
||||||
|
|
||||||
/*var msg = { "component" : "timeslider",
|
|
||||||
"type":"CHANGESET_REQ",
|
|
||||||
"padId": padId,
|
|
||||||
"token": token,
|
|
||||||
"protocolVersion": 2,
|
|
||||||
"data"
|
|
||||||
{
|
|
||||||
"start": start,
|
|
||||||
"granularity": granularity
|
|
||||||
}};
|
|
||||||
|
|
||||||
socket.send(msg);*/
|
|
||||||
|
|
||||||
sendSocketMsg("CHANGESET_REQ", {
|
sendSocketMsg("CHANGESET_REQ", {
|
||||||
"start": start,
|
"start": start,
|
||||||
"granularity": granularity,
|
"granularity": granularity,
|
||||||
|
@ -452,19 +439,6 @@ function loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, Bro
|
||||||
});
|
});
|
||||||
|
|
||||||
self.reqCallbacks[requestID] = callback;
|
self.reqCallbacks[requestID] = callback;
|
||||||
|
|
||||||
/*debugLog("loadinging revision", start, "through ajax");
|
|
||||||
$.getJSON("/ep/pad/changes/" + clientVars.padIdForUrl + "?s=" + start + "&g=" + granularity, function (data, textStatus)
|
|
||||||
{
|
|
||||||
if (textStatus !== "success")
|
|
||||||
{
|
|
||||||
console.log(textStatus);
|
|
||||||
BroadcastSlider.showReconnectUI();
|
|
||||||
}
|
|
||||||
self.handleResponse(data, start, granularity, callback);
|
|
||||||
|
|
||||||
setTimeout(self.loadFromQueue, 10); // load the next ajax function
|
|
||||||
});*/
|
|
||||||
},
|
},
|
||||||
handleSocketResponse: function(message)
|
handleSocketResponse: function(message)
|
||||||
{
|
{
|
||||||
|
@ -493,130 +467,58 @@ function loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, Bro
|
||||||
revisionInfo.addChangeset(astart, aend, forwardcs, backwardcs, data.timeDeltas[i]);
|
revisionInfo.addChangeset(astart, aend, forwardcs, backwardcs, data.timeDeltas[i]);
|
||||||
}
|
}
|
||||||
if (callback) callback(start - 1, start + data.forwardsChangesets.length * granularity - 1);
|
if (callback) callback(start - 1, start + data.forwardsChangesets.length * granularity - 1);
|
||||||
|
},
|
||||||
|
handleMessageFromServer: function (obj)
|
||||||
|
{
|
||||||
|
debugLog("handleMessage:", arguments);
|
||||||
|
|
||||||
|
if (obj.type == "COLLABROOM")
|
||||||
|
{
|
||||||
|
obj = obj.data;
|
||||||
|
|
||||||
|
if (obj.type == "NEW_CHANGES")
|
||||||
|
{
|
||||||
|
debugLog(obj);
|
||||||
|
var changeset = Changeset.moveOpsToNewPool(
|
||||||
|
obj.changeset, (new AttribPool()).fromJsonable(obj.apool), padContents.apool);
|
||||||
|
|
||||||
|
var changesetBack = Changeset.inverse(
|
||||||
|
obj.changeset, padContents.currentLines, padContents.alines, padContents.apool);
|
||||||
|
|
||||||
|
var changesetBack = Changeset.moveOpsToNewPool(
|
||||||
|
changesetBack, (new AttribPool()).fromJsonable(obj.apool), padContents.apool);
|
||||||
|
|
||||||
|
loadedNewChangeset(changeset, changesetBack, obj.newRev - 1, obj.timeDelta);
|
||||||
|
}
|
||||||
|
else if (obj.type == "NEW_AUTHORDATA")
|
||||||
|
{
|
||||||
|
var authorMap = {};
|
||||||
|
authorMap[obj.author] = obj.data;
|
||||||
|
receiveAuthorData(authorMap);
|
||||||
|
|
||||||
|
var authors = _.map(padContents.getActiveAuthors(), function(name) {
|
||||||
|
return authorData[name];
|
||||||
|
});
|
||||||
|
|
||||||
|
BroadcastSlider.setAuthors(authors);
|
||||||
|
}
|
||||||
|
else if (obj.type == "NEW_SAVEDREV")
|
||||||
|
{
|
||||||
|
var savedRev = obj.savedRev;
|
||||||
|
BroadcastSlider.addSavedRevision(savedRev.revNum, savedRev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(obj.type == "CHANGESET_REQ")
|
||||||
|
{
|
||||||
|
changesetLoader.handleSocketResponse(obj);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
debugLog("Unknown message type: " + obj.type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function handleMessageFromServer()
|
|
||||||
{
|
|
||||||
debugLog("handleMessage:", arguments);
|
|
||||||
var obj = arguments[0]['data'];
|
|
||||||
var expectedType = "COLLABROOM";
|
|
||||||
|
|
||||||
obj = JSON.parse(obj);
|
|
||||||
if (obj['type'] == expectedType)
|
|
||||||
{
|
|
||||||
obj = obj['data'];
|
|
||||||
|
|
||||||
if (obj['type'] == "NEW_CHANGES")
|
|
||||||
{
|
|
||||||
debugLog(obj);
|
|
||||||
var changeset = Changeset.moveOpsToNewPool(
|
|
||||||
obj.changeset, (new AttribPool()).fromJsonable(obj.apool), padContents.apool);
|
|
||||||
|
|
||||||
var changesetBack = Changeset.moveOpsToNewPool(
|
|
||||||
obj.changesetBack, (new AttribPool()).fromJsonable(obj.apool), padContents.apool);
|
|
||||||
|
|
||||||
loadedNewChangeset(changeset, changesetBack, obj.newRev - 1, obj.timeDelta);
|
|
||||||
}
|
|
||||||
else if (obj['type'] == "NEW_AUTHORDATA")
|
|
||||||
{
|
|
||||||
var authorMap = {};
|
|
||||||
authorMap[obj.author] = obj.data;
|
|
||||||
receiveAuthorData(authorMap);
|
|
||||||
|
|
||||||
var authors = _.map(padContents.getActiveAuthors(), function(name) {
|
|
||||||
return authorData[name];
|
|
||||||
});
|
|
||||||
|
|
||||||
BroadcastSlider.setAuthors(authors);
|
|
||||||
}
|
|
||||||
else if (obj['type'] == "NEW_SAVEDREV")
|
|
||||||
{
|
|
||||||
var savedRev = obj.savedRev;
|
|
||||||
BroadcastSlider.addSavedRevision(savedRev.revNum, savedRev);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
debugLog("incorrect message type: " + obj['type'] + ", expected " + expectedType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleSocketClosed(params)
|
|
||||||
{
|
|
||||||
debugLog("socket closed!", params);
|
|
||||||
socket = null;
|
|
||||||
|
|
||||||
BroadcastSlider.showReconnectUI();
|
|
||||||
// var reason = appLevelDisconnectReason || params.reason;
|
|
||||||
// var shouldReconnect = params.reconnect;
|
|
||||||
// if (shouldReconnect) {
|
|
||||||
// // determine if this is a tight reconnect loop due to weird connectivity problems
|
|
||||||
// // reconnectTimes.push(+new Date());
|
|
||||||
// var TOO_MANY_RECONNECTS = 8;
|
|
||||||
// var TOO_SHORT_A_TIME_MS = 10000;
|
|
||||||
// if (reconnectTimes.length >= TOO_MANY_RECONNECTS &&
|
|
||||||
// ((+new Date()) - reconnectTimes[reconnectTimes.length-TOO_MANY_RECONNECTS]) <
|
|
||||||
// TOO_SHORT_A_TIME_MS) {
|
|
||||||
// setChannelState("DISCONNECTED", "looping");
|
|
||||||
// }
|
|
||||||
// else {
|
|
||||||
// setChannelState("RECONNECTING", reason);
|
|
||||||
// setUpSocket();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// else {
|
|
||||||
// BroadcastSlider.showReconnectUI();
|
|
||||||
// setChannelState("DISCONNECTED", reason);
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendMessage(msg)
|
|
||||||
{
|
|
||||||
socket.postMessage(JSON.stringify(
|
|
||||||
{
|
|
||||||
type: "COLLABROOM",
|
|
||||||
data: msg
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function setChannelState(newChannelState, moreInfo)
|
|
||||||
{
|
|
||||||
if (newChannelState != channelState)
|
|
||||||
{
|
|
||||||
channelState = newChannelState;
|
|
||||||
// callbacks.onChannelStateChange(channelState, moreInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function abandonConnection(reason)
|
|
||||||
{
|
|
||||||
if (socket)
|
|
||||||
{
|
|
||||||
socket.onclosed = function()
|
|
||||||
{};
|
|
||||||
socket.onhiccup = function()
|
|
||||||
{};
|
|
||||||
socket.disconnect();
|
|
||||||
}
|
|
||||||
socket = null;
|
|
||||||
setChannelState("DISCONNECTED", reason);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Since its not used, import 'forEach' has been dropped
|
|
||||||
/*window['onloadFuncts'] = [];
|
|
||||||
window.onload = function ()
|
|
||||||
{
|
|
||||||
window['isloaded'] = true;
|
|
||||||
|
|
||||||
|
|
||||||
forEach(window['onloadFuncts'],function (funct)
|
|
||||||
{
|
|
||||||
funct();
|
|
||||||
});
|
|
||||||
};*/
|
|
||||||
|
|
||||||
// to start upon window load, just push a function onto this array
|
// to start upon window load, just push a function onto this array
|
||||||
//window['onloadFuncts'].push(setUpSocket);
|
//window['onloadFuncts'].push(setUpSocket);
|
||||||
//window['onloadFuncts'].push(function ()
|
//window['onloadFuncts'].push(function ()
|
||||||
|
@ -637,36 +539,19 @@ function loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, Bro
|
||||||
// this is necessary to keep infinite loops of events firing,
|
// this is necessary to keep infinite loops of events firing,
|
||||||
// since goToRevision changes the slider position
|
// since goToRevision changes the slider position
|
||||||
var goToRevisionIfEnabledCount = 0;
|
var goToRevisionIfEnabledCount = 0;
|
||||||
var goToRevisionIfEnabled = function()
|
var goToRevisionIfEnabled = function() {
|
||||||
|
if (goToRevisionIfEnabledCount > 0)
|
||||||
{
|
{
|
||||||
if (goToRevisionIfEnabledCount > 0)
|
goToRevisionIfEnabledCount--;
|
||||||
{
|
}
|
||||||
goToRevisionIfEnabledCount--;
|
else
|
||||||
}
|
{
|
||||||
else
|
goToRevision.apply(goToRevision, arguments);
|
||||||
{
|
}
|
||||||
goToRevision.apply(goToRevision, arguments);
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
BroadcastSlider.onSlider(goToRevisionIfEnabled);
|
BroadcastSlider.onSlider(goToRevisionIfEnabled);
|
||||||
|
|
||||||
(function()
|
|
||||||
{
|
|
||||||
for (var i = 0; i < clientVars.initialChangesets.length; i++)
|
|
||||||
{
|
|
||||||
var csgroup = clientVars.initialChangesets[i];
|
|
||||||
var start = clientVars.initialChangesets[i].start;
|
|
||||||
var granularity = clientVars.initialChangesets[i].granularity;
|
|
||||||
debugLog("loading changest on startup: ", start, granularity, csgroup);
|
|
||||||
changesetLoader.handleResponse(csgroup, start, granularity, null);
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
var dynamicCSS = makeCSSManager('dynamicsyntax');
|
var dynamicCSS = makeCSSManager('dynamicsyntax');
|
||||||
var authorData = {};
|
var authorData = {};
|
||||||
|
|
||||||
|
@ -686,7 +571,7 @@ function loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, Bro
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
receiveAuthorData(clientVars.historicalAuthorData);
|
receiveAuthorData(clientVars.collab_client_vars.historicalAuthorData);
|
||||||
|
|
||||||
return changesetLoader;
|
return changesetLoader;
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,7 @@ function loadBroadcastRevisionsJS()
|
||||||
endRevision.addChangeset(fromIndex, backChangeset, -1 * timeDelta);
|
endRevision.addChangeset(fromIndex, backChangeset, -1 * timeDelta);
|
||||||
}
|
}
|
||||||
|
|
||||||
revisionInfo.latest = clientVars.totalRevs || -1;
|
revisionInfo.latest = clientVars.collab_client_vars.rev || -1;
|
||||||
|
|
||||||
revisionInfo.createNew = function(index)
|
revisionInfo.createNew = function(index)
|
||||||
{
|
{
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
// These parameters were global, now they are injected. A reference to the
|
// These parameters were global, now they are injected. A reference to the
|
||||||
// Timeslider controller would probably be more appropriate.
|
// Timeslider controller would probably be more appropriate.
|
||||||
var _ = require('./underscore');
|
var _ = require('./underscore');
|
||||||
|
var padmodals = require('./pad_modals').padmodals;
|
||||||
|
|
||||||
function loadBroadcastSliderJS(fireWhenAllScriptsAreLoaded)
|
function loadBroadcastSliderJS(fireWhenAllScriptsAreLoaded)
|
||||||
{
|
{
|
||||||
|
@ -54,11 +55,7 @@ function loadBroadcastSliderJS(fireWhenAllScriptsAreLoaded)
|
||||||
{
|
{
|
||||||
slidercallbacks[i](newval);
|
slidercallbacks[i](newval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var updateSliderElements = function()
|
var updateSliderElements = function()
|
||||||
{
|
{
|
||||||
|
@ -68,12 +65,8 @@ function loadBroadcastSliderJS(fireWhenAllScriptsAreLoaded)
|
||||||
savedRevisions[i].css('left', (position * ($("#ui-slider-bar").width() - 2) / (sliderLength * 1.0)) - 1);
|
savedRevisions[i].css('left', (position * ($("#ui-slider-bar").width() - 2) / (sliderLength * 1.0)) - 1);
|
||||||
}
|
}
|
||||||
$("#ui-slider-handle").css('left', sliderPos * ($("#ui-slider-bar").width() - 2) / (sliderLength * 1.0));
|
$("#ui-slider-handle").css('left', sliderPos * ($("#ui-slider-bar").width() - 2) / (sliderLength * 1.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var addSavedRevision = function(position, info)
|
var addSavedRevision = function(position, info)
|
||||||
{
|
{
|
||||||
var newSavedRevision = $('<div></div>');
|
var newSavedRevision = $('<div></div>');
|
||||||
|
@ -88,7 +81,7 @@ function loadBroadcastSliderJS(fireWhenAllScriptsAreLoaded)
|
||||||
BroadcastSlider.setSliderPosition(position);
|
BroadcastSlider.setSliderPosition(position);
|
||||||
});
|
});
|
||||||
savedRevisions.push(newSavedRevision);
|
savedRevisions.push(newSavedRevision);
|
||||||
};
|
};
|
||||||
|
|
||||||
var removeSavedRevision = function(position)
|
var removeSavedRevision = function(position)
|
||||||
{
|
{
|
||||||
|
@ -96,7 +89,7 @@ function loadBroadcastSliderJS(fireWhenAllScriptsAreLoaded)
|
||||||
savedRevisions.remove(element);
|
savedRevisions.remove(element);
|
||||||
element.remove();
|
element.remove();
|
||||||
return element;
|
return element;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Begin small 'API' */
|
/* Begin small 'API' */
|
||||||
|
|
||||||
|
@ -162,9 +155,9 @@ function loadBroadcastSliderJS(fireWhenAllScriptsAreLoaded)
|
||||||
|
|
||||||
function showReconnectUI()
|
function showReconnectUI()
|
||||||
{
|
{
|
||||||
$("#padmain, #rightbars").css('top', "130px");
|
var cls = 'modaldialog cboxdisconnected cboxdisconnected_unknown';
|
||||||
$("#timeslider").show();
|
$("#connectionbox").get(0).className = cls;
|
||||||
$('#error').show();
|
padmodals.showModal("#connectionbox", 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
var fixPadHeight = _.throttle(function(){
|
var fixPadHeight = _.throttle(function(){
|
||||||
|
@ -481,8 +474,8 @@ function loadBroadcastSliderJS(fireWhenAllScriptsAreLoaded)
|
||||||
}
|
}
|
||||||
|
|
||||||
$("#timeslider").show();
|
$("#timeslider").show();
|
||||||
setSliderLength(clientVars.totalRevs);
|
setSliderLength(clientVars.collab_client_vars.rev);
|
||||||
setSliderPosition(clientVars.revNum);
|
setSliderPosition(clientVars.collab_client_vars.rev);
|
||||||
|
|
||||||
_.each(clientVars.savedRevisions, function(revision)
|
_.each(clientVars.savedRevisions, function(revision)
|
||||||
{
|
{
|
||||||
|
|
|
@ -310,14 +310,20 @@ function handshake()
|
||||||
receivedClientVars = true;
|
receivedClientVars = true;
|
||||||
|
|
||||||
//set some client vars
|
//set some client vars
|
||||||
clientVars = obj;
|
clientVars = obj.data;
|
||||||
clientVars.userAgent = "Anonymous";
|
clientVars.userAgent = "Anonymous";
|
||||||
clientVars.collab_client_vars.clientAgent = "Anonymous";
|
clientVars.collab_client_vars.clientAgent = "Anonymous";
|
||||||
|
|
||||||
//initalize the pad
|
//initalize the pad
|
||||||
pad._afterHandshake();
|
pad._afterHandshake();
|
||||||
initalized = true;
|
initalized = true;
|
||||||
|
|
||||||
|
$("body").addClass(clientVars.readonly ? "readonly" : "readwrite")
|
||||||
|
|
||||||
|
padeditor.ace.callWithAce(function (ace) {
|
||||||
|
ace.ace_setEditable(!clientVars.readonly);
|
||||||
|
});
|
||||||
|
|
||||||
// If the LineNumbersDisabled value is set to true then we need to hide the Line Numbers
|
// If the LineNumbersDisabled value is set to true then we need to hide the Line Numbers
|
||||||
if (settings.LineNumbersDisabled == true)
|
if (settings.LineNumbersDisabled == true)
|
||||||
{
|
{
|
||||||
|
@ -354,6 +360,8 @@ function handshake()
|
||||||
//this message advices the client to disconnect
|
//this message advices the client to disconnect
|
||||||
if (obj.disconnect)
|
if (obj.disconnect)
|
||||||
{
|
{
|
||||||
|
console.warn("FORCED TO DISCONNECT");
|
||||||
|
console.warn(obj);
|
||||||
padconnectionstatus.disconnected(obj.disconnect);
|
padconnectionstatus.disconnected(obj.disconnect);
|
||||||
socket.disconnect();
|
socket.disconnect();
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -241,7 +241,7 @@ var padeditbar = (function()
|
||||||
if ($('#readonlyinput').is(':checked'))
|
if ($('#readonlyinput').is(':checked'))
|
||||||
{
|
{
|
||||||
var basePath = document.location.href.substring(0, document.location.href.indexOf("/p/"));
|
var basePath = document.location.href.substring(0, document.location.href.indexOf("/p/"));
|
||||||
var readonlyLink = basePath + "/ro/" + clientVars.readOnlyId;
|
var readonlyLink = basePath + "/p/" + clientVars.readOnlyId;
|
||||||
$('#embedinput').val("<iframe name='embed_readonly' src='" + readonlyLink + "?showControls=true&showChat=true&showLineNumbers=true&useMonospaceFont=false' width=600 height=400>");
|
$('#embedinput').val("<iframe name='embed_readonly' src='" + readonlyLink + "?showControls=true&showChat=true&showLineNumbers=true&useMonospaceFont=false' width=600 height=400>");
|
||||||
$('#linkinput').val(readonlyLink);
|
$('#linkinput').val(readonlyLink);
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,7 @@ var padmodals = (function()
|
||||||
{
|
{
|
||||||
$("#modaloverlay").hide();
|
$("#modaloverlay").hide();
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
return self;
|
return self;
|
||||||
}());
|
}());
|
||||||
|
|
|
@ -19,19 +19,21 @@
|
||||||
* @params reqModuleName Module name e.g. (ep_etherpad-lite/static/js/plugins)
|
* @params reqModuleName Module name e.g. (ep_etherpad-lite/static/js/plugins)
|
||||||
*/
|
*/
|
||||||
exports.getRequirementFromParent = function(requireDefObj, reqModuleName) {
|
exports.getRequirementFromParent = function(requireDefObj, reqModuleName) {
|
||||||
requireDefObj.define(reqModuleName, function(require, exports, module) {
|
// Force the 'undefinition' of the modules (if they already have been loaded).
|
||||||
var t = parent;
|
delete (requireDefObj._definitions)[reqModuleName];
|
||||||
var max = 0; // make sure I don't go up more than 10 times
|
delete (requireDefObj._modules)[reqModuleName];
|
||||||
while (typeof(t) != "undefined") {
|
requireDefObj.define(reqModuleName, function(require, exports, module) {
|
||||||
max++;
|
var t = parent;
|
||||||
if (max==10)
|
var max = 0; // make sure I don't go up more than 10 times
|
||||||
break;
|
while (typeof(t) != "undefined") {
|
||||||
if (typeof(t.require) != "undefined") {
|
max++;
|
||||||
module.exports = t.require(reqModuleName);
|
if (max==10)
|
||||||
return;
|
break;
|
||||||
}
|
if (typeof(t.require) != "undefined") {
|
||||||
t = t.parent;
|
module.exports = t.require(reqModuleName);
|
||||||
}
|
return;
|
||||||
});
|
}
|
||||||
|
t = t.parent;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,6 +70,11 @@ function init() {
|
||||||
sendSocketMsg("CLIENT_READY", {});
|
sendSocketMsg("CLIENT_READY", {});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
socket.on('disconnect', function()
|
||||||
|
{
|
||||||
|
BroadcastSlider.showReconnectUI();
|
||||||
|
});
|
||||||
|
|
||||||
//route the incoming messages
|
//route the incoming messages
|
||||||
socket.on('message', function(message)
|
socket.on('message', function(message)
|
||||||
{
|
{
|
||||||
|
@ -79,13 +84,11 @@ function init() {
|
||||||
{
|
{
|
||||||
handleClientVars(message);
|
handleClientVars(message);
|
||||||
}
|
}
|
||||||
else if(message.type == "CHANGESET_REQ")
|
|
||||||
{
|
|
||||||
changesetLoader.handleSocketResponse(message);
|
|
||||||
}
|
|
||||||
else if(message.accessStatus)
|
else if(message.accessStatus)
|
||||||
{
|
{
|
||||||
$("body").html("<h2>You have no permission to access this pad</h2>")
|
$("body").html("<h2>You have no permission to access this pad</h2>")
|
||||||
|
} else {
|
||||||
|
changesetLoader.handleMessageFromServer(message);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -97,6 +100,12 @@ function init() {
|
||||||
} else {
|
} else {
|
||||||
$("#returnbutton").attr("href", document.location.href.substring(0,document.location.href.lastIndexOf("/")));
|
$("#returnbutton").attr("href", document.location.href.substring(0,document.location.href.lastIndexOf("/")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$('button#forcereconnect').click(function()
|
||||||
|
{
|
||||||
|
window.location.reload();
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,7 +115,7 @@ function sendSocketMsg(type, data)
|
||||||
var sessionID = readCookie("sessionID");
|
var sessionID = readCookie("sessionID");
|
||||||
var password = readCookie("password");
|
var password = readCookie("password");
|
||||||
|
|
||||||
var msg = { "component" : "timeslider",
|
var msg = { "component" : "pad", // FIXME: Remove this stupidity!
|
||||||
"type": type,
|
"type": type,
|
||||||
"data": data,
|
"data": data,
|
||||||
"padId": padId,
|
"padId": padId,
|
||||||
|
|
|
@ -24,60 +24,60 @@
|
||||||
<div id="editbar" class="toolbar">
|
<div id="editbar" class="toolbar">
|
||||||
<ul class="menu_left">
|
<ul class="menu_left">
|
||||||
<% e.begin_block("editbarMenuLeft"); %>
|
<% e.begin_block("editbarMenuLeft"); %>
|
||||||
<li id="bold" data-key="bold">
|
<li class="acl-write" id="bold" data-key="bold">
|
||||||
<a class="grouped-left" title="Bold (ctrl-B)">
|
<a class="grouped-left" title="Bold (ctrl-B)">
|
||||||
<span class="buttonicon buttonicon-bold"></span>
|
<span class="buttonicon buttonicon-bold"></span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li id="italic" data-key="italic">
|
<li class="acl-write" id="italic" data-key="italic">
|
||||||
<a class="grouped-middle" title="Italics (ctrl-I)">
|
<a class="grouped-middle" title="Italics (ctrl-I)">
|
||||||
<span class="buttonicon buttonicon-italic"></span>
|
<span class="buttonicon buttonicon-italic"></span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li id="underline" data-key="underline">
|
<li class="acl-write" id="underline" data-key="underline">
|
||||||
<a class="grouped-middle" title="Underline (ctrl-U)">
|
<a class="grouped-middle" title="Underline (ctrl-U)">
|
||||||
<span class="buttonicon buttonicon-underline"></span>
|
<span class="buttonicon buttonicon-underline"></span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li id="strikethrough" data-key="strikethrough">
|
<li class="acl-write" id="strikethrough" data-key="strikethrough">
|
||||||
<a class="grouped-right" title="Strikethrough">
|
<a class="grouped-right" title="Strikethrough">
|
||||||
<span class="buttonicon buttonicon-strikethrough"></span>
|
<span class="buttonicon buttonicon-strikethrough"></span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="separator"></li>
|
<li class="acl-write separator"></li>
|
||||||
<li id="oderedlist" data-key="insertorderedlist">
|
<li class="acl-write" id="oderedlist" data-key="insertorderedlist">
|
||||||
<a class="grouped-left" title="Toggle Ordered List">
|
<a class="grouped-left" title="Toggle Ordered List">
|
||||||
<span class="buttonicon buttonicon-insertorderedlist"></span>
|
<span class="buttonicon buttonicon-insertorderedlist"></span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li id="unoderedlist" data-key="insertunorderedlist">
|
<li class="acl-write" id="unoderedlist" data-key="insertunorderedlist">
|
||||||
<a class="grouped-middle" title="Toggle Bullet List">
|
<a class="grouped-middle" title="Toggle Bullet List">
|
||||||
<span class="buttonicon buttonicon-insertunorderedlist"></span>
|
<span class="buttonicon buttonicon-insertunorderedlist"></span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li id="indent" data-key="indent">
|
<li class="acl-write" id="indent" data-key="indent">
|
||||||
<a class="grouped-middle" title="Indent">
|
<a class="grouped-middle" title="Indent">
|
||||||
<span class="buttonicon buttonicon-indent"></span>
|
<span class="buttonicon buttonicon-indent"></span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li id="outdent" data-key="outdent">
|
<li class="acl-write" id="outdent" data-key="outdent">
|
||||||
<a class="grouped-right" title="Unindent">
|
<a class="grouped-right" title="Unindent">
|
||||||
<span class="buttonicon buttonicon-outdent"></span>
|
<span class="buttonicon buttonicon-outdent"></span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="separator"></li>
|
<li class="acl-write separator"></li>
|
||||||
<li id="undo" data-key="undo">
|
<li class="acl-write" id="undo" data-key="undo">
|
||||||
<a class="grouped-left" title="Undo (ctrl-Z)">
|
<a class="grouped-left" title="Undo (ctrl-Z)">
|
||||||
<span class="buttonicon buttonicon-undo"></span>
|
<span class="buttonicon buttonicon-undo"></span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li id="redo" data-key="redo">
|
<li class="acl-write" id="redo" data-key="redo">
|
||||||
<a class="grouped-right" title="Redo (ctrl-Y)">
|
<a class="grouped-right" title="Redo (ctrl-Y)">
|
||||||
<span class="buttonicon buttonicon-redo"></span>
|
<span class="buttonicon buttonicon-redo"></span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="separator"></li>
|
<li class="acl-write separator"></li>
|
||||||
<li id="clearAuthorship" data-key="clearauthorship">
|
<li class="acl-write" id="clearAuthorship" data-key="clearauthorship">
|
||||||
<a title="Clear Authorship Colors">
|
<a title="Clear Authorship Colors">
|
||||||
<span class="buttonicon buttonicon-clearauthorship"></span>
|
<span class="buttonicon buttonicon-clearauthorship"></span>
|
||||||
</a>
|
</a>
|
||||||
|
@ -86,24 +86,25 @@
|
||||||
</ul>
|
</ul>
|
||||||
<ul class="menu_right">
|
<ul class="menu_right">
|
||||||
<% e.begin_block("editbarMenuRight"); %>
|
<% e.begin_block("editbarMenuRight"); %>
|
||||||
<li data-key="settings">
|
<li class="acl-write" data-key="settings">
|
||||||
<a class="grouped-left" id="settingslink" title="Settings of this pad">
|
<a class="grouped-left" id="settingslink" title="Settings of this pad">
|
||||||
<span class="buttonicon buttonicon-settings"></span>
|
<span class="buttonicon buttonicon-settings"></span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="acl-write" data-key="savedRevision">
|
||||||
|
<a class="grouped-right" id="revisionlink" title="Mark this revision as a saved revision">
|
||||||
|
<span class="buttonicon buttonicon-savedRevision"></span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="acl-write separator"></li>
|
||||||
<li data-key="import_export">
|
<li data-key="import_export">
|
||||||
<a class="grouped-middle" id="importexportlink" title="Import/Export from/to different document formats">
|
<a class="grouped-left" id="importexportlink" title="Import/Export from/to different document formats">
|
||||||
<span class="buttonicon buttonicon-import_export"></span>
|
<span class="buttonicon buttonicon-import_export"></span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li data-key="embed">
|
<li data-key="embed">
|
||||||
<a class="grouped-middle" id="embedlink" title="Share and Embed this pad">
|
<a class="grouped-right" id="embedlink" title="Share and Embed this pad">
|
||||||
<span class="buttonicon buttonicon-embed"></span>
|
<span class="grouped-right buttonicon buttonicon-embed"></span>
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li data-key="savedRevision">
|
|
||||||
<a class="grouped-right" id="revisionlink" title="Mark this revision as a saved revision">
|
|
||||||
<span class="buttonicon buttonicon-savedRevision"></span>
|
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="separator"></li>
|
<li class="separator"></li>
|
||||||
|
@ -185,7 +186,7 @@
|
||||||
|
|
||||||
<div id="importexport" class="popup">
|
<div id="importexport" class="popup">
|
||||||
<h1>Import/Export</h1>
|
<h1>Import/Export</h1>
|
||||||
<div class="column">
|
<div class="column acl-write">
|
||||||
<% e.begin_block("importColumn"); %>
|
<% e.begin_block("importColumn"); %>
|
||||||
<h2>Upload any text file or document</h2><br>
|
<h2>Upload any text file or document</h2><br>
|
||||||
<form id="importform" method="post" action="" target="importiframe" enctype="multipart/form-data">
|
<form id="importform" method="post" action="" target="importiframe" enctype="multipart/form-data">
|
||||||
|
@ -221,7 +222,7 @@
|
||||||
|
|
||||||
<div id="embed" class="popup">
|
<div id="embed" class="popup">
|
||||||
<% e.begin_block("embedPopup"); %>
|
<% e.begin_block("embedPopup"); %>
|
||||||
<div id="embedreadonly" class="right">
|
<div id="embedreadonly" class="right acl-write">
|
||||||
<input type="checkbox" id="readonlyinput" onClick="padeditbar.setEmbedLinks();">
|
<input type="checkbox" id="readonlyinput" onClick="padeditbar.setEmbedLinks();">
|
||||||
<label for="readonlyinput">Read only</label>
|
<label for="readonlyinput">Read only</label>
|
||||||
</div>
|
</div>
|
||||||
|
@ -313,15 +314,14 @@
|
||||||
|
|
||||||
<% e.begin_block("scripts"); %>
|
<% e.begin_block("scripts"); %>
|
||||||
<script type="text/javascript" src="../static/js/require-kernel.js"></script>
|
<script type="text/javascript" src="../static/js/require-kernel.js"></script>
|
||||||
<script type="text/javascript" src="../static/js/jquery.js"></script>
|
|
||||||
<script type="text/javascript" src="../socket.io/socket.io.js"></script>
|
<script type="text/javascript" src="../socket.io/socket.io.js"></script>
|
||||||
<script type="text/javascript" src="../javascripts/lib/ep_etherpad-lite/static/js/pad.js?callback=require.define"></script>
|
|
||||||
<script type="text/javascript">
|
|
||||||
if ((!$.browser.msie) && (!($.browser.mozilla && $.browser.version.indexOf("1.8.") == 0)))
|
|
||||||
{
|
|
||||||
document.domain = document.domain; // for comet
|
|
||||||
}
|
|
||||||
|
|
||||||
|
<!-- Include base packages manually (this help with debugging) -->
|
||||||
|
<script type="text/javascript" src="../javascripts/lib/ep_etherpad-lite/static/js/pad.js?callback=require.define"></script>
|
||||||
|
<script type="text/javascript" src="../javascripts/lib/ep_etherpad-lite/static/js/ace2_common.js?callback=require.define"></script>
|
||||||
|
|
||||||
|
<!-- Bootstrap page -->
|
||||||
|
<script type="text/javascript">
|
||||||
var clientVars = {};
|
var clientVars = {};
|
||||||
(function () {
|
(function () {
|
||||||
|
|
||||||
|
@ -335,6 +335,12 @@
|
||||||
require.setLibraryURI(baseURL + "javascripts/lib");
|
require.setLibraryURI(baseURL + "javascripts/lib");
|
||||||
require.setGlobalKeyPath("require");
|
require.setGlobalKeyPath("require");
|
||||||
|
|
||||||
|
$ = jQuery = require('ep_etherpad-lite/static/js/rjquery').jQuery; // Expose jQuery #HACK
|
||||||
|
|
||||||
|
if ((!$.browser.msie) && (!($.browser.mozilla && $.browser.version.indexOf("1.8.") == 0))) {
|
||||||
|
document.domain = document.domain; // for comet
|
||||||
|
}
|
||||||
|
|
||||||
var plugins = require('ep_etherpad-lite/static/js/pluginfw/plugins');
|
var plugins = require('ep_etherpad-lite/static/js/pluginfw/plugins');
|
||||||
plugins.baseURL = baseURL;
|
plugins.baseURL = baseURL;
|
||||||
plugins.update(function () {
|
plugins.update(function () {
|
||||||
|
|
|
@ -76,7 +76,48 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="mainmodals"></div>
|
<div id="mainmodals">
|
||||||
|
<% e.begin_block("modals"); %>
|
||||||
|
<div id="connectionbox" class="modaldialog">
|
||||||
|
<div id="connectionboxinner" class="modaldialog-inner">
|
||||||
|
<div class="connecting">Connecting...</div>
|
||||||
|
<div class="reconnecting">Reestablishing connection...</div>
|
||||||
|
<div class="disconnected">
|
||||||
|
<h2 class="h2_disconnect">Disconnected.</h2>
|
||||||
|
<h2 class="h2_userdup">Opened in another window.</h2>
|
||||||
|
<h2 class="h2_unauth">No Authorization.</h2>
|
||||||
|
<div id="disconnected_looping">
|
||||||
|
<p><b>We're having trouble talking to the EtherPad lite synchronization server.</b> You may be connecting through an incompatible firewall or proxy server.</p>
|
||||||
|
</div>
|
||||||
|
<div id="disconnected_initsocketfail">
|
||||||
|
<p><b>We were unable to connect to the EtherPad lite synchronization server.</b> This may be due to an incompatibility with your web browser or internet connection.</p>
|
||||||
|
</div>
|
||||||
|
<div id="disconnected_userdup">
|
||||||
|
<p><b>You seem to have opened this pad in another browser window.</b> If you'd like to use this window instead, you can reconnect.</p>
|
||||||
|
</div>
|
||||||
|
<div id="disconnected_unknown">
|
||||||
|
<p><b>Lost connection with the EtherPad lite synchronization server.</b> This may be due to a loss of network connectivity.</p>
|
||||||
|
</div>
|
||||||
|
<div id="disconnected_slowcommit">
|
||||||
|
<p><b>Server not responding.</b> This may be due to network connectivity issues or high load on the server.</p>
|
||||||
|
</div>
|
||||||
|
<div id="disconnected_unauth">
|
||||||
|
<p>Your browser's credentials or permissions have changed while viewing this pad. Try reconnecting.</p>
|
||||||
|
</div>
|
||||||
|
<div id="disconnected_deleted">
|
||||||
|
<p>This pad was deleted.</p>
|
||||||
|
</div>
|
||||||
|
<div id="reconnect_advise">
|
||||||
|
<p>If this continues to happen, please let us know</p>
|
||||||
|
</div>
|
||||||
|
<div id="reconnect_form">
|
||||||
|
<button id="forcereconnect">Reconnect Now</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% e.end_block(); %>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- export code -->
|
<!-- export code -->
|
||||||
<div id="importexport">
|
<div id="importexport">
|
||||||
|
@ -93,17 +134,16 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script type="text/javascript" src="../../static/js/require-kernel.js"></script>
|
<script type="text/javascript" src="../../static/js/require-kernel.js"></script>
|
||||||
<script type="text/javascript" src="../../static/js/jquery.js"></script>
|
|
||||||
<script type="text/javascript" src="../../socket.io/socket.io.js"></script>
|
<script type="text/javascript" src="../../socket.io/socket.io.js"></script>
|
||||||
|
|
||||||
|
<!-- Include base packages manually (this help with debugging) -->
|
||||||
<script type="text/javascript" src="../../javascripts/lib/ep_etherpad-lite/static/js/timeslider.js?callback=require.define"></script>
|
<script type="text/javascript" src="../../javascripts/lib/ep_etherpad-lite/static/js/timeslider.js?callback=require.define"></script>
|
||||||
|
<script type="text/javascript" src="../../javascripts/lib/ep_etherpad-lite/static/js/ace2_common.js?callback=require.define"></script>
|
||||||
|
|
||||||
<script type="text/javascript" src="../../static/custom/timeslider.js"></script>
|
<script type="text/javascript" src="../../static/custom/timeslider.js"></script>
|
||||||
|
|
||||||
|
<!-- Bootstrap -->
|
||||||
<script type="text/javascript" >
|
<script type="text/javascript" >
|
||||||
if ((!$.browser.msie) && (!($.browser.mozilla && $.browser.version.indexOf("1.8.") == 0)))
|
|
||||||
{
|
|
||||||
document.domain = document.domain; // for comet
|
|
||||||
}
|
|
||||||
|
|
||||||
var clientVars = {};
|
var clientVars = {};
|
||||||
|
|
||||||
(function () {
|
(function () {
|
||||||
|
@ -118,6 +158,12 @@
|
||||||
require.setLibraryURI(baseURL + "javascripts/lib");
|
require.setLibraryURI(baseURL + "javascripts/lib");
|
||||||
require.setGlobalKeyPath("require");
|
require.setGlobalKeyPath("require");
|
||||||
|
|
||||||
|
$ = jQuery = require('ep_etherpad-lite/static/js/rjquery').jQuery; // Expose jQuery #HACK
|
||||||
|
|
||||||
|
if ((!$.browser.msie) && (!($.browser.mozilla && $.browser.version.indexOf("1.8.") == 0))) {
|
||||||
|
document.domain = document.domain; // for comet
|
||||||
|
}
|
||||||
|
|
||||||
var plugins = require('ep_etherpad-lite/static/js/pluginfw/plugins');
|
var plugins = require('ep_etherpad-lite/static/js/pluginfw/plugins');
|
||||||
plugins.baseURL = baseURL;
|
plugins.baseURL = baseURL;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue