mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-04-24 17:36:14 -04:00
Merge branch 'develop' of https://github.com/Pita/etherpad-lite into develop
This commit is contained in:
commit
de9b3c3975
15 changed files with 334 additions and 42 deletions
35
bin/installOnWindows.bat
Normal file
35
bin/installOnWindows.bat
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
@echo off
|
||||||
|
set NODE_VERSION=0.6.5
|
||||||
|
set JQUERY_VERSION=1.7
|
||||||
|
|
||||||
|
:: change directory to etherpad-lite root
|
||||||
|
cd bin
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
echo _
|
||||||
|
echo Setting up settings.json...
|
||||||
|
copy settings.json.template_windows settings.json
|
||||||
|
|
||||||
|
echo _
|
||||||
|
echo Updating node...
|
||||||
|
curl -lo bin\node.exe http://nodejs.org/dist/v%NODE_VERSION%/node.exe
|
||||||
|
|
||||||
|
echo _
|
||||||
|
echo Installing etherpad-lite and dependencies...
|
||||||
|
cmd /C npm install src/
|
||||||
|
|
||||||
|
echo _
|
||||||
|
echo Updating jquery...
|
||||||
|
curl -lo "node_modules\ep_etherpad-lite\static\js\jquery.min.js" "http://code.jquery.com/jquery-%JQUERY_VERSION%.min.js"
|
||||||
|
|
||||||
|
echo _
|
||||||
|
echo Some other stuff...
|
||||||
|
copy node_modules\ep_etherpad-lite\static\custom\js.template node_modules\ep_etherpad-lite\static\custom\index.template
|
||||||
|
copy node_modules\ep_etherpad-lite\static\custom\js.template node_modules\ep_etherpad-lite\static\custom\pad.template
|
||||||
|
copy node_modules\ep_etherpad-lite\static\custom\js.template node_modules\ep_etherpad-lite\static\custom\timeslider.template
|
||||||
|
copy node_modules\ep_etherpad-lite\static\custom\css.template node_modules\ep_etherpad-lite\static\custom\index.template
|
||||||
|
copy node_modules\ep_etherpad-lite\static\custom\css.template node_modules\ep_etherpad-lite\static\custom\pad.template
|
||||||
|
copy node_modules\ep_etherpad-lite\static\custom\css.template node_modules\ep_etherpad-lite\static\custom\timeslider.template
|
||||||
|
|
||||||
|
echo _
|
||||||
|
echo Installed Etherpad-lite!
|
|
@ -8,8 +8,8 @@
|
||||||
"ip": "0.0.0.0",
|
"ip": "0.0.0.0",
|
||||||
"port" : 9001,
|
"port" : 9001,
|
||||||
|
|
||||||
//The Type of the database. You can choose between dirty, sqlite and mysql
|
//The Type of the database. You can choose between dirty, postgres, sqlite and mysql
|
||||||
//You should use mysql or sqlite for anything else than testing or development
|
//You shouldn't use "dirty" for for anything else than testing or development
|
||||||
"dbType" : "dirty",
|
"dbType" : "dirty",
|
||||||
//the database specific settings
|
//the database specific settings
|
||||||
"dbSettings" : {
|
"dbSettings" : {
|
||||||
|
|
|
@ -47,6 +47,7 @@ exports.createGroupPad = groupManager.createGroupPad;
|
||||||
|
|
||||||
exports.createAuthor = authorManager.createAuthor;
|
exports.createAuthor = authorManager.createAuthor;
|
||||||
exports.createAuthorIfNotExistsFor = authorManager.createAuthorIfNotExistsFor;
|
exports.createAuthorIfNotExistsFor = authorManager.createAuthorIfNotExistsFor;
|
||||||
|
exports.listPadsOfAuthor = authorManager.listPadsOfAuthor;
|
||||||
|
|
||||||
/**********************/
|
/**********************/
|
||||||
/**SESSION FUNCTIONS***/
|
/**SESSION FUNCTIONS***/
|
||||||
|
@ -282,6 +283,24 @@ exports.getRevisionsCount = function(padID, callback)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
getLastEdited(padID) returns the timestamp of the last revision of the pad
|
||||||
|
|
||||||
|
Example returns:
|
||||||
|
|
||||||
|
{code: 0, message:"ok", data: {lastEdited: 1340815946602}}
|
||||||
|
{code: 1, message:"padID does not exist", data: null}
|
||||||
|
*/
|
||||||
|
exports.getLastEdited = function(padID, callback)
|
||||||
|
{
|
||||||
|
//get the pad
|
||||||
|
getPadSafe(padID, true, function(err, pad)
|
||||||
|
{
|
||||||
|
if(ERR(err, callback)) return;
|
||||||
|
callback(null, {lastEdited: pad.getLastEdited()});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
createPad(padName [, text]) creates a new pad in this group
|
createPad(padName [, text]) creates a new pad in this group
|
||||||
|
|
||||||
|
@ -463,6 +482,26 @@ exports.isPasswordProtected = function(padID, callback)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
listAuthorsOfPad(padID) returns an array of authors who contributed to this pad
|
||||||
|
|
||||||
|
Example returns:
|
||||||
|
|
||||||
|
{code: 0, message:"ok", data: {authorIDs : ["a.s8oes9dhwrvt0zif", "a.akf8finncvomlqva"]}
|
||||||
|
{code: 1, message:"padID does not exist", data: null}
|
||||||
|
*/
|
||||||
|
exports.listAuthorsOfPad = function(padID, callback)
|
||||||
|
{
|
||||||
|
//get the pad
|
||||||
|
getPadSafe(padID, true, function(err, pad)
|
||||||
|
{
|
||||||
|
if(ERR(err, callback)) return;
|
||||||
|
|
||||||
|
callback(null, {authorIDs: pad.getAllAuthors()});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/******************************/
|
/******************************/
|
||||||
/** INTERNAL HELPER FUNCTIONS */
|
/** INTERNAL HELPER FUNCTIONS */
|
||||||
/******************************/
|
/******************************/
|
||||||
|
|
|
@ -55,6 +55,7 @@ exports.getAuthor4Token = function (token, callback)
|
||||||
/**
|
/**
|
||||||
* Returns the AuthorID for a mapper.
|
* Returns the AuthorID for a mapper.
|
||||||
* @param {String} token The mapper
|
* @param {String} token The mapper
|
||||||
|
* @param {String} name The name of the author (optional)
|
||||||
* @param {Function} callback callback (err, author)
|
* @param {Function} callback callback (err, author)
|
||||||
*/
|
*/
|
||||||
exports.createAuthorIfNotExistsFor = function (authorMapper, name, callback)
|
exports.createAuthorIfNotExistsFor = function (authorMapper, name, callback)
|
||||||
|
@ -153,6 +154,7 @@ exports.getAuthorColorId = function (author, callback)
|
||||||
/**
|
/**
|
||||||
* Sets the color Id of the author
|
* Sets the color Id of the author
|
||||||
* @param {String} author The id of the author
|
* @param {String} author The id of the author
|
||||||
|
* @param {String} colorId The color id of the author
|
||||||
* @param {Function} callback (optional)
|
* @param {Function} callback (optional)
|
||||||
*/
|
*/
|
||||||
exports.setAuthorColorId = function (author, colorId, callback)
|
exports.setAuthorColorId = function (author, colorId, callback)
|
||||||
|
@ -173,9 +175,95 @@ exports.getAuthorName = function (author, callback)
|
||||||
/**
|
/**
|
||||||
* Sets the name of the author
|
* Sets the name of the author
|
||||||
* @param {String} author The id of the author
|
* @param {String} author The id of the author
|
||||||
|
* @param {String} name The name of the author
|
||||||
* @param {Function} callback (optional)
|
* @param {Function} callback (optional)
|
||||||
*/
|
*/
|
||||||
exports.setAuthorName = function (author, name, callback)
|
exports.setAuthorName = function (author, name, callback)
|
||||||
{
|
{
|
||||||
db.setSub("globalAuthor:" + author, ["name"], name, callback);
|
db.setSub("globalAuthor:" + author, ["name"], name, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of all pads this author contributed to
|
||||||
|
* @param {String} author The id of the author
|
||||||
|
* @param {Function} callback (optional)
|
||||||
|
*/
|
||||||
|
exports.listPadsOfAuthor = function (authorID, callback)
|
||||||
|
{
|
||||||
|
/* There are two other places where this array is manipulated:
|
||||||
|
* (1) When the author is added to a pad, the author object is also updated
|
||||||
|
* (2) When a pad is deleted, each author of that pad is also updated
|
||||||
|
*/
|
||||||
|
//get the globalAuthor
|
||||||
|
db.get("globalAuthor:" + authorID, function(err, author)
|
||||||
|
{
|
||||||
|
if(ERR(err, callback)) return;
|
||||||
|
|
||||||
|
//author does not exists
|
||||||
|
if(author == null)
|
||||||
|
{
|
||||||
|
callback(new customError("authorID does not exist","apierror"))
|
||||||
|
}
|
||||||
|
//everything is fine, return the pad IDs
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var pads = [];
|
||||||
|
if(author.padIDs != null)
|
||||||
|
{
|
||||||
|
for (var padId in author.padIDs)
|
||||||
|
{
|
||||||
|
pads.push(padId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
callback(null, {padIDs: pads});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new pad to the list of contributions
|
||||||
|
* @param {String} author The id of the author
|
||||||
|
* @param {String} padID The id of the pad the author contributes to
|
||||||
|
*/
|
||||||
|
exports.addPad = function (authorID, padID)
|
||||||
|
{
|
||||||
|
//get the entry
|
||||||
|
db.get("globalAuthor:" + authorID, function(err, author)
|
||||||
|
{
|
||||||
|
if(ERR(err)) return;
|
||||||
|
if(author == null) return;
|
||||||
|
|
||||||
|
//the entry doesn't exist so far, let's create it
|
||||||
|
if(author.padIDs == null)
|
||||||
|
{
|
||||||
|
author.padIDs = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
//add the entry for this pad
|
||||||
|
author.padIDs[padID] = 1;// anything, because value is not used
|
||||||
|
|
||||||
|
//save the new element back
|
||||||
|
db.set("globalAuthor:" + authorID, author);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a pad from the list of contributions
|
||||||
|
* @param {String} author The id of the author
|
||||||
|
* @param {String} padID The id of the pad the author contributes to
|
||||||
|
*/
|
||||||
|
exports.removePad = function (authorID, padID)
|
||||||
|
{
|
||||||
|
db.get("globalAuthor:" + authorID, function (err, author)
|
||||||
|
{
|
||||||
|
if(ERR(err)) return;
|
||||||
|
if(author == null) return;
|
||||||
|
|
||||||
|
if(author.padIDs != null)
|
||||||
|
{
|
||||||
|
//remove pad from author
|
||||||
|
delete author.padIDs[padID];
|
||||||
|
db.set("globalAuthor:" + authorID, author);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
|
@ -80,8 +80,12 @@ Pad.prototype.appendRevision = function appendRevision(aChangeset, author) {
|
||||||
newRevData.meta.atext = this.atext;
|
newRevData.meta.atext = this.atext;
|
||||||
}
|
}
|
||||||
|
|
||||||
db.set("pad:"+this.id+":revs:"+newRev, newRevData);
|
db.set("pad:"+this.id+":revs:"+newRev, newRevData);
|
||||||
this.saveToDatabase();
|
this.saveToDatabase();
|
||||||
|
|
||||||
|
// set the author to pad
|
||||||
|
if(author)
|
||||||
|
authorManager.addPad(author, this.id);
|
||||||
};
|
};
|
||||||
|
|
||||||
//save all attributes to the database
|
//save all attributes to the database
|
||||||
|
@ -102,6 +106,12 @@ Pad.prototype.saveToDatabase = function saveToDatabase(){
|
||||||
db.set("pad:"+this.id, dbObject);
|
db.set("pad:"+this.id, dbObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get time of last edit (changeset application)
|
||||||
|
Pad.prototype.getLastEdit = function getLastEdit(callback){
|
||||||
|
var revNum = this.getHeadRevisionNumber();
|
||||||
|
db.getSub("pad:"+this.id+":revs:"+revNum, ["meta", "timestamp"], callback);
|
||||||
|
}
|
||||||
|
|
||||||
Pad.prototype.getRevisionChangeset = function getRevisionChangeset(revNum, callback) {
|
Pad.prototype.getRevisionChangeset = function getRevisionChangeset(revNum, callback) {
|
||||||
db.getSub("pad:"+this.id+":revs:"+revNum, ["changeset"], callback);
|
db.getSub("pad:"+this.id+":revs:"+revNum, ["changeset"], callback);
|
||||||
};
|
};
|
||||||
|
@ -436,6 +446,18 @@ Pad.prototype.remove = function remove(callback) {
|
||||||
db.remove("pad:"+padID+":revs:"+i);
|
db.remove("pad:"+padID+":revs:"+i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
callback();
|
||||||
|
},
|
||||||
|
//remove pad from all authors who contributed
|
||||||
|
function(callback)
|
||||||
|
{
|
||||||
|
var authorIDs = _this.getAllAuthors();
|
||||||
|
|
||||||
|
authorIDs.forEach(function (authorID)
|
||||||
|
{
|
||||||
|
authorManager.removePad(authorID, padID);
|
||||||
|
});
|
||||||
|
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
], callback);
|
], callback);
|
||||||
|
|
|
@ -40,13 +40,14 @@ catch(e)
|
||||||
//a list of all functions
|
//a list of all functions
|
||||||
var functions = {
|
var functions = {
|
||||||
"createGroup" : [],
|
"createGroup" : [],
|
||||||
"createGroupIfNotExistsFor" : ["groupMapper"],
|
"createGroupIfNotExistsFor" : ["groupMapper"],
|
||||||
"deleteGroup" : ["groupID"],
|
"deleteGroup" : ["groupID"],
|
||||||
"listPads" : ["groupID"],
|
"listPads" : ["groupID"],
|
||||||
"createPad" : ["padID", "text"],
|
"createPad" : ["padID", "text"],
|
||||||
"createGroupPad" : ["groupID", "padName", "text"],
|
"createGroupPad" : ["groupID", "padName", "text"],
|
||||||
"createAuthor" : ["name"],
|
"createAuthor" : ["name"],
|
||||||
"createAuthorIfNotExistsFor": ["authorMapper" , "name"],
|
"createAuthorIfNotExistsFor": ["authorMapper" , "name"],
|
||||||
|
"listPadsOfAuthor" : ["authorID"],
|
||||||
"createSession" : ["groupID", "authorID", "validUntil"],
|
"createSession" : ["groupID", "authorID", "validUntil"],
|
||||||
"deleteSession" : ["sessionID"],
|
"deleteSession" : ["sessionID"],
|
||||||
"getSessionInfo" : ["sessionID"],
|
"getSessionInfo" : ["sessionID"],
|
||||||
|
@ -57,12 +58,14 @@ var functions = {
|
||||||
"getHTML" : ["padID", "rev"],
|
"getHTML" : ["padID", "rev"],
|
||||||
"setHTML" : ["padID", "html"],
|
"setHTML" : ["padID", "html"],
|
||||||
"getRevisionsCount" : ["padID"],
|
"getRevisionsCount" : ["padID"],
|
||||||
|
"getLastEdited" : ["padID"],
|
||||||
"deletePad" : ["padID"],
|
"deletePad" : ["padID"],
|
||||||
"getReadOnlyID" : ["padID"],
|
"getReadOnlyID" : ["padID"],
|
||||||
"setPublicStatus" : ["padID", "publicStatus"],
|
"setPublicStatus" : ["padID", "publicStatus"],
|
||||||
"getPublicStatus" : ["padID"],
|
"getPublicStatus" : ["padID"],
|
||||||
"setPassword" : ["padID", "password"],
|
"setPassword" : ["padID", "password"],
|
||||||
"isPasswordProtected" : ["padID"]
|
"isPasswordProtected" : ["padID"],
|
||||||
|
"listAuthorsOfPad" : ["padID"]
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -33,6 +33,7 @@ var plugins = require("ep_etherpad-lite/static/js/pluginfw/plugins.js");
|
||||||
var log4js = require('log4js');
|
var log4js = require('log4js');
|
||||||
var messageLogger = log4js.getLogger("message");
|
var messageLogger = log4js.getLogger("message");
|
||||||
var _ = require('underscore');
|
var _ = require('underscore');
|
||||||
|
var hooks = require("ep_etherpad-lite/static/js/pluginfw/hooks.js");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A associative array that saves which sessions belong to a pad
|
* A associative array that saves which sessions belong to a pad
|
||||||
|
@ -158,6 +159,11 @@ exports.handleDisconnect = function(client)
|
||||||
*/
|
*/
|
||||||
exports.handleMessage = function(client, message)
|
exports.handleMessage = function(client, message)
|
||||||
{
|
{
|
||||||
|
_.map(hooks.callAll( "handleMessage", { client: client, message: message }), function ( newmessage ) {
|
||||||
|
if ( newmessage || newmessage === null ) {
|
||||||
|
message = newmessage;
|
||||||
|
}
|
||||||
|
});
|
||||||
if(message == null)
|
if(message == null)
|
||||||
{
|
{
|
||||||
messageLogger.warn("Message is null!");
|
messageLogger.warn("Message is null!");
|
||||||
|
@ -168,31 +174,65 @@ exports.handleMessage = function(client, message)
|
||||||
messageLogger.warn("Message has no type attribute!");
|
messageLogger.warn("Message has no type attribute!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Check what type of message we get and delegate to the other methodes
|
var finalHandler = function () {
|
||||||
if(message.type == "CLIENT_READY") {
|
//Check what type of message we get and delegate to the other methodes
|
||||||
handleClientReady(client, message);
|
if(message.type == "CLIENT_READY") {
|
||||||
} else if(message.type == "CHANGESET_REQ") {
|
handleClientReady(client, message);
|
||||||
handleChangesetRequest(client, message);
|
} else if(message.type == "CHANGESET_REQ") {
|
||||||
} else if(message.type == "COLLABROOM") {
|
handleChangesetRequest(client, message);
|
||||||
if (sessioninfos[client.id].readonly) {
|
} else if(message.type == "COLLABROOM") {
|
||||||
messageLogger.warn("Dropped message, COLLABROOM for readonly pad");
|
if (sessioninfos[client.id].readonly) {
|
||||||
} else if (message.data.type == "USER_CHANGES") {
|
messageLogger.warn("Dropped message, COLLABROOM for readonly pad");
|
||||||
handleUserChanges(client, message);
|
} else if (message.data.type == "USER_CHANGES") {
|
||||||
} else if (message.data.type == "USERINFO_UPDATE") {
|
handleUserChanges(client, message);
|
||||||
handleUserInfoUpdate(client, message);
|
} else if (message.data.type == "USERINFO_UPDATE") {
|
||||||
} else if (message.data.type == "CHAT_MESSAGE") {
|
handleUserInfoUpdate(client, message);
|
||||||
handleChatMessage(client, message);
|
} else if (message.data.type == "CHAT_MESSAGE") {
|
||||||
} else if (message.data.type == "SAVE_REVISION") {
|
handleChatMessage(client, message);
|
||||||
handleSaveRevisionMessage(client, message);
|
} else if (message.data.type == "SAVE_REVISION") {
|
||||||
} else if (message.data.type == "CLIENT_MESSAGE" &&
|
handleSaveRevisionMessage(client, message);
|
||||||
message.data.payload.type == "suggestUserName") {
|
} else if (message.data.type == "CLIENT_MESSAGE" &&
|
||||||
handleSuggestUserName(client, message);
|
message.data.payload.type == "suggestUserName") {
|
||||||
|
handleSuggestUserName(client, message);
|
||||||
|
} else {
|
||||||
|
messageLogger.warn("Dropped message, unknown COLLABROOM Data Type " + message.data.type);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
messageLogger.warn("Dropped message, unknown COLLABROOM Data Type " + message.data.type);
|
messageLogger.warn("Dropped message, unknown Message Type " + message.type);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (message && message.padId) {
|
||||||
|
async.series([
|
||||||
|
//check permissions
|
||||||
|
function(callback)
|
||||||
|
{
|
||||||
|
// Note: message.sessionID is an entirely 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(message.padId, message.sessionID, message.token, message.password, function(err, statusObject)
|
||||||
|
{
|
||||||
|
if(ERR(err, callback)) return;
|
||||||
|
|
||||||
|
//access was granted
|
||||||
|
if(statusObject.accessStatus == "grant")
|
||||||
|
{
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
//no access, send the client a message that tell him why
|
||||||
|
else
|
||||||
|
{
|
||||||
|
client.json.send({accessStatus: statusObject.accessStatus})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
finalHandler
|
||||||
|
]);
|
||||||
} else {
|
} else {
|
||||||
messageLogger.warn("Dropped message, unknown Message Type " + message.type);
|
finalHandler();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,11 @@ exports.expressCreateServer = function (hook_name, args, cb) {
|
||||||
"ep_etherpad-lite/templates/admin/plugins.html",
|
"ep_etherpad-lite/templates/admin/plugins.html",
|
||||||
render_args), {});
|
render_args), {});
|
||||||
});
|
});
|
||||||
|
args.app.get('/admin/plugins/info', function(req, res) {
|
||||||
|
res.send(eejs.require(
|
||||||
|
"ep_etherpad-lite/templates/admin/plugins-info.html",
|
||||||
|
{}), {});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.socketio = function (hook_name, args, cb) {
|
exports.socketio = function (hook_name, args, cb) {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
var padManager = require('../../db/PadManager');
|
var padManager = require('../../db/PadManager');
|
||||||
|
var url = require('url');
|
||||||
|
|
||||||
exports.expressCreateServer = function (hook_name, args, cb) {
|
exports.expressCreateServer = function (hook_name, args, cb) {
|
||||||
//redirects browser to the pad's sanitized url if needed. otherwise, renders the html
|
//redirects browser to the pad's sanitized url if needed. otherwise, renders the html
|
||||||
|
@ -14,9 +15,11 @@ exports.expressCreateServer = function (hook_name, args, cb) {
|
||||||
//the pad id was sanitized, so we redirect to the sanitized version
|
//the pad id was sanitized, so we redirect to the sanitized version
|
||||||
if(sanitizedPadId != padId)
|
if(sanitizedPadId != padId)
|
||||||
{
|
{
|
||||||
var real_path = req.path.replace(/^\/p\/[^\/]+/, '/p/' + sanitizedPadId);
|
var real_url = req.url.replace(/^\/p\/[^\/]+/, '/p/' + sanitizedPadId);
|
||||||
res.header('Location', real_path);
|
var query = url.parse(req.url).query;
|
||||||
res.send('You should be redirected to <a href="' + real_path + '">' + real_path + '</a>', 302);
|
if ( query ) real_url += '?' + query;
|
||||||
|
res.header('Location', real_url);
|
||||||
|
res.send('You should be redirected to <a href="' + real_url + '">' + real_url + '</a>', 302);
|
||||||
}
|
}
|
||||||
//the pad id was fine, so just render it
|
//the pad id was fine, so just render it
|
||||||
else
|
else
|
||||||
|
|
|
@ -114,9 +114,13 @@ var chat = (function()
|
||||||
{
|
{
|
||||||
var count = Number($("#chatcounter").text());
|
var count = Number($("#chatcounter").text());
|
||||||
count++;
|
count++;
|
||||||
|
|
||||||
|
// is the users focus already in the chatbox?
|
||||||
|
var alreadyFocused = $("#chatinput").is(":focus");
|
||||||
|
|
||||||
$("#chatcounter").text(count);
|
$("#chatcounter").text(count);
|
||||||
// chat throb stuff -- Just make it throw for twice as long
|
// chat throb stuff -- Just make it throw for twice as long
|
||||||
if(wasMentioned)
|
if(wasMentioned && !alreadyFocused)
|
||||||
{ // If the user was mentioned show for twice as long and flash the browser window
|
{ // If the user was mentioned show for twice as long and flash the browser window
|
||||||
if (chatMentions == 0){
|
if (chatMentions == 0){
|
||||||
title = document.title;
|
title = document.title;
|
||||||
|
@ -130,7 +134,11 @@ var chat = (function()
|
||||||
$('#chatthrob').html("<b>"+authorName+"</b>" + ": " + text).show().delay(2000).hide(400);
|
$('#chatthrob').html("<b>"+authorName+"</b>" + ": " + text).show().delay(2000).hide(400);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Clear the chat mentions when the user clicks on the chat input box
|
||||||
|
$('#chatinput').click(function(){
|
||||||
|
chatMentions = 0;
|
||||||
|
document.title = title;
|
||||||
|
});
|
||||||
self.scrollDown();
|
self.scrollDown();
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
|
@ -102,7 +102,7 @@ exports.aCallAll = function (hook_name, args, cb) {
|
||||||
|
|
||||||
exports.callFirst = function (hook_name, args) {
|
exports.callFirst = function (hook_name, args) {
|
||||||
if (!args) args = {};
|
if (!args) args = {};
|
||||||
if (plugins.hooks[hook_name][0] === undefined) return [];
|
if (plugins.hooks[hook_name] === undefined) return [];
|
||||||
return exports.syncMapFirst(plugins.hooks[hook_name], function (hook) {
|
return exports.syncMapFirst(plugins.hooks[hook_name], function (hook) {
|
||||||
return hookCallWrapper(hook, hook_name, args);
|
return hookCallWrapper(hook, hook_name, args);
|
||||||
});
|
});
|
||||||
|
|
|
@ -41,28 +41,42 @@ exports.formatParts = function () {
|
||||||
return _.map(exports.parts, function (part) { return part.full_name; }).join("\n");
|
return _.map(exports.parts, function (part) { return part.full_name; }).join("\n");
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.formatHooks = function () {
|
exports.formatHooks = function (hook_set_name) {
|
||||||
var res = [];
|
var res = [];
|
||||||
_.chain(exports.hooks).keys().forEach(function (hook_name) {
|
var hooks = exports.extractHooks(exports.parts, hook_set_name || "hooks");
|
||||||
_.forEach(exports.hooks[hook_name], function (hook) {
|
|
||||||
res.push(hook.hook_name + ": " + hook.hook_fn_name + " from " + hook.part.full_name);
|
_.chain(hooks).keys().forEach(function (hook_name) {
|
||||||
|
_.forEach(hooks[hook_name], function (hook) {
|
||||||
|
res.push("<dt>" + hook.hook_name + "</dt><dd>" + hook.hook_fn_name + " from " + hook.part.full_name + "</dd>");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
return res.join("\n");
|
return "<dl>" + res.join("\n") + "</dl>";
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.loadFn = function (path, hookName) {
|
exports.loadFn = function (path, hookName) {
|
||||||
var x = path.split(":");
|
var functionName
|
||||||
var fn = require(x[0]);
|
, parts = path.split(":");
|
||||||
var functionName = x[1] ? x[1] : hookName;
|
|
||||||
|
|
||||||
|
// on windows
|
||||||
|
if(process.platform == 'win32') {
|
||||||
|
if(parts.length == 3)
|
||||||
|
functionName = parts.pop();
|
||||||
|
path = parts.join(":");
|
||||||
|
}else{
|
||||||
|
path = parts[0];
|
||||||
|
functionName = parts[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
var fn = require(path);
|
||||||
|
functionName = functionName ? functionName : hookName;
|
||||||
|
|
||||||
_.each(functionName.split("."), function (name) {
|
_.each(functionName.split("."), function (name) {
|
||||||
fn = fn[name];
|
fn = fn[name];
|
||||||
});
|
});
|
||||||
return fn;
|
return fn;
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.extractHooks = function (parts, hook_set_name, plugins) {
|
exports.extractHooks = function (parts, hook_set_name) {
|
||||||
var hooks = {};
|
var hooks = {};
|
||||||
_.each(parts,function (part) {
|
_.each(parts,function (part) {
|
||||||
_.chain(part[hook_set_name] || {})
|
_.chain(part[hook_set_name] || {})
|
||||||
|
|
30
src/templates/admin/plugins-info.html
Normal file
30
src/templates/admin/plugins-info.html
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
<%
|
||||||
|
var plugins = require("ep_etherpad-lite/static/js/pluginfw/plugins");
|
||||||
|
%>
|
||||||
|
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Plugin information</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0">
|
||||||
|
<link rel="stylesheet" href="../../static/css/admin.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="wrapper">
|
||||||
|
<h1>Etherpad Lite</h1>
|
||||||
|
<div class="separator"></div>
|
||||||
|
|
||||||
|
<h2>Installed plugins</h2>
|
||||||
|
<pre><%= plugins.formatPlugins() %></pre>
|
||||||
|
|
||||||
|
<h2>Installed parts</h2>
|
||||||
|
<pre><%= plugins.formatParts() %></pre>
|
||||||
|
|
||||||
|
<h2>Installed hooks</h2>
|
||||||
|
<h3>Server side hooks</h3>
|
||||||
|
<div><%= plugins.formatHooks() %></div>
|
||||||
|
|
||||||
|
<h3>Client side hooks</h3>
|
||||||
|
<div><%= plugins.formatHooks("client_hooks") %></div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -20,6 +20,9 @@
|
||||||
|
|
||||||
|
|
||||||
<h1>Etherpad Lite</h1>
|
<h1>Etherpad Lite</h1>
|
||||||
|
|
||||||
|
<a href="/admin/plugins/info">Technical information on installed plugins</a>
|
||||||
|
|
||||||
<div class="separator"></div>
|
<div class="separator"></div>
|
||||||
<h2>Installed plugins</h2>
|
<h2>Installed plugins</h2>
|
||||||
<table>
|
<table>
|
||||||
|
|
|
@ -320,6 +320,8 @@
|
||||||
<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/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>
|
<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/pad.js"></script>
|
||||||
|
|
||||||
<!-- Bootstrap page -->
|
<!-- Bootstrap page -->
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var clientVars = {};
|
var clientVars = {};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue