mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-05-08 08:01:02 -04:00
Merge f05fc7ba31
into 7232dff6db
This commit is contained in:
commit
f60a9cce17
27 changed files with 1353 additions and 1344 deletions
|
@ -111,6 +111,9 @@ You can join the [mailinglist](http://groups.google.com/group/etherpad-lite-dev)
|
|||
|
||||
You also help the project, if you only host a Etherpad Lite instance and share your experience with us.
|
||||
|
||||
Please consider using [jshint](http://www.jshint.com/about/) if you plan to
|
||||
contribute to Etherpad Lite.
|
||||
|
||||
# Modules created for this project
|
||||
|
||||
* [ueberDB](https://github.com/Pita/ueberDB) "transforms every database into a object key value store" - manages all database access
|
||||
|
|
9
bin/jshint.sh
Executable file
9
bin/jshint.sh
Executable file
|
@ -0,0 +1,9 @@
|
|||
#!/bin/sh
|
||||
|
||||
if [ -d "../bin" ]; then
|
||||
cd "../"
|
||||
fi
|
||||
|
||||
JSHINT=./node_modules/jshint/bin/hint
|
||||
|
||||
$JSHINT ./node/
|
|
@ -29,7 +29,7 @@ var sessionManager = require("./SessionManager");
|
|||
var async = require("async");
|
||||
var exportHtml = require("../utils/ExportHtml");
|
||||
var importHtml = require("../utils/ImportHtml");
|
||||
var cleanText = require("./Pad").cleanText;
|
||||
var cleanText = require("../utils/cleantext").cleanText;
|
||||
|
||||
/**********************/
|
||||
/**GROUP FUNCTIONS*****/
|
||||
|
@ -83,9 +83,9 @@ exports.getText = function(padID, rev, callback)
|
|||
if(rev !== undefined && typeof rev != "number")
|
||||
{
|
||||
//try to parse the number
|
||||
if(!isNaN(parseInt(rev)))
|
||||
if(!isNaN(parseInt(rev, 10)))
|
||||
{
|
||||
rev = parseInt(rev);
|
||||
rev = parseInt(rev, 10);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -131,7 +131,7 @@ exports.getText = function(padID, rev, callback)
|
|||
data = {text: atext.text};
|
||||
|
||||
callback(null, data);
|
||||
})
|
||||
});
|
||||
}
|
||||
//the client wants the latest text, lets return it to him
|
||||
else
|
||||
|
@ -139,7 +139,7 @@ exports.getText = function(padID, rev, callback)
|
|||
callback(null, {"text": pad.text()});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
setText(padID, text) sets the text of a pad
|
||||
|
@ -163,7 +163,7 @@ exports.setText = function(padID, text, callback)
|
|||
//update the clients on the pad
|
||||
padMessageHandler.updatePadClients(pad, callback);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
getHTML(padID, [rev]) returns the html of a pad
|
||||
|
@ -183,9 +183,9 @@ exports.getHTML = function(padID, rev, callback)
|
|||
|
||||
if (rev !== undefined && typeof rev != "number")
|
||||
{
|
||||
if (!isNaN(parseInt(rev)))
|
||||
if (!isNaN(parseInt(rev, 10)))
|
||||
{
|
||||
rev = parseInt(rev);
|
||||
rev = parseInt(rev, 10);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -241,7 +241,7 @@ exports.getHTML = function(padID, rev, callback)
|
|||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.setHTML = function(padID, html, callback)
|
||||
{
|
||||
|
@ -257,7 +257,7 @@ exports.setHTML = function(padID, html, callback)
|
|||
padMessageHandler.updatePadClients(pad, callback);
|
||||
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/*****************/
|
||||
/**PAD FUNCTIONS */
|
||||
|
@ -280,7 +280,7 @@ exports.getRevisionsCount = function(padID, callback)
|
|||
|
||||
callback(null, {revisions: pad.getHeadRevisionNumber()});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
createPad(padName [, text]) creates a new pad in this group
|
||||
|
@ -305,7 +305,7 @@ exports.createPad = function(padID, text, callback)
|
|||
if(ERR(err, callback)) return;
|
||||
callback();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
deletePad(padID) deletes a pad
|
||||
|
@ -323,7 +323,7 @@ exports.deletePad = function(padID, callback)
|
|||
|
||||
pad.remove(callback);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
getReadOnlyLink(padID) returns the read only link of a pad
|
||||
|
@ -347,7 +347,7 @@ exports.getReadOnlyID = function(padID, callback)
|
|||
callback(null, {readOnlyID: readOnlyId});
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
setPublicStatus(padID, publicStatus) sets a boolean for the public status of a pad
|
||||
|
@ -380,7 +380,7 @@ exports.setPublicStatus = function(padID, publicStatus, callback)
|
|||
|
||||
callback();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
getPublicStatus(padID) return true of false
|
||||
|
@ -406,7 +406,7 @@ exports.getPublicStatus = function(padID, callback)
|
|||
|
||||
callback(null, {publicStatus: pad.getPublicStatus()});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
setPassword(padID, password) returns ok or a error message
|
||||
|
@ -435,7 +435,7 @@ exports.setPassword = function(padID, password, callback)
|
|||
|
||||
callback();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
isPasswordProtected(padID) returns true or false
|
||||
|
@ -461,7 +461,7 @@ exports.isPasswordProtected = function(padID, callback)
|
|||
|
||||
callback(null, {isPasswordProtected: pad.isPasswordProtected()});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/******************************/
|
||||
/** INTERNAL HELPER FUNCTIONS */
|
||||
|
@ -470,7 +470,7 @@ exports.isPasswordProtected = function(padID, callback)
|
|||
//checks if a number is an int
|
||||
function is_int(value)
|
||||
{
|
||||
return (parseFloat(value) == parseInt(value)) && !isNaN(value)
|
||||
return (parseFloat(value) == parseInt(value, 10)) && !isNaN(value);
|
||||
}
|
||||
|
||||
//gets a pad safe
|
||||
|
@ -502,12 +502,12 @@ function getPadSafe(padID, shouldExist, text, callback)
|
|||
if(ERR(err, callback)) return;
|
||||
|
||||
//does not exist, but should
|
||||
if(exists == false && shouldExist == true)
|
||||
if(!exists && shouldExist)
|
||||
{
|
||||
callback(new customError("padID does not exist","apierror"));
|
||||
}
|
||||
//does exists, but shouldn't
|
||||
else if(exists == true && shouldExist == false)
|
||||
else if(exists && !shouldExist)
|
||||
{
|
||||
callback(new customError("padID does already exist","apierror"));
|
||||
}
|
||||
|
|
|
@ -31,9 +31,9 @@ exports.doesAuthorExists = function (authorID, callback)
|
|||
db.get("globalAuthor:" + authorID, function (err, author)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
callback(null, author != null);
|
||||
callback(null, author ? true : false);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the AuthorID for a token.
|
||||
|
@ -48,7 +48,7 @@ exports.getAuthor4Token = function (token, callback)
|
|||
//return only the sub value authorID
|
||||
callback(null, author ? author.authorID : author);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the AuthorID for a mapper.
|
||||
|
@ -63,12 +63,14 @@ exports.createAuthorIfNotExistsFor = function (authorMapper, name, callback)
|
|||
|
||||
//set the name of this author
|
||||
if(name)
|
||||
{
|
||||
exports.setAuthorName(author.authorID, name);
|
||||
}
|
||||
|
||||
//return the authorID
|
||||
callback(null, author);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the AuthorID for a mapper. We can map using a mapperkey,
|
||||
|
@ -85,7 +87,7 @@ function mapAuthorWithDBKey (mapperkey, mapper, callback)
|
|||
if(ERR(err, callback)) return;
|
||||
|
||||
//there is no author with this mapper, so create one
|
||||
if(author == null)
|
||||
if(!author)
|
||||
{
|
||||
exports.createAuthor(null, function(err, author)
|
||||
{
|
||||
|
@ -126,7 +128,7 @@ exports.createAuthor = function(name, callback)
|
|||
db.set("globalAuthor:" + author, authorObj);
|
||||
|
||||
callback(null, {authorID: author});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the Author Obj of the author
|
||||
|
@ -136,7 +138,7 @@ exports.createAuthor = function(name, callback)
|
|||
exports.getAuthor = function (author, callback)
|
||||
{
|
||||
db.get("globalAuthor:" + author, callback);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the color Id of the author
|
||||
|
@ -146,7 +148,7 @@ exports.getAuthor = function (author, callback)
|
|||
exports.getAuthorColorId = function (author, callback)
|
||||
{
|
||||
db.getSub("globalAuthor:" + author, ["colorId"], callback);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the color Id of the author
|
||||
|
@ -156,7 +158,7 @@ exports.getAuthorColorId = function (author, callback)
|
|||
exports.setAuthorColorId = function (author, colorId, callback)
|
||||
{
|
||||
db.setSub("globalAuthor:" + author, ["colorId"], colorId, callback);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the name of the author
|
||||
|
@ -166,7 +168,7 @@ exports.setAuthorColorId = function (author, colorId, callback)
|
|||
exports.getAuthorName = function (author, callback)
|
||||
{
|
||||
db.getSub("globalAuthor:" + author, ["name"], callback);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the name of the author
|
||||
|
@ -176,7 +178,7 @@ exports.getAuthorName = function (author, callback)
|
|||
exports.setAuthorName = function (author, name, callback)
|
||||
{
|
||||
db.setSub("globalAuthor:" + author, ["name"], name, callback);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates a random String with the given length. Is needed to generate the Author Ids
|
||||
|
|
|
@ -54,4 +54,4 @@ exports.init = function(callback)
|
|||
callback(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -39,7 +39,7 @@ exports.deleteGroup = function(groupID, callback)
|
|||
if(ERR(err, callback)) return;
|
||||
|
||||
//group does not exist
|
||||
if(_group == null)
|
||||
if(!_group)
|
||||
{
|
||||
callback(new customError("groupID does not exist","apierror"));
|
||||
}
|
||||
|
@ -81,7 +81,10 @@ exports.deleteGroup = function(groupID, callback)
|
|||
if(ERR(err, callback)) return;
|
||||
|
||||
//skip if there is no group2sessions entry
|
||||
if(group2sessions == null) {callback(); return}
|
||||
if(!group2sessions) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
//collect all sessions in an array, that allows us to use async.forEach
|
||||
var sessions = [];
|
||||
|
@ -109,7 +112,7 @@ exports.deleteGroup = function(groupID, callback)
|
|||
if(ERR(err, callback)) return;
|
||||
callback();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.doesGroupExist = function(groupID, callback)
|
||||
{
|
||||
|
@ -117,9 +120,9 @@ exports.doesGroupExist = function(groupID, callback)
|
|||
db.get("group:" + groupID, function (err, group)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
callback(null, group != null);
|
||||
callback(null, group ? true : false);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.createGroup = function(callback)
|
||||
{
|
||||
|
@ -129,7 +132,7 @@ exports.createGroup = function(callback)
|
|||
//create the group
|
||||
db.set("group:" + groupID, {pads: {}});
|
||||
callback(null, {groupID: groupID});
|
||||
}
|
||||
};
|
||||
|
||||
exports.createGroupIfNotExistsFor = function(groupMapper, callback)
|
||||
{
|
||||
|
@ -146,7 +149,7 @@ exports.createGroupIfNotExistsFor = function(groupMapper, callback)
|
|||
if(ERR(err, callback)) return;
|
||||
|
||||
//there is no group for this mapper, let's create a group
|
||||
if(groupID == null)
|
||||
if(!groupID)
|
||||
{
|
||||
exports.createGroup(function(err, responseObj)
|
||||
{
|
||||
|
@ -165,7 +168,7 @@ exports.createGroupIfNotExistsFor = function(groupMapper, callback)
|
|||
callback(null, {groupID: groupID});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.createGroupPad = function(groupID, padName, text, callback)
|
||||
{
|
||||
|
@ -181,7 +184,7 @@ exports.createGroupPad = function(groupID, padName, text, callback)
|
|||
if(ERR(err, callback)) return;
|
||||
|
||||
//group does not exist
|
||||
if(exists == false)
|
||||
if(!exists)
|
||||
{
|
||||
callback(new customError("groupID does not exist","apierror"));
|
||||
}
|
||||
|
@ -200,7 +203,7 @@ exports.createGroupPad = function(groupID, padName, text, callback)
|
|||
if(ERR(err, callback)) return;
|
||||
|
||||
//pad exists already
|
||||
if(exists == true)
|
||||
if(exists)
|
||||
{
|
||||
callback(new customError("padName does already exist","apierror"));
|
||||
}
|
||||
|
@ -231,7 +234,7 @@ exports.createGroupPad = function(groupID, padName, text, callback)
|
|||
if(ERR(err, callback)) return;
|
||||
callback(null, {padID: padID});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.listPads = function(groupID, callback)
|
||||
{
|
||||
|
@ -240,7 +243,7 @@ exports.listPads = function(groupID, callback)
|
|||
if(ERR(err, callback)) return;
|
||||
|
||||
//group does not exist
|
||||
if(exists == false)
|
||||
if(!exists)
|
||||
{
|
||||
callback(new customError("groupID does not exist","apierror"));
|
||||
}
|
||||
|
@ -254,7 +257,7 @@ exports.listPads = function(groupID, callback)
|
|||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates a random String with the given length. Is needed to generate the Author Ids
|
||||
|
|
870
node/db/Pad.js
870
node/db/Pad.js
|
@ -2,8 +2,6 @@
|
|||
* The pad object, defined with joose
|
||||
*/
|
||||
|
||||
require('joose');
|
||||
|
||||
var ERR = require("async-stacktrace");
|
||||
var Changeset = require("../utils/Changeset");
|
||||
var AttributePoolFactory = require("../utils/AttributePoolFactory");
|
||||
|
@ -15,497 +13,463 @@ var padManager = require("./PadManager");
|
|||
var padMessageHandler = require("../handler/PadMessageHandler");
|
||||
var readOnlyManager = require("./ReadOnlyManager");
|
||||
var crypto = require("crypto");
|
||||
var cleanText = require("../utils/cleantext").cleanText;
|
||||
|
||||
/**
|
||||
* Copied from the Etherpad source code. It converts Windows line breaks to Unix line breaks and convert Tabs to spaces
|
||||
* @param txt
|
||||
*/
|
||||
exports.cleanText = function (txt) {
|
||||
return txt.replace(/\r\n/g,'\n').replace(/\r/g,'\n').replace(/\t/g, ' ').replace(/\xa0/g, ' ');
|
||||
}
|
||||
var Pad = function Pad(id) {
|
||||
this.atext = Changeset.makeAText("\n");
|
||||
this.pool = AttributePoolFactory.createAttributePool();
|
||||
this.head = -1;
|
||||
this.chatHead = -1;
|
||||
this.publicStatus = false;
|
||||
this.passwordHash = null;
|
||||
this.id = id;
|
||||
};
|
||||
|
||||
Class('Pad', {
|
||||
exports.Pad = Pad;
|
||||
|
||||
// these are the properties
|
||||
has : {
|
||||
Pad.prototype.apool = function apool() {
|
||||
return this.pool;
|
||||
};
|
||||
|
||||
atext : {
|
||||
is : 'rw', // readwrite
|
||||
init : function() { return Changeset.makeAText("\n"); } // first value
|
||||
}, // atext
|
||||
Pad.prototype.getHeadRevisionNumber = function getHeadRevisionNumber() {
|
||||
return this.head;
|
||||
};
|
||||
|
||||
pool : {
|
||||
is: 'rw',
|
||||
init : function() { return AttributePoolFactory.createAttributePool(); },
|
||||
getterName : 'apool' // legacy
|
||||
}, // pool
|
||||
Pad.prototype.getPublicStatus = function getPublicStatus() {
|
||||
return this.publicStatus;
|
||||
};
|
||||
|
||||
head : {
|
||||
is : 'rw',
|
||||
init : -1,
|
||||
getterName : 'getHeadRevisionNumber'
|
||||
}, // head
|
||||
Pad.prototype.appendRevision = function appendRevision(aChangeset, author) {
|
||||
|
||||
chatHead : {
|
||||
is: 'rw',
|
||||
init: -1
|
||||
}, // chatHead
|
||||
if(!author)
|
||||
{
|
||||
author = '';
|
||||
}
|
||||
|
||||
publicStatus : {
|
||||
is: 'rw',
|
||||
init: false,
|
||||
getterName : 'getPublicStatus'
|
||||
}, //publicStatus
|
||||
var newAText = Changeset.applyToAText(aChangeset, this.atext, this.pool);
|
||||
Changeset.copyAText(newAText, this.atext);
|
||||
|
||||
passwordHash : {
|
||||
is: 'rw',
|
||||
init: null
|
||||
}, // passwordHash
|
||||
var newRev = ++this.head;
|
||||
|
||||
id : { is : 'r' }
|
||||
},
|
||||
var newRevData = {};
|
||||
newRevData.changeset = aChangeset;
|
||||
newRevData.meta = {};
|
||||
newRevData.meta.author = author;
|
||||
newRevData.meta.timestamp = new Date().getTime();
|
||||
|
||||
methods : {
|
||||
//ex. getNumForAuthor
|
||||
if(author !== '')
|
||||
{
|
||||
this.pool.putAttrib(['author', author || '']);
|
||||
}
|
||||
|
||||
BUILD : function (id)
|
||||
if(newRev % 100 === 0)
|
||||
{
|
||||
newRevData.meta.atext = this.atext;
|
||||
}
|
||||
|
||||
db.set("pad:"+this.id+":revs:"+newRev, newRevData);
|
||||
db.set("pad:"+this.id, {atext: this.atext,
|
||||
pool: this.pool.toJsonable(),
|
||||
head: this.head,
|
||||
chatHead: this.chatHead,
|
||||
publicStatus: this.publicStatus,
|
||||
passwordHash: this.passwordHash});
|
||||
|
||||
|
||||
};
|
||||
|
||||
Pad.prototype.getRevisionChangeset = function getRevisionChangeset(revNum, callback) {
|
||||
db.getSub("pad:"+this.id+":revs:"+revNum, ["changeset"], callback);
|
||||
};
|
||||
|
||||
Pad.prototype.getRevisionAuthor = function getRevisionAuthor(revNum, callback) {
|
||||
db.getSub("pad:"+this.id+":revs:"+revNum, ["meta", "author"], callback);
|
||||
};
|
||||
|
||||
Pad.prototype.getRevisionDate = function getRevisionDate(revNum, callback) {
|
||||
db.getSub("pad:"+this.id+":revs:"+revNum, ["meta", "timestamp"], callback);
|
||||
};
|
||||
|
||||
Pad.prototype.getAllAuthors = function getAllAuthors() {
|
||||
var authors = [];
|
||||
|
||||
for(var key in this.pool.numToAttrib)
|
||||
{
|
||||
if(this.pool.numToAttrib[key][0] == "author" && this.pool.numToAttrib[key][1] !== "")
|
||||
{
|
||||
return {
|
||||
'id' : id,
|
||||
}
|
||||
},
|
||||
authors.push(this.pool.numToAttrib[key][1]);
|
||||
}
|
||||
}
|
||||
|
||||
appendRevision : function(aChangeset, author)
|
||||
return authors;
|
||||
};
|
||||
|
||||
Pad.prototype.getInternalRevisionAText = function getInternalRevisionAText(targetRev, callback) {
|
||||
var _this = this;
|
||||
|
||||
var keyRev = this.getKeyRevisionNumber(targetRev);
|
||||
var atext;
|
||||
var changesets = [];
|
||||
|
||||
//find out which changesets are needed
|
||||
var neededChangesets = [];
|
||||
var curRev = keyRev;
|
||||
while (curRev < targetRev)
|
||||
{
|
||||
curRev++;
|
||||
neededChangesets.push(curRev);
|
||||
}
|
||||
|
||||
async.series([
|
||||
//get all needed data out of the database
|
||||
function(callback)
|
||||
{
|
||||
if(!author)
|
||||
author = '';
|
||||
|
||||
var newAText = Changeset.applyToAText(aChangeset, this.atext, this.pool);
|
||||
Changeset.copyAText(newAText, this.atext);
|
||||
|
||||
var newRev = ++this.head;
|
||||
|
||||
var newRevData = {};
|
||||
newRevData.changeset = aChangeset;
|
||||
newRevData.meta = {};
|
||||
newRevData.meta.author = author;
|
||||
newRevData.meta.timestamp = new Date().getTime();
|
||||
|
||||
//ex. getNumForAuthor
|
||||
if(author != '')
|
||||
this.pool.putAttrib(['author', author || '']);
|
||||
|
||||
if(newRev % 100 == 0)
|
||||
{
|
||||
newRevData.meta.atext = this.atext;
|
||||
}
|
||||
|
||||
db.set("pad:"+this.id+":revs:"+newRev, newRevData);
|
||||
db.set("pad:"+this.id, {atext: this.atext,
|
||||
pool: this.pool.toJsonable(),
|
||||
head: this.head,
|
||||
chatHead: this.chatHead,
|
||||
publicStatus: this.publicStatus,
|
||||
passwordHash: this.passwordHash});
|
||||
}, //appendRevision
|
||||
|
||||
getRevisionChangeset : function(revNum, callback)
|
||||
{
|
||||
db.getSub("pad:"+this.id+":revs:"+revNum, ["changeset"], callback);
|
||||
}, // getRevisionChangeset
|
||||
|
||||
getRevisionAuthor : function(revNum, callback)
|
||||
{
|
||||
db.getSub("pad:"+this.id+":revs:"+revNum, ["meta", "author"], callback);
|
||||
}, // getRevisionAuthor
|
||||
|
||||
getRevisionDate : function(revNum, callback)
|
||||
{
|
||||
db.getSub("pad:"+this.id+":revs:"+revNum, ["meta", "timestamp"], callback);
|
||||
}, // getRevisionAuthor
|
||||
|
||||
getAllAuthors : function()
|
||||
{
|
||||
var authors = [];
|
||||
|
||||
for(key in this.pool.numToAttrib)
|
||||
{
|
||||
if(this.pool.numToAttrib[key][0] == "author" && this.pool.numToAttrib[key][1] != "")
|
||||
async.parallel([
|
||||
//get the atext of the key revision
|
||||
function (callback)
|
||||
{
|
||||
authors.push(this.pool.numToAttrib[key][1]);
|
||||
db.getSub("pad:"+_this.id+":revs:"+keyRev, ["meta", "atext"], function(err, _atext)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
atext = Changeset.cloneAText(_atext);
|
||||
callback();
|
||||
});
|
||||
},
|
||||
//get all needed changesets
|
||||
function (callback)
|
||||
{
|
||||
async.forEach(neededChangesets, function(item, callback)
|
||||
{
|
||||
_this.getRevisionChangeset(item, function(err, changeset)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
changesets[item] = changeset;
|
||||
callback();
|
||||
});
|
||||
}, callback);
|
||||
}
|
||||
}
|
||||
|
||||
return authors;
|
||||
], callback);
|
||||
},
|
||||
|
||||
getInternalRevisionAText : function(targetRev, callback)
|
||||
//apply all changesets to the key changeset
|
||||
function(callback)
|
||||
{
|
||||
var _this = this;
|
||||
|
||||
var keyRev = this.getKeyRevisionNumber(targetRev);
|
||||
var atext;
|
||||
var changesets = [];
|
||||
|
||||
//find out which changesets are needed
|
||||
var neededChangesets = [];
|
||||
var apool = _this.apool();
|
||||
var curRev = keyRev;
|
||||
|
||||
while (curRev < targetRev)
|
||||
{
|
||||
curRev++;
|
||||
neededChangesets.push(curRev);
|
||||
var cs = changesets[curRev];
|
||||
atext = Changeset.applyToAText(cs, atext, apool);
|
||||
}
|
||||
|
||||
async.series([
|
||||
//get all needed data out of the database
|
||||
function(callback)
|
||||
{
|
||||
async.parallel([
|
||||
//get the atext of the key revision
|
||||
function (callback)
|
||||
{
|
||||
db.getSub("pad:"+_this.id+":revs:"+keyRev, ["meta", "atext"], function(err, _atext)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
atext = Changeset.cloneAText(_atext);
|
||||
callback();
|
||||
});
|
||||
},
|
||||
//get all needed changesets
|
||||
function (callback)
|
||||
{
|
||||
async.forEach(neededChangesets, function(item, callback)
|
||||
{
|
||||
_this.getRevisionChangeset(item, function(err, changeset)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
changesets[item] = changeset;
|
||||
callback();
|
||||
});
|
||||
}, callback);
|
||||
}
|
||||
], callback);
|
||||
},
|
||||
//apply all changesets to the key changeset
|
||||
function(callback)
|
||||
{
|
||||
var apool = _this.apool();
|
||||
var curRev = keyRev;
|
||||
callback(null);
|
||||
}
|
||||
], function(err)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
callback(null, atext);
|
||||
});
|
||||
|
||||
while (curRev < targetRev)
|
||||
{
|
||||
curRev++;
|
||||
var cs = changesets[curRev];
|
||||
atext = Changeset.applyToAText(cs, atext, apool);
|
||||
}
|
||||
};
|
||||
|
||||
callback(null);
|
||||
}
|
||||
], function(err)
|
||||
Pad.prototype.getKeyRevisionNumber = function getKeyRevisionNumber(revNum) {
|
||||
return Math.floor(revNum / 100) * 100;
|
||||
};
|
||||
|
||||
Pad.prototype.text = function text() {
|
||||
return this.atext.text;
|
||||
};
|
||||
|
||||
Pad.prototype.setText = function setText(newText) {
|
||||
//clean the new text
|
||||
newText = cleanText(newText);
|
||||
|
||||
var oldText = this.text();
|
||||
|
||||
//create the changeset
|
||||
var changeset = Changeset.makeSplice(oldText, 0, oldText.length-1, newText);
|
||||
|
||||
//append the changeset
|
||||
this.appendRevision(changeset);
|
||||
};
|
||||
|
||||
Pad.prototype.appendChatMessage = function appendChatMessage(text, userId, time) {
|
||||
this.chatHead++;
|
||||
//save the chat entry in the database
|
||||
db.set("pad:"+this.id+":chat:"+this.chatHead, {"text": text, "userId": userId, "time": time});
|
||||
//save the new chat head
|
||||
db.setSub("pad:"+this.id, ["chatHead"], this.chatHead);
|
||||
};
|
||||
|
||||
Pad.prototype.getChatMessage = function getChatMessage(entryNum, callback) {
|
||||
var _this = this;
|
||||
var entry;
|
||||
|
||||
async.series([
|
||||
//get the chat entry
|
||||
function(callback)
|
||||
{
|
||||
db.get("pad:"+_this.id+":chat:"+entryNum, function(err, _entry)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
callback(null, atext);
|
||||
entry = _entry;
|
||||
callback();
|
||||
});
|
||||
},
|
||||
|
||||
getKeyRevisionNumber : function(revNum)
|
||||
//add the authorName
|
||||
function(callback)
|
||||
{
|
||||
return Math.floor(revNum / 100) * 100;
|
||||
},
|
||||
|
||||
text : function()
|
||||
{
|
||||
return this.atext.text;
|
||||
},
|
||||
|
||||
setText : function(newText)
|
||||
{
|
||||
//clean the new text
|
||||
newText = exports.cleanText(newText);
|
||||
|
||||
var oldText = this.text();
|
||||
|
||||
//create the changeset
|
||||
var changeset = Changeset.makeSplice(oldText, 0, oldText.length-1, newText);
|
||||
|
||||
//append the changeset
|
||||
this.appendRevision(changeset);
|
||||
},
|
||||
|
||||
appendChatMessage: function(text, userId, time)
|
||||
{
|
||||
this.chatHead++;
|
||||
//save the chat entry in the database
|
||||
db.set("pad:"+this.id+":chat:"+this.chatHead, {"text": text, "userId": userId, "time": time});
|
||||
//save the new chat head
|
||||
db.setSub("pad:"+this.id, ["chatHead"], this.chatHead);
|
||||
},
|
||||
|
||||
getChatMessage: function(entryNum, callback)
|
||||
{
|
||||
var _this = this;
|
||||
var entry;
|
||||
|
||||
async.series([
|
||||
//get the chat entry
|
||||
function(callback)
|
||||
{
|
||||
db.get("pad:"+_this.id+":chat:"+entryNum, function(err, _entry)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
entry = _entry;
|
||||
callback();
|
||||
});
|
||||
},
|
||||
//add the authorName
|
||||
function(callback)
|
||||
{
|
||||
//this chat message doesn't exist, return null
|
||||
if(entry == null)
|
||||
{
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
//get the authorName
|
||||
authorManager.getAuthorName(entry.userId, function(err, authorName)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
entry.userName = authorName;
|
||||
callback();
|
||||
});
|
||||
}
|
||||
], function(err)
|
||||
//this chat message doesn't exist, return null
|
||||
if(!entry)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
callback(null, entry);
|
||||
});
|
||||
},
|
||||
|
||||
getLastChatMessages: function(count, callback)
|
||||
{
|
||||
//return an empty array if there are no chat messages
|
||||
if(this.chatHead == -1)
|
||||
{
|
||||
callback(null, []);
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
var _this = this;
|
||||
|
||||
//works only if we decrement the amount, for some reason
|
||||
count--;
|
||||
|
||||
//set the startpoint
|
||||
var start = this.chatHead-count;
|
||||
if(start < 0)
|
||||
start = 0;
|
||||
|
||||
//set the endpoint
|
||||
var end = this.chatHead;
|
||||
|
||||
//collect the numbers of chat entries and in which order we need them
|
||||
var neededEntries = [];
|
||||
var order = 0;
|
||||
for(var i=start;i<=end; i++)
|
||||
{
|
||||
neededEntries.push({entryNum:i, order: order});
|
||||
order++;
|
||||
}
|
||||
|
||||
//get all entries out of the database
|
||||
var entries = [];
|
||||
async.forEach(neededEntries, function(entryObject, callback)
|
||||
{
|
||||
_this.getChatMessage(entryObject.entryNum, function(err, entry)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
entries[entryObject.order] = entry;
|
||||
callback();
|
||||
});
|
||||
}, function(err)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
//sort out broken chat entries
|
||||
//it looks like in happend in the past that the chat head was
|
||||
//incremented, but the chat message wasn't added
|
||||
var cleanedEntries = [];
|
||||
for(var i=0;i<entries.length;i++)
|
||||
{
|
||||
if(entries[i]!=null)
|
||||
cleanedEntries.push(entries[i]);
|
||||
else
|
||||
console.warn("WARNING: Found broken chat entry in pad " + _this.id);
|
||||
}
|
||||
|
||||
callback(null, cleanedEntries);
|
||||
});
|
||||
},
|
||||
|
||||
init : function (text, callback)
|
||||
{
|
||||
var _this = this;
|
||||
|
||||
//replace text with default text if text isn't set
|
||||
if(text == null)
|
||||
{
|
||||
text = settings.defaultPadText;
|
||||
}
|
||||
|
||||
//try to load the pad
|
||||
db.get("pad:"+this.id, function(err, value)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
//if this pad exists, load it
|
||||
if(value != null)
|
||||
{
|
||||
_this.head = value.head;
|
||||
_this.atext = value.atext;
|
||||
_this.pool = _this.pool.fromJsonable(value.pool);
|
||||
|
||||
//ensure we have a local chatHead variable
|
||||
if(value.chatHead != null)
|
||||
_this.chatHead = value.chatHead;
|
||||
else
|
||||
_this.chatHead = -1;
|
||||
|
||||
//ensure we have a local publicStatus variable
|
||||
if(value.publicStatus != null)
|
||||
_this.publicStatus = value.publicStatus;
|
||||
else
|
||||
_this.publicStatus = false;
|
||||
|
||||
//ensure we have a local passwordHash variable
|
||||
if(value.passwordHash != null)
|
||||
_this.passwordHash = value.passwordHash;
|
||||
else
|
||||
_this.passwordHash = null;
|
||||
}
|
||||
//this pad doesn't exist, so create it
|
||||
else
|
||||
{
|
||||
var firstChangeset = Changeset.makeSplice("\n", 0, 0, exports.cleanText(text));
|
||||
|
||||
_this.appendRevision(firstChangeset, '');
|
||||
}
|
||||
|
||||
callback(null);
|
||||
});
|
||||
},
|
||||
remove: function(callback)
|
||||
{
|
||||
var padID = this.id;
|
||||
var _this = this;
|
||||
|
||||
//kick everyone from this pad
|
||||
padMessageHandler.kickSessionsFromPad(padID);
|
||||
|
||||
async.series([
|
||||
//delete all relations
|
||||
function(callback)
|
||||
{
|
||||
async.parallel([
|
||||
//is it a group pad? -> delete the entry of this pad in the group
|
||||
function(callback)
|
||||
{
|
||||
//is it a group pad?
|
||||
if(padID.indexOf("$")!=-1)
|
||||
{
|
||||
var groupID = padID.substring(0,padID.indexOf("$"));
|
||||
|
||||
db.get("group:" + groupID, function (err, group)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
//remove the pad entry
|
||||
delete group.pads[padID];
|
||||
|
||||
//set the new value
|
||||
db.set("group:" + groupID, group);
|
||||
|
||||
callback();
|
||||
});
|
||||
}
|
||||
//its no group pad, nothing to do here
|
||||
else
|
||||
{
|
||||
callback();
|
||||
}
|
||||
},
|
||||
//remove the readonly entries
|
||||
function(callback)
|
||||
{
|
||||
readOnlyManager.getReadOnlyId(padID, function(err, readonlyID)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
db.remove("pad2readonly:" + padID);
|
||||
db.remove("readonly2pad:" + readonlyID);
|
||||
|
||||
callback();
|
||||
});
|
||||
},
|
||||
//delete all chat messages
|
||||
function(callback)
|
||||
{
|
||||
var chatHead = _this.chatHead;
|
||||
|
||||
for(var i=0;i<=chatHead;i++)
|
||||
{
|
||||
db.remove("pad:"+padID+":chat:"+i);
|
||||
}
|
||||
|
||||
callback();
|
||||
},
|
||||
//delete all revisions
|
||||
function(callback)
|
||||
{
|
||||
var revHead = _this.head;
|
||||
|
||||
for(var i=0;i<=revHead;i++)
|
||||
{
|
||||
db.remove("pad:"+padID+":revs:"+i);
|
||||
}
|
||||
|
||||
callback();
|
||||
}
|
||||
], callback);
|
||||
},
|
||||
//delete the pad entry and delete pad from padManager
|
||||
function(callback)
|
||||
{
|
||||
db.remove("pad:"+padID);
|
||||
padManager.unloadPad(padID);
|
||||
callback();
|
||||
}
|
||||
], function(err)
|
||||
//get the authorName
|
||||
authorManager.getAuthorName(entry.userId, function(err, authorName)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
entry.userName = authorName;
|
||||
callback();
|
||||
})
|
||||
},
|
||||
//set in db
|
||||
setPublicStatus: function(publicStatus)
|
||||
{
|
||||
this.publicStatus = publicStatus;
|
||||
db.setSub("pad:"+this.id, ["publicStatus"], this.publicStatus);
|
||||
},
|
||||
setPassword: function(password)
|
||||
{
|
||||
this.passwordHash = password == null ? null : hash(password, generateSalt());
|
||||
db.setSub("pad:"+this.id, ["passwordHash"], this.passwordHash);
|
||||
},
|
||||
isCorrectPassword: function(password)
|
||||
{
|
||||
return compare(this.passwordHash, password)
|
||||
},
|
||||
isPasswordProtected: function()
|
||||
{
|
||||
return this.passwordHash != null;
|
||||
});
|
||||
}
|
||||
}, // methods
|
||||
});
|
||||
], function(err)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
callback(null, entry);
|
||||
});
|
||||
};
|
||||
|
||||
Pad.prototype.getLastChatMessages = function getLastChatMessages(count, callback) {
|
||||
//return an empty array if there are no chat messages
|
||||
if(this.chatHead == -1)
|
||||
{
|
||||
callback(null, []);
|
||||
return;
|
||||
}
|
||||
|
||||
var _this = this;
|
||||
|
||||
//works only if we decrement the amount, for some reason
|
||||
count--;
|
||||
|
||||
//set the startpoint
|
||||
var start = this.chatHead-count;
|
||||
if(start < 0)
|
||||
start = 0;
|
||||
|
||||
//set the endpoint
|
||||
var end = this.chatHead;
|
||||
|
||||
//collect the numbers of chat entries and in which order we need them
|
||||
var neededEntries = [];
|
||||
var order = 0;
|
||||
for(var i=start;i<=end; i++)
|
||||
{
|
||||
neededEntries.push({entryNum:i, order: order});
|
||||
order++;
|
||||
}
|
||||
|
||||
//get all entries out of the database
|
||||
var entries = [];
|
||||
async.forEach(neededEntries, function(entryObject, callback)
|
||||
{
|
||||
_this.getChatMessage(entryObject.entryNum, function(err, entry)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
entries[entryObject.order] = entry;
|
||||
callback();
|
||||
});
|
||||
}, function(err)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
//sort out broken chat entries
|
||||
//it looks like in happend in the past that the chat head was
|
||||
//incremented, but the chat message wasn't added
|
||||
var cleanedEntries = [];
|
||||
for(var i=0;i<entries.length;i++)
|
||||
{
|
||||
if(entries[i]) {
|
||||
cleanedEntries.push(entries[i]);
|
||||
}
|
||||
else
|
||||
console.warn("WARNING: Found broken chat entry in pad " + _this.id);
|
||||
}
|
||||
|
||||
callback(null, cleanedEntries);
|
||||
});
|
||||
};
|
||||
|
||||
Pad.prototype.init = function init(text, callback) {
|
||||
var _this = this;
|
||||
|
||||
//replace text with default text if text isn't set
|
||||
if(!text)
|
||||
{
|
||||
text = settings.defaultPadText;
|
||||
}
|
||||
|
||||
//try to load the pad
|
||||
db.get("pad:"+this.id, function(err, value)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
//if this pad exists, load it
|
||||
if(value)
|
||||
{
|
||||
_this.head = value.head;
|
||||
_this.atext = value.atext;
|
||||
_this.pool = _this.pool.fromJsonable(value.pool);
|
||||
|
||||
//ensure we have a local chatHead variable
|
||||
if(value.chatHead) {
|
||||
_this.chatHead = value.chatHead;
|
||||
}
|
||||
else {
|
||||
_this.chatHead = -1;
|
||||
}
|
||||
//ensure we have a local publicStatus variable
|
||||
if(value.publicStatus) {
|
||||
_this.publicStatus = value.publicStatus;
|
||||
}
|
||||
else {
|
||||
_this.publicStatus = false;
|
||||
}
|
||||
//ensure we have a local passwordHash variable
|
||||
if(value.passwordHash) {
|
||||
_this.passwordHash = value.passwordHash;
|
||||
}
|
||||
else {
|
||||
_this.passwordHash = null;
|
||||
}
|
||||
}
|
||||
//this pad doesn't exist, so create it
|
||||
else
|
||||
{
|
||||
var firstChangeset = Changeset.makeSplice("\n", 0, 0, cleanText(text));
|
||||
|
||||
_this.appendRevision(firstChangeset, '');
|
||||
}
|
||||
|
||||
callback(null);
|
||||
});
|
||||
};
|
||||
|
||||
Pad.prototype.remove = function remove(callback) {
|
||||
var padID = this.id;
|
||||
var _this = this;
|
||||
|
||||
//kick everyone from this pad
|
||||
padMessageHandler.kickSessionsFromPad(padID);
|
||||
|
||||
async.series([
|
||||
//delete all relations
|
||||
function(callback)
|
||||
{
|
||||
async.parallel([
|
||||
//is it a group pad? -> delete the entry of this pad in the group
|
||||
function(callback)
|
||||
{
|
||||
//is it a group pad?
|
||||
if(padID.indexOf("$")!=-1)
|
||||
{
|
||||
var groupID = padID.substring(0,padID.indexOf("$"));
|
||||
|
||||
db.get("group:" + groupID, function (err, group)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
//remove the pad entry
|
||||
delete group.pads[padID];
|
||||
|
||||
//set the new value
|
||||
db.set("group:" + groupID, group);
|
||||
|
||||
callback();
|
||||
});
|
||||
}
|
||||
//its no group pad, nothing to do here
|
||||
else
|
||||
{
|
||||
callback();
|
||||
}
|
||||
},
|
||||
//remove the readonly entries
|
||||
function(callback)
|
||||
{
|
||||
readOnlyManager.getReadOnlyId(padID, function(err, readonlyID)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
db.remove("pad2readonly:" + padID);
|
||||
db.remove("readonly2pad:" + readonlyID);
|
||||
|
||||
callback();
|
||||
});
|
||||
},
|
||||
//delete all chat messages
|
||||
function(callback)
|
||||
{
|
||||
var chatHead = _this.chatHead;
|
||||
|
||||
for(var i=0;i<=chatHead;i++)
|
||||
{
|
||||
db.remove("pad:"+padID+":chat:"+i);
|
||||
}
|
||||
|
||||
callback();
|
||||
},
|
||||
//delete all revisions
|
||||
function(callback)
|
||||
{
|
||||
var revHead = _this.head;
|
||||
|
||||
for(var i=0;i<=revHead;i++)
|
||||
{
|
||||
db.remove("pad:"+padID+":revs:"+i);
|
||||
}
|
||||
|
||||
callback();
|
||||
}
|
||||
], callback);
|
||||
},
|
||||
//delete the pad entry and delete pad from padManager
|
||||
function(callback)
|
||||
{
|
||||
db.remove("pad:"+padID);
|
||||
padManager.unloadPad(padID);
|
||||
callback();
|
||||
}
|
||||
], function(err)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
callback();
|
||||
});
|
||||
};
|
||||
|
||||
//set in db
|
||||
Pad.prototype.setPublicStatus = function setPublicStatus(publicStatus) {
|
||||
this.publicStatus = publicStatus;
|
||||
db.setSub("pad:"+this.id, ["publicStatus"], this.publicStatus);
|
||||
};
|
||||
|
||||
Pad.prototype.setPassword = function setPassword(password) {
|
||||
this.passwordHash = password ? hash(password, generateSalt()) : null;
|
||||
db.setSub("pad:"+this.id, ["passwordHash"], this.passwordHash);
|
||||
};
|
||||
|
||||
Pad.isCorrectPassword = function isCorrectPassword(password) {
|
||||
return compare(this.passwordHash, password);
|
||||
};
|
||||
|
||||
Pad.isPasswordProtected = function isPasswordProtected() {
|
||||
return this.passwordHash ? true: false;
|
||||
};
|
||||
|
||||
|
||||
/* Crypto helper methods */
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
var ERR = require("async-stacktrace");
|
||||
var customError = require("../utils/customError");
|
||||
require("../db/Pad");
|
||||
var Pad = require("../db/Pad").Pad;
|
||||
var db = require("./DB").db;
|
||||
|
||||
/**
|
||||
|
@ -53,14 +53,14 @@ exports.getPad = function(id, text, callback)
|
|||
}
|
||||
|
||||
//make text an optional parameter
|
||||
if(typeof text == "function")
|
||||
if(typeof text === "function")
|
||||
{
|
||||
callback = text;
|
||||
text = null;
|
||||
}
|
||||
|
||||
//check if this is a valid text
|
||||
if(text != null)
|
||||
if(text)
|
||||
{
|
||||
//check if text is a string
|
||||
if(typeof text != "string")
|
||||
|
@ -80,7 +80,7 @@ exports.getPad = function(id, text, callback)
|
|||
var pad = globalPads.get(id);
|
||||
|
||||
//return pad if its already loaded
|
||||
if(pad != null)
|
||||
if(pad)
|
||||
{
|
||||
callback(null, pad);
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ exports.getPad = function(id, text, callback)
|
|||
callback(null, pad);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//checks if a pad exists
|
||||
exports.doesPadExists = function(padId, callback)
|
||||
|
@ -106,18 +106,18 @@ exports.doesPadExists = function(padId, callback)
|
|||
db.get("pad:"+padId, function(err, value)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
callback(null, value != null);
|
||||
callback(null, value ? true : false);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.isValidPadId = function(padId)
|
||||
{
|
||||
return /^(g.[a-zA-Z0-9]{16}\$)?[^$]{1,50}$/.test(padId);
|
||||
}
|
||||
return (/^(g.[a-zA-Z0-9]{16}\$)?[^$]{1,50}$/).test(padId);
|
||||
};
|
||||
|
||||
//removes a pad from the array
|
||||
exports.unloadPad = function(padId)
|
||||
{
|
||||
if(globalPads.get(padId))
|
||||
globalPads.remove(padId);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -39,7 +39,7 @@ exports.getReadOnlyId = function (padId, callback)
|
|||
function(dbReadOnlyId, callback)
|
||||
{
|
||||
//there is no readOnly Entry in the database, let's create one
|
||||
if(dbReadOnlyId == null)
|
||||
if(!dbReadOnlyId)
|
||||
{
|
||||
readOnlyId = "r." + randomString(16);
|
||||
|
||||
|
@ -59,8 +59,8 @@ exports.getReadOnlyId = function (padId, callback)
|
|||
if(ERR(err, callback)) return;
|
||||
//return the results
|
||||
callback(null, readOnlyId);
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* returns a the padId for a read only id
|
||||
|
@ -69,7 +69,7 @@ exports.getReadOnlyId = function (padId, callback)
|
|||
exports.getPadId = function(readOnlyId, callback)
|
||||
{
|
||||
db.get("readonly2pad:" + readOnlyId, callback);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates a random String with the given length. Is needed to generate the read only ids
|
||||
|
|
|
@ -24,7 +24,7 @@ var async = require("async");
|
|||
var authorManager = require("./AuthorManager");
|
||||
var padManager = require("./PadManager");
|
||||
var sessionManager = require("./SessionManager");
|
||||
var settings = require("../utils/Settings")
|
||||
var settings = require("../utils/Settings");
|
||||
|
||||
/**
|
||||
* This function controlls the access to a pad, it checks if the user can access a pad.
|
||||
|
@ -81,7 +81,7 @@ exports.checkAccess = function (padID, sessionID, token, password, callback)
|
|||
// grant access, with author of token
|
||||
callback(null, statusObject);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
//don't continue
|
||||
return;
|
||||
|
@ -95,7 +95,7 @@ exports.checkAccess = function (padID, sessionID, token, password, callback)
|
|||
var tokenAuthor;
|
||||
var isPublic;
|
||||
var isPasswordProtected;
|
||||
var passwordStatus = password == null ? "notGiven" : "wrong"; // notGiven, correct, wrong
|
||||
var passwordStatus = password === null ? "notGiven" : "wrong"; // notGiven, correct, wrong
|
||||
|
||||
async.series([
|
||||
//get basic informations from the database
|
||||
|
@ -156,7 +156,7 @@ exports.checkAccess = function (padID, sessionID, token, password, callback)
|
|||
function(callback)
|
||||
{
|
||||
//skip this if the pad doesn't exists
|
||||
if(padExists == false)
|
||||
if(!padExists)
|
||||
{
|
||||
callback();
|
||||
return;
|
||||
|
@ -275,4 +275,4 @@ exports.checkAccess = function (padID, sessionID, token, password, callback)
|
|||
if(ERR(err, callback)) return;
|
||||
callback(null, statusObject);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -31,9 +31,9 @@ exports.doesSessionExist = function(sessionID, callback)
|
|||
db.get("session:" + sessionID, function (err, session)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
callback(null, session != null);
|
||||
callback(null, session ? true : false);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new session between an author and a group
|
||||
|
@ -51,7 +51,7 @@ exports.createSession = function(groupID, authorID, validUntil, callback)
|
|||
if(ERR(err, callback)) return;
|
||||
|
||||
//group does not exist
|
||||
if(exists == false)
|
||||
if(!exists)
|
||||
{
|
||||
callback(new customError("groupID does not exist","apierror"));
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ exports.createSession = function(groupID, authorID, validUntil, callback)
|
|||
if(ERR(err, callback)) return;
|
||||
|
||||
//author does not exist
|
||||
if(exists == false)
|
||||
if(!exists)
|
||||
{
|
||||
callback(new customError("authorID does not exist","apierror"));
|
||||
}
|
||||
|
@ -88,9 +88,9 @@ exports.createSession = function(groupID, authorID, validUntil, callback)
|
|||
if(typeof validUntil != "number")
|
||||
{
|
||||
//try to parse the number
|
||||
if(!isNaN(parseInt(validUntil)))
|
||||
if(!isNaN(parseInt(validUntil, 10)))
|
||||
{
|
||||
validUntil = parseInt(validUntil);
|
||||
validUntil = parseInt(validUntil, 10);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -137,7 +137,7 @@ exports.createSession = function(groupID, authorID, validUntil, callback)
|
|||
if(ERR(err, callback)) return;
|
||||
|
||||
//the entry doesn't exist so far, let's create it
|
||||
if(group2sessions == null)
|
||||
if(!group2sessions)
|
||||
{
|
||||
group2sessions = {sessionIDs : {}};
|
||||
}
|
||||
|
@ -160,7 +160,7 @@ exports.createSession = function(groupID, authorID, validUntil, callback)
|
|||
if(ERR(err, callback)) return;
|
||||
|
||||
//the entry doesn't exist so far, let's create it
|
||||
if(author2sessions == null)
|
||||
if(!author2sessions)
|
||||
{
|
||||
author2sessions = {sessionIDs : {}};
|
||||
}
|
||||
|
@ -180,8 +180,8 @@ exports.createSession = function(groupID, authorID, validUntil, callback)
|
|||
|
||||
//return error and sessionID
|
||||
callback(null, {sessionID: sessionID});
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
exports.getSessionInfo = function(sessionID, callback)
|
||||
{
|
||||
|
@ -191,9 +191,9 @@ exports.getSessionInfo = function(sessionID, callback)
|
|||
if(ERR(err, callback)) return;
|
||||
|
||||
//session does not exists
|
||||
if(session == null)
|
||||
if(session === null)
|
||||
{
|
||||
callback(new customError("sessionID does not exist","apierror"))
|
||||
callback(new customError("sessionID does not exist","apierror"));
|
||||
}
|
||||
//everything is fine, return the sessioninfos
|
||||
else
|
||||
|
@ -201,7 +201,7 @@ exports.getSessionInfo = function(sessionID, callback)
|
|||
callback(null, session);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Deletes a session
|
||||
|
@ -220,9 +220,9 @@ exports.deleteSession = function(sessionID, callback)
|
|||
if(ERR(err, callback)) return;
|
||||
|
||||
//session does not exists
|
||||
if(session == null)
|
||||
if(!session)
|
||||
{
|
||||
callback(new customError("sessionID does not exist","apierror"))
|
||||
callback(new customError("sessionID does not exist","apierror"));
|
||||
}
|
||||
//everything is fine, return the sessioninfos
|
||||
else
|
||||
|
@ -274,8 +274,8 @@ exports.deleteSession = function(sessionID, callback)
|
|||
{
|
||||
if(ERR(err, callback)) return;
|
||||
callback();
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
exports.listSessionsOfGroup = function(groupID, callback)
|
||||
{
|
||||
|
@ -284,7 +284,7 @@ exports.listSessionsOfGroup = function(groupID, callback)
|
|||
if(ERR(err, callback)) return;
|
||||
|
||||
//group does not exist
|
||||
if(exists == false)
|
||||
if(!exists)
|
||||
{
|
||||
callback(new customError("groupID does not exist","apierror"));
|
||||
}
|
||||
|
@ -294,7 +294,7 @@ exports.listSessionsOfGroup = function(groupID, callback)
|
|||
listSessionsWithDBKey("group2sessions:" + groupID, callback);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.listSessionsOfAuthor = function(authorID, callback)
|
||||
{
|
||||
|
@ -303,7 +303,7 @@ exports.listSessionsOfAuthor = function(authorID, callback)
|
|||
if(ERR(err, callback)) return;
|
||||
|
||||
//group does not exist
|
||||
if(exists == false)
|
||||
if(!exists)
|
||||
{
|
||||
callback(new customError("authorID does not exist","apierror"));
|
||||
}
|
||||
|
@ -313,7 +313,7 @@ exports.listSessionsOfAuthor = function(authorID, callback)
|
|||
listSessionsWithDBKey("author2sessions:" + authorID, callback);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
//this function is basicly the code listSessionsOfAuthor and listSessionsOfGroup has in common
|
||||
function listSessionsWithDBKey (dbkey, callback)
|
||||
|
@ -376,5 +376,5 @@ function randomString(len)
|
|||
//checks if a number is an int
|
||||
function is_int(value)
|
||||
{
|
||||
return (parseFloat(value) == parseInt(value)) && !isNaN(value)
|
||||
return (parseFloat(value) == parseInt(value, 10)) && !isNaN(value);
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ var functions = {
|
|||
exports.handle = function(functionName, fields, req, res)
|
||||
{
|
||||
//check the api key!
|
||||
if(fields["apikey"] != apikey.trim())
|
||||
if(fields.apikey != apikey.trim())
|
||||
{
|
||||
res.send({code: 4, message: "no or wrong API Key", data: null});
|
||||
return;
|
||||
|
@ -107,7 +107,7 @@ exports.handle = function(functionName, fields, req, res)
|
|||
functionParams.push(function(err, data)
|
||||
{
|
||||
// no error happend, everything is fine
|
||||
if(err == null)
|
||||
if(!err)
|
||||
{
|
||||
if(!data)
|
||||
data = null;
|
||||
|
@ -129,7 +129,7 @@ exports.handle = function(functionName, fields, req, res)
|
|||
|
||||
//call the api function
|
||||
api[functionName](functionParams[0],functionParams[1],functionParams[2],functionParams[3],functionParams[4]);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates a random String with the given length. Is needed to generate the Author Ids
|
||||
|
|
|
@ -28,8 +28,10 @@ var settings = require('../utils/Settings');
|
|||
var os = require('os');
|
||||
|
||||
//load abiword only if its enabled
|
||||
if(settings.abiword != null)
|
||||
if(settings.abiword)
|
||||
{
|
||||
var abiword = require("../utils/Abiword");
|
||||
}
|
||||
|
||||
var tempDirectory = "/tmp";
|
||||
|
||||
|
@ -47,6 +49,10 @@ exports.doExport = function(req, res, padId, type)
|
|||
//tell the browser that this is a downloadable file
|
||||
res.attachment(padId + "." + type);
|
||||
|
||||
var randNum;
|
||||
var srcFile;
|
||||
var destFile;
|
||||
|
||||
//if this is a plain text export, we can do this directly
|
||||
if(type == "txt")
|
||||
{
|
||||
|
@ -59,8 +65,6 @@ exports.doExport = function(req, res, padId, type)
|
|||
}
|
||||
else if(type == 'dokuwiki')
|
||||
{
|
||||
var randNum;
|
||||
var srcFile, destFile;
|
||||
|
||||
async.series([
|
||||
//render the dokuwiki document
|
||||
|
@ -71,7 +75,7 @@ exports.doExport = function(req, res, padId, type)
|
|||
res.send(dokuwiki);
|
||||
callback("stop");
|
||||
});
|
||||
},
|
||||
}
|
||||
], function(err)
|
||||
{
|
||||
if(err && err != "stop") throw err;
|
||||
|
@ -80,8 +84,6 @@ exports.doExport = function(req, res, padId, type)
|
|||
else
|
||||
{
|
||||
var html;
|
||||
var randNum;
|
||||
var srcFile, destFile;
|
||||
|
||||
async.series([
|
||||
//render the html document
|
||||
|
@ -152,6 +154,6 @@ exports.doExport = function(req, res, padId, type)
|
|||
], function(err)
|
||||
{
|
||||
if(err && err != "stop") ERR(err);
|
||||
})
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -28,8 +28,10 @@ var formidable = require('formidable');
|
|||
var os = require("os");
|
||||
|
||||
//load abiword only if its enabled
|
||||
if(settings.abiword != null)
|
||||
if(settings.abiword)
|
||||
{
|
||||
var abiword = require("../utils/Abiword");
|
||||
}
|
||||
|
||||
var tempDirectory = "/tmp/";
|
||||
|
||||
|
@ -139,17 +141,17 @@ exports.doImport = function(req, res, padId)
|
|||
|
||||
//node on windows has a delay on releasing of the file lock.
|
||||
//We add a 100ms delay to work around this
|
||||
if(os.type().indexOf("Windows") > -1)
|
||||
{
|
||||
if(os.type().indexOf("Windows") > -1)
|
||||
{
|
||||
setTimeout(function()
|
||||
{
|
||||
callback();
|
||||
}, 100);
|
||||
}
|
||||
else
|
||||
{
|
||||
callback();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
callback();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -188,4 +190,4 @@ exports.doImport = function(req, res, padId)
|
|||
//close the connection
|
||||
res.send("ok");
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -61,7 +61,7 @@ var socketio;
|
|||
exports.setSocketIO = function(socket_io)
|
||||
{
|
||||
socketio=socket_io;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles the connection of a new user
|
||||
|
@ -72,7 +72,7 @@ exports.handleConnect = function(client)
|
|||
//Initalize session2pad and sessioninfos for this new session
|
||||
session2pad[client.id]=null;
|
||||
sessioninfos[client.id]={};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Kicks all sessions from a pad
|
||||
|
@ -89,7 +89,7 @@ exports.kickSessionsFromPad = function(padID)
|
|||
{
|
||||
socketio.sockets.sockets[pad2sessions[padID][i]].json.send({disconnect:"deleted"});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles the disconnection of a user
|
||||
|
@ -125,7 +125,7 @@ exports.handleDisconnect = function(client)
|
|||
};
|
||||
|
||||
//Go trough all user that are still on the pad, and send them the USER_LEAVE message
|
||||
for(i in pad2sessions[sessionPad])
|
||||
for(var i in pad2sessions[sessionPad])
|
||||
{
|
||||
socketio.sockets.sockets[pad2sessions[sessionPad][i]].json.send(messageToTheOtherUsers);
|
||||
}
|
||||
|
@ -133,7 +133,7 @@ exports.handleDisconnect = function(client)
|
|||
}
|
||||
|
||||
//Go trough all sessions of this pad, search and destroy the entry of this client
|
||||
for(i in pad2sessions[sessionPad])
|
||||
for(var i in pad2sessions[sessionPad])
|
||||
{
|
||||
if(pad2sessions[sessionPad][i] == client.id)
|
||||
{
|
||||
|
@ -145,7 +145,7 @@ exports.handleDisconnect = function(client)
|
|||
//Delete the session2pad and sessioninfos entrys of this session
|
||||
delete session2pad[client.id];
|
||||
delete sessioninfos[client.id];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles a message from a user
|
||||
|
@ -154,7 +154,7 @@ exports.handleDisconnect = function(client)
|
|||
*/
|
||||
exports.handleMessage = function(client, message)
|
||||
{
|
||||
if(message == null)
|
||||
if(!message)
|
||||
{
|
||||
messageLogger.warn("Message is null!");
|
||||
return;
|
||||
|
@ -186,17 +186,28 @@ exports.handleMessage = function(client, message)
|
|||
handleChatMessage(client, message);
|
||||
}
|
||||
else if(message.type == "COLLABROOM" &&
|
||||
message.data.type == "CLIENT_MESSAGE" &&
|
||||
message.data.payload.type == "suggestUserName")
|
||||
message.data.type == "CLIENT_MESSAGE")
|
||||
{
|
||||
handleSuggestUserName(client, message);
|
||||
if(message.data.payload.type == "suggestUserName")
|
||||
{
|
||||
handleSuggestUserName(client, message);
|
||||
}
|
||||
else if (message.data.payload.type == "padoptions")
|
||||
{
|
||||
messageLogger.info("Handler not implemented for payload type: " + message.data.payload.type);
|
||||
//handlePadOptions
|
||||
}
|
||||
else
|
||||
{
|
||||
messageLogger.warn("Dropped COLLABROOM CLIENT_MESSAGE message, unknown Message Type " + message.type);
|
||||
}
|
||||
}
|
||||
//if the message type is unknown, throw an exception
|
||||
else
|
||||
{
|
||||
messageLogger.warn("Dropped message, unknown Message Type " + message.type);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles a Chat Message
|
||||
|
@ -273,12 +284,12 @@ function handleChatMessage(client, message)
|
|||
function handleSuggestUserName(client, message)
|
||||
{
|
||||
//check if all ok
|
||||
if(message.data.payload.newName == null)
|
||||
if(!message.data.payload.newName)
|
||||
{
|
||||
messageLogger.warn("Dropped message, suggestUserName Message has no newName!");
|
||||
return;
|
||||
}
|
||||
if(message.data.payload.unnamedId == null)
|
||||
if(!message.data.payload.unnamedId)
|
||||
{
|
||||
messageLogger.warn("Dropped message, suggestUserName Message has no unnamedId!");
|
||||
return;
|
||||
|
@ -305,7 +316,7 @@ function handleSuggestUserName(client, message)
|
|||
function handleUserInfoUpdate(client, message)
|
||||
{
|
||||
//check if all ok
|
||||
if(message.data.userInfo.colorId == null)
|
||||
if(!message.data.userInfo.colorId)
|
||||
{
|
||||
messageLogger.warn("Dropped message, USERINFO_UPDATE Message has no colorId!");
|
||||
return;
|
||||
|
@ -321,7 +332,7 @@ function handleUserInfoUpdate(client, message)
|
|||
var padId = session2pad[client.id];
|
||||
|
||||
//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)
|
||||
{
|
||||
message.data.userInfo.name = null;
|
||||
}
|
||||
|
@ -349,17 +360,17 @@ function handleUserInfoUpdate(client, message)
|
|||
function handleUserChanges(client, message)
|
||||
{
|
||||
//check if all ok
|
||||
if(message.data.baseRev == null)
|
||||
if(message.data.baseRev === null || message.data.baseRev === undefined)
|
||||
{
|
||||
messageLogger.warn("Dropped message, USER_CHANGES Message has no baseRev!");
|
||||
return;
|
||||
}
|
||||
if(message.data.apool == null)
|
||||
if(!message.data.apool)
|
||||
{
|
||||
messageLogger.warn("Dropped message, USER_CHANGES Message has no apool!");
|
||||
return;
|
||||
}
|
||||
if(message.data.changeset == null)
|
||||
if(!message.data.changeset)
|
||||
{
|
||||
messageLogger.warn("Dropped message, USER_CHANGES Message has no changeset!");
|
||||
return;
|
||||
|
@ -488,7 +499,7 @@ exports.updatePadClients = function(pad, callback)
|
|||
//https://github.com/caolan/async#whilst
|
||||
//send them all new changesets
|
||||
async.whilst(
|
||||
function (){ return lastRev < pad.getHeadRevisionNumber()},
|
||||
function (){ return lastRev < pad.getHeadRevisionNumber(); },
|
||||
function(callback)
|
||||
{
|
||||
var author, revChangeset;
|
||||
|
@ -541,7 +552,7 @@ exports.updatePadClients = function(pad, callback)
|
|||
|
||||
sessioninfos[session].rev = pad.getHeadRevisionNumber();
|
||||
},callback);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Copied from the Etherpad Source Code. Don't know what this methode does excatly...
|
||||
|
@ -570,7 +581,7 @@ function _correctMarkersInPad(atext, apool) {
|
|||
}
|
||||
}
|
||||
|
||||
if (badMarkers.length == 0) {
|
||||
if (badMarkers.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -640,7 +651,7 @@ function handleClientReady(client, message)
|
|||
//no access, send the client a message that tell him why
|
||||
else
|
||||
{
|
||||
client.json.send({accessStatus: statusObject.accessStatus})
|
||||
client.json.send({accessStatus: statusObject.accessStatus});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
@ -756,8 +767,8 @@ function handleClientReady(client, message)
|
|||
atext.attribs = attribsForWire.translated;
|
||||
|
||||
//check if abiword is avaiable
|
||||
var abiwordAvailable = settings.abiword != null ? "yes" : "no";
|
||||
if(settings.abiword != null && os.type().indexOf("Windows") != -1)
|
||||
var abiwordAvailable = settings.abiword ? "yes" : "no";
|
||||
if(settings.abiword && os.type().indexOf("Windows") != -1)
|
||||
{
|
||||
abiwordAvailable = "withoutPDF";
|
||||
}
|
||||
|
@ -800,10 +811,10 @@ function handleClientReady(client, message)
|
|||
},
|
||||
"abiwordAvailable": abiwordAvailable,
|
||||
"hooks": {}
|
||||
}
|
||||
};
|
||||
|
||||
//Add a username to the clientVars if one avaiable
|
||||
if(authorName != null)
|
||||
if(authorName)
|
||||
{
|
||||
clientVars.userName = authorName;
|
||||
}
|
||||
|
@ -811,7 +822,7 @@ function handleClientReady(client, message)
|
|||
if(sessioninfos[client.id] !== undefined)
|
||||
{
|
||||
//This is a reconnect, so we don't have to send the client the ClientVars again
|
||||
if(message.reconnect == true)
|
||||
if(message.reconnect)
|
||||
{
|
||||
//Save the revision in sessioninfos, we take the revision from the info the client send to us
|
||||
sessioninfos[client.id].rev = message.client_rev;
|
||||
|
@ -844,7 +855,7 @@ function handleClientReady(client, message)
|
|||
};
|
||||
|
||||
//Add the authorname of this new User, if avaiable
|
||||
if(authorName != null)
|
||||
if(authorName)
|
||||
{
|
||||
messageToTheOtherUsers.data.userInfo.name = authorName;
|
||||
}
|
||||
|
@ -866,7 +877,7 @@ function handleClientReady(client, message)
|
|||
if(ERR(err, callback)) return;
|
||||
sessionAuthorColorId = value;
|
||||
callback();
|
||||
})
|
||||
});
|
||||
},
|
||||
function(callback)
|
||||
{
|
||||
|
@ -875,7 +886,7 @@ function handleClientReady(client, message)
|
|||
if(ERR(err, callback)) return;
|
||||
sessionAuthorName = value;
|
||||
callback();
|
||||
})
|
||||
});
|
||||
}
|
||||
],callback);
|
||||
},
|
||||
|
|
|
@ -43,7 +43,7 @@ exports.addComponent = function(moduleName, module)
|
|||
|
||||
//give the module the socket
|
||||
module.setSocketIO(socket);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* sets the socket.io and adds event functions for routing
|
||||
|
@ -63,7 +63,7 @@ exports.setSocketIO = function(_socket)
|
|||
{
|
||||
messageLogger.info("to " + client.id + ": " + stringifyWithoutPassword(message));
|
||||
client._send(message);
|
||||
}
|
||||
};
|
||||
|
||||
//tell all components about this connect
|
||||
for(var i in components)
|
||||
|
@ -143,7 +143,7 @@ exports.setSocketIO = function(_socket)
|
|||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
//returns a stringified representation of a message, removes the password
|
||||
//this ensures there are no passwords in the log
|
||||
|
@ -153,8 +153,8 @@ function stringifyWithoutPassword(message)
|
|||
|
||||
for(var i in message)
|
||||
{
|
||||
if(i == "password" && message[i] != null)
|
||||
newMessage["password"] = "xxx";
|
||||
if(i == "password" && message[i])
|
||||
newMessage.password = "xxx";
|
||||
else
|
||||
newMessage[i]=message[i];
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ var socketio;
|
|||
exports.setSocketIO = function(socket_io)
|
||||
{
|
||||
socketio=socket_io;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles the connection of a new user
|
||||
|
@ -48,7 +48,7 @@ exports.setSocketIO = function(socket_io)
|
|||
exports.handleConnect = function(client)
|
||||
{
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles the disconnection of a user
|
||||
|
@ -57,7 +57,7 @@ exports.handleConnect = function(client)
|
|||
exports.handleDisconnect = function(client)
|
||||
{
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles a message from a user
|
||||
|
@ -80,11 +80,11 @@ exports.handleMessage = function(client, message)
|
|||
{
|
||||
messageLogger.warn("Dropped message, unknown Message Type: '" + message.type + "'");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function handleClientReady(client, message)
|
||||
{
|
||||
if(message.padId == null)
|
||||
if(!message.padId)
|
||||
{
|
||||
messageLogger.warn("Dropped message, changeset request has no padId!");
|
||||
return;
|
||||
|
@ -96,7 +96,7 @@ function handleClientReady(client, message)
|
|||
ERR(err);
|
||||
|
||||
client.json.send({type: "CLIENT_VARS", data: clientVars});
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -105,27 +105,27 @@ function handleClientReady(client, message)
|
|||
function handleChangesetRequest(client, message)
|
||||
{
|
||||
//check if all ok
|
||||
if(message.data == null)
|
||||
if(!message.data)
|
||||
{
|
||||
messageLogger.warn("Dropped message, changeset request has no data!");
|
||||
return;
|
||||
}
|
||||
if(message.padId == null)
|
||||
if(!message.padId)
|
||||
{
|
||||
messageLogger.warn("Dropped message, changeset request has no padId!");
|
||||
return;
|
||||
}
|
||||
if(message.data.granularity == null)
|
||||
if(!message.data.granularity)
|
||||
{
|
||||
messageLogger.warn("Dropped message, changeset request has no granularity!");
|
||||
return;
|
||||
}
|
||||
if(message.data.start == null)
|
||||
if(!message.data.start)
|
||||
{
|
||||
messageLogger.warn("Dropped message, changeset request has no start!");
|
||||
return;
|
||||
}
|
||||
if(message.data.requestID == null)
|
||||
if(!message.data.requestID)
|
||||
{
|
||||
messageLogger.warn("Dropped message, changeset request has no requestID!");
|
||||
return;
|
||||
|
@ -301,7 +301,7 @@ function getChangesetInfo(padId, startNum, endNum, granularity, callback)
|
|||
compositesChangesetNeeded.push({start: compositeStart, end: compositeEnd});
|
||||
|
||||
//add the t1 time we need
|
||||
revTimesNeeded.push(compositeStart == 0 ? 0 : compositeStart - 1);
|
||||
revTimesNeeded.push(compositeStart === 0 ? 0 : compositeStart - 1);
|
||||
//add the t2 time we need
|
||||
revTimesNeeded.push(compositeEnd - 1);
|
||||
|
||||
|
@ -372,7 +372,7 @@ function getChangesetInfo(padId, startNum, endNum, granularity, callback)
|
|||
var backwards2 = Changeset.moveOpsToNewPool(backwards, pad.apool(), apool);
|
||||
|
||||
var t1, t2;
|
||||
if (compositeStart == 0)
|
||||
if (compositeStart === 0)
|
||||
{
|
||||
t1 = revisionDate[0];
|
||||
}
|
||||
|
|
|
@ -53,10 +53,10 @@ try
|
|||
}
|
||||
catch(e)
|
||||
{
|
||||
console.warn("Can't get git version for server header\n" + e.message)
|
||||
console.warn("Can't get git version for server header\n" + e.message);
|
||||
}
|
||||
|
||||
console.log("Report bugs at https://github.com/Pita/etherpad-lite/issues")
|
||||
console.log("Report bugs at https://github.com/Pita/etherpad-lite/issues");
|
||||
|
||||
var serverName = "Etherpad-Lite " + version + " (http://j.mp/ep-lite)";
|
||||
|
||||
|
@ -93,12 +93,15 @@ async.waterfall([
|
|||
app.configure(function()
|
||||
{
|
||||
// Activate http basic auth if it has been defined in settings.json
|
||||
if(settings.httpAuth != null) app.use(basic_auth);
|
||||
if(settings.httpAuth) {
|
||||
app.use(basic_auth);
|
||||
}
|
||||
|
||||
// If the log level specified in the config file is WARN or ERROR the application server never starts listening to requests as reported in issue #158.
|
||||
// Not installing the log4js connect logger when the log level has a higher severity than INFO since it would not log at that level anyway.
|
||||
if (!(settings.loglevel === "WARN" || settings.loglevel == "ERROR"))
|
||||
if (!(settings.loglevel === "WARN" || settings.loglevel == "ERROR")) {
|
||||
app.use(log4js.connectLogger(httpLogger, { level: log4js.levels.INFO, format: ':status, :method :url'}));
|
||||
}
|
||||
app.use(express.cookieParser());
|
||||
});
|
||||
|
||||
|
@ -137,6 +140,7 @@ async.waterfall([
|
|||
//checks for padAccess
|
||||
function hasPadAccess(req, res, callback)
|
||||
{
|
||||
console.log(req.params);
|
||||
securityManager.checkAccess(req.params.pad, req.cookies.sessionid, req.cookies.token, req.cookies.password, function(err, accessObj)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
@ -203,7 +207,7 @@ async.waterfall([
|
|||
function(callback)
|
||||
{
|
||||
//return if the there is no padId
|
||||
if(padId == null)
|
||||
if(!padId)
|
||||
{
|
||||
callback("notfound");
|
||||
return;
|
||||
|
@ -282,8 +286,7 @@ async.waterfall([
|
|||
}
|
||||
|
||||
//if abiword is disabled, and this is a format we only support with abiword, output a message
|
||||
if(settings.abiword == null &&
|
||||
["odt", "pdf", "doc"].indexOf(req.params.type) !== -1)
|
||||
if(!settings.abiword && ["odt", "pdf", "doc"].indexOf(req.params.type) !== -1)
|
||||
{
|
||||
res.send("Abiword is not enabled at this Etherpad Lite instance. Set the path to Abiword in settings.json to enable this feature");
|
||||
return;
|
||||
|
@ -309,7 +312,7 @@ async.waterfall([
|
|||
}
|
||||
|
||||
//if abiword is disabled, skip handling this request
|
||||
if(settings.abiword == null)
|
||||
if(!settings.abiword)
|
||||
{
|
||||
next();
|
||||
return;
|
||||
|
@ -344,16 +347,16 @@ async.waterfall([
|
|||
response = req.query.jsonp + "(" + response + ")";
|
||||
|
||||
res._send(response);
|
||||
}
|
||||
};
|
||||
|
||||
//call the api handler
|
||||
apiHandler.handle(req.params.func, fields, req, res);
|
||||
}
|
||||
};
|
||||
|
||||
//This is a api GET call, collect all post informations and pass it to the apiHandler
|
||||
app.get('/api/1/:func', function(req, res)
|
||||
{
|
||||
apiCaller(req, res, req.query)
|
||||
apiCaller(req, res, req.query);
|
||||
});
|
||||
|
||||
//This is a api POST call, collect all post informations and pass it to the apiHandler
|
||||
|
@ -361,7 +364,7 @@ async.waterfall([
|
|||
{
|
||||
new formidable.IncomingForm().parse(req, function(err, fields, files)
|
||||
{
|
||||
apiCaller(req, res, fields)
|
||||
apiCaller(req, res, fields);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -453,7 +456,7 @@ async.waterfall([
|
|||
setTimeout(function(){
|
||||
process.exit(1);
|
||||
}, 3000);
|
||||
}
|
||||
};
|
||||
|
||||
//connect graceful shutdown with sigint and uncaughtexception
|
||||
if(os.type().indexOf("Windows") == -1)
|
||||
|
@ -489,7 +492,7 @@ async.waterfall([
|
|||
error: function (str)
|
||||
{
|
||||
socketIOLogger.error.apply(socketIOLogger, arguments);
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
//minify socket.io javascript
|
||||
|
|
|
@ -52,18 +52,18 @@ if(os.type().indexOf("Windows") > -1)
|
|||
//throw exceptions if abiword is dieing
|
||||
abiword.on('exit', function (code)
|
||||
{
|
||||
if(code != 0) {
|
||||
if(code !== 0) {
|
||||
throw "Abiword died with exit code " + code;
|
||||
}
|
||||
|
||||
if(stdoutBuffer != "")
|
||||
if(stdoutBuffer !== "")
|
||||
{
|
||||
console.log(stdoutBuffer);
|
||||
}
|
||||
|
||||
callback();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.convertFile = function(srcFile, destFile, type, callback)
|
||||
{
|
||||
|
@ -89,14 +89,12 @@ else
|
|||
throw "Abiword died with exit code " + code;
|
||||
});
|
||||
|
||||
//delegate the processing of stdout to a other function
|
||||
abiword.stdout.on('data',onAbiwordStdout);
|
||||
|
||||
var stdoutCallback = null;
|
||||
var stdoutBuffer = "";
|
||||
var firstPrompt = true;
|
||||
|
||||
function onAbiwordStdout(data)
|
||||
var onAbiwordStdout = function onAbiwordStdout(data)
|
||||
{
|
||||
//add data to buffer
|
||||
stdoutBuffer+=data.toString();
|
||||
|
@ -112,7 +110,7 @@ else
|
|||
|
||||
//call the callback with the error message
|
||||
//skip the first prompt
|
||||
if(stdoutCallback != null && !firstPrompt)
|
||||
if(stdoutCallback && !firstPrompt)
|
||||
{
|
||||
stdoutCallback(err);
|
||||
stdoutCallback = null;
|
||||
|
@ -120,7 +118,10 @@ else
|
|||
|
||||
firstPrompt = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//delegate the processing of stdout to a other function
|
||||
abiword.stdout.on('data',onAbiwordStdout);
|
||||
|
||||
doConvertTask = function(task, callback)
|
||||
{
|
||||
|
@ -132,7 +133,7 @@ else
|
|||
callback();
|
||||
task.callback(err);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
//Queue with the converts we have to do
|
||||
var queue = async.queue(doConvertTask, 1);
|
||||
|
|
|
@ -87,4 +87,4 @@ exports.createAttributePool = function () {
|
|||
};
|
||||
|
||||
return p;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -66,7 +66,7 @@ exports.newLen = function (cs) {
|
|||
|
||||
exports.opIterator = function (opsStr, optStartIndex) {
|
||||
//print(opsStr);
|
||||
var regex = /((?:\*[0-9a-z]+)*)(?:\|([0-9a-z]+))?([-+=])([0-9a-z]+)|\?|/g;
|
||||
var regex = /((?:\*[0-9a-z]+)*)(?:\|([0-9a-z]+))?([\-+=])([0-9a-z]+)|\?|/g;
|
||||
var startIndex = (optStartIndex || 0);
|
||||
var curIndex = startIndex;
|
||||
var prevIndex = curIndex;
|
||||
|
@ -195,12 +195,10 @@ exports.checkRep = function (cs) {
|
|||
exports.assert(oldPos < oldLen, oldPos, " >= ", oldLen, " in ", cs);
|
||||
break;
|
||||
case '+':
|
||||
{
|
||||
calcNewLen += o.chars;
|
||||
numInserted += o.chars;
|
||||
exports.assert(calcNewLen < newLen, calcNewLen, " >= ", newLen, " in ", cs);
|
||||
break;
|
||||
}
|
||||
calcNewLen += o.chars;
|
||||
numInserted += o.chars;
|
||||
exports.assert(calcNewLen < newLen, calcNewLen, " >= ", newLen, " in ", cs);
|
||||
break;
|
||||
}
|
||||
assem.append(o);
|
||||
}
|
||||
|
@ -216,7 +214,7 @@ exports.checkRep = function (cs) {
|
|||
exports.assert(normalized == cs, normalized, ' != ', cs);
|
||||
|
||||
return cs;
|
||||
}
|
||||
};
|
||||
|
||||
exports.smartOpAssembler = function () {
|
||||
// Like opAssembler but able to produce conforming exportss
|
||||
|
@ -387,7 +385,7 @@ if (_opt) {
|
|||
bufOp.chars += bufOpAdditionalCharsAfterNewline + op.chars;
|
||||
bufOp.lines += op.lines;
|
||||
bufOpAdditionalCharsAfterNewline = 0;
|
||||
} else if (bufOp.lines == 0) {
|
||||
} else if (bufOp.lines === 0) {
|
||||
// both bufOp and op are in-line
|
||||
bufOp.chars += op.chars;
|
||||
} else {
|
||||
|
@ -635,9 +633,9 @@ exports.textLinesMutator = function (lines) {
|
|||
}
|
||||
//print(inSplice+" / "+isCurLineInSplice()+" / "+curSplice[0]+" / "+curSplice[1]+" / "+lines.length);
|
||||
/*if (inSplice && (! isCurLineInSplice()) && (curSplice[0] + curSplice[1] < lines.length)) {
|
||||
print("BLAH");
|
||||
putCurLineInSplice();
|
||||
}*/
|
||||
print("BLAH");
|
||||
putCurLineInSplice();
|
||||
}*/
|
||||
// tests case foo in remove(), which isn't otherwise covered in current impl
|
||||
}
|
||||
//debugPrint("skip");
|
||||
|
@ -667,13 +665,13 @@ exports.textLinesMutator = function (lines) {
|
|||
enterSplice();
|
||||
}
|
||||
|
||||
function nextKLinesText(k) {
|
||||
var nextKLinesText = function nextKLinesText(k) {
|
||||
var m = curSplice[0] + curSplice[1];
|
||||
return lines_slice(m, m + k).join('');
|
||||
}
|
||||
};
|
||||
if (isCurLineInSplice()) {
|
||||
//print(curCol);
|
||||
if (curCol == 0) {
|
||||
if (curCol === 0) {
|
||||
removed = curSplice[curSplice.length - 1];
|
||||
// print("FOO"); // case foo
|
||||
curSplice.length--;
|
||||
|
@ -719,6 +717,7 @@ exports.textLinesMutator = function (lines) {
|
|||
if (!inSplice) {
|
||||
enterSplice();
|
||||
}
|
||||
var sline;
|
||||
if (L) {
|
||||
var newLines = exports.splitTextLines(text);
|
||||
if (isCurLineInSplice()) {
|
||||
|
@ -729,7 +728,7 @@ exports.textLinesMutator = function (lines) {
|
|||
//curLine += newLines.length;
|
||||
//}
|
||||
//else {
|
||||
var sline = curSplice.length - 1;
|
||||
sline = curSplice.length - 1;
|
||||
var theLine = curSplice[sline];
|
||||
var lineCol = curCol;
|
||||
curSplice[sline] = theLine.substring(0, lineCol) + newLines[0];
|
||||
|
@ -745,7 +744,7 @@ exports.textLinesMutator = function (lines) {
|
|||
curLine += newLines.length;
|
||||
}
|
||||
} else {
|
||||
var sline = putCurLineInSplice();
|
||||
sline = putCurLineInSplice();
|
||||
curSplice[sline] = curSplice[sline].substring(0, curCol) + text + curSplice[sline].substring(curCol);
|
||||
curCol += text.length;
|
||||
}
|
||||
|
@ -949,74 +948,66 @@ exports._slicerZipperFunc = function (attOp, csOp, opOut, pool) {
|
|||
} else {
|
||||
switch (csOp.opcode) {
|
||||
case '-':
|
||||
{
|
||||
if (csOp.chars <= attOp.chars) {
|
||||
// delete or delete part
|
||||
if (attOp.opcode == '=') {
|
||||
opOut.opcode = '-';
|
||||
opOut.chars = csOp.chars;
|
||||
opOut.lines = csOp.lines;
|
||||
opOut.attribs = '';
|
||||
}
|
||||
attOp.chars -= csOp.chars;
|
||||
attOp.lines -= csOp.lines;
|
||||
csOp.opcode = '';
|
||||
if (!attOp.chars) {
|
||||
attOp.opcode = '';
|
||||
}
|
||||
} else {
|
||||
// delete and keep going
|
||||
if (attOp.opcode == '=') {
|
||||
opOut.opcode = '-';
|
||||
opOut.chars = attOp.chars;
|
||||
opOut.lines = attOp.lines;
|
||||
opOut.attribs = '';
|
||||
}
|
||||
csOp.chars -= attOp.chars;
|
||||
csOp.lines -= attOp.lines;
|
||||
attOp.opcode = '';
|
||||
}
|
||||
break;
|
||||
}
|
||||
case '+':
|
||||
{
|
||||
// insert
|
||||
exports.copyOp(csOp, opOut);
|
||||
csOp.opcode = '';
|
||||
break;
|
||||
}
|
||||
case '=':
|
||||
{
|
||||
if (csOp.chars <= attOp.chars) {
|
||||
// keep or keep part
|
||||
opOut.opcode = attOp.opcode;
|
||||
if (csOp.chars <= attOp.chars) {
|
||||
// delete or delete part
|
||||
if (attOp.opcode == '=') {
|
||||
opOut.opcode = '-';
|
||||
opOut.chars = csOp.chars;
|
||||
opOut.lines = csOp.lines;
|
||||
opOut.attribs = exports.composeAttributes(attOp.attribs, csOp.attribs, attOp.opcode == '=', pool);
|
||||
csOp.opcode = '';
|
||||
attOp.chars -= csOp.chars;
|
||||
attOp.lines -= csOp.lines;
|
||||
if (!attOp.chars) {
|
||||
attOp.opcode = '';
|
||||
}
|
||||
} else {
|
||||
// keep and keep going
|
||||
opOut.opcode = attOp.opcode;
|
||||
opOut.attribs = '';
|
||||
}
|
||||
attOp.chars -= csOp.chars;
|
||||
attOp.lines -= csOp.lines;
|
||||
csOp.opcode = '';
|
||||
if (!attOp.chars) {
|
||||
attOp.opcode = '';
|
||||
}
|
||||
} else {
|
||||
// delete and keep going
|
||||
if (attOp.opcode == '=') {
|
||||
opOut.opcode = '-';
|
||||
opOut.chars = attOp.chars;
|
||||
opOut.lines = attOp.lines;
|
||||
opOut.attribs = exports.composeAttributes(attOp.attribs, csOp.attribs, attOp.opcode == '=', pool);
|
||||
attOp.opcode = '';
|
||||
csOp.chars -= attOp.chars;
|
||||
csOp.lines -= attOp.lines;
|
||||
opOut.attribs = '';
|
||||
}
|
||||
break;
|
||||
}
|
||||
case '':
|
||||
{
|
||||
exports.copyOp(attOp, opOut);
|
||||
csOp.chars -= attOp.chars;
|
||||
csOp.lines -= attOp.lines;
|
||||
attOp.opcode = '';
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case '+':
|
||||
// insert
|
||||
exports.copyOp(csOp, opOut);
|
||||
csOp.opcode = '';
|
||||
break;
|
||||
case '=':
|
||||
if (csOp.chars <= attOp.chars) {
|
||||
// keep or keep part
|
||||
opOut.opcode = attOp.opcode;
|
||||
opOut.chars = csOp.chars;
|
||||
opOut.lines = csOp.lines;
|
||||
opOut.attribs = exports.composeAttributes(attOp.attribs, csOp.attribs, attOp.opcode == '=', pool);
|
||||
csOp.opcode = '';
|
||||
attOp.chars -= csOp.chars;
|
||||
attOp.lines -= csOp.lines;
|
||||
if (!attOp.chars) {
|
||||
attOp.opcode = '';
|
||||
}
|
||||
} else {
|
||||
// keep and keep going
|
||||
opOut.opcode = attOp.opcode;
|
||||
opOut.chars = attOp.chars;
|
||||
opOut.lines = attOp.lines;
|
||||
opOut.attribs = exports.composeAttributes(attOp.attribs, csOp.attribs, attOp.opcode == '=', pool);
|
||||
attOp.opcode = '';
|
||||
csOp.chars -= attOp.chars;
|
||||
csOp.lines -= attOp.lines;
|
||||
}
|
||||
break;
|
||||
case '':
|
||||
exports.copyOp(attOp, opOut);
|
||||
attOp.opcode = '';
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -1470,7 +1461,7 @@ exports.appendATextToAssembler = function (atext, assem) {
|
|||
};
|
||||
|
||||
exports.prepareForWire = function (cs, pool) {
|
||||
var newPool = AttributePoolFactory.createAttributePool();;
|
||||
var newPool = AttributePoolFactory.createAttributePool();
|
||||
var newCs = exports.moveOpsToNewPool(cs, pool, newPool);
|
||||
return {
|
||||
translated: newCs,
|
||||
|
@ -1480,7 +1471,7 @@ exports.prepareForWire = function (cs, pool) {
|
|||
|
||||
exports.isIdentity = function (cs) {
|
||||
var unpacked = exports.unpack(cs);
|
||||
return unpacked.ops == "" && unpacked.oldLen == unpacked.newLen;
|
||||
return unpacked.ops === "" && unpacked.oldLen == unpacked.newLen;
|
||||
};
|
||||
|
||||
exports.opAttributeValue = function (op, key, pool) {
|
||||
|
|
|
@ -28,7 +28,7 @@ function getPadDokuWiki(pad, revNum, callback)
|
|||
|
||||
function (callback)
|
||||
{
|
||||
if (revNum != undefined)
|
||||
if (revNum)
|
||||
{
|
||||
pad.getInternalRevisionAText(revNum, function (err, revisionAtext)
|
||||
{
|
||||
|
@ -122,6 +122,8 @@ function getDokuWikiFromAtext(pad, atext)
|
|||
var iter = Changeset.opIterator(Changeset.subattribution(attribs, idx, idx + numChars));
|
||||
idx += numChars;
|
||||
|
||||
var i;
|
||||
|
||||
while (iter.hasNext())
|
||||
{
|
||||
var o = iter.next();
|
||||
|
@ -142,7 +144,7 @@ function getDokuWikiFromAtext(pad, atext)
|
|||
}
|
||||
}
|
||||
});
|
||||
for (var i = 0; i < propVals.length; i++)
|
||||
for (i = 0; i < propVals.length; i++)
|
||||
{
|
||||
if (propVals[i] === true)
|
||||
{
|
||||
|
@ -160,7 +162,7 @@ function getDokuWikiFromAtext(pad, atext)
|
|||
{
|
||||
// leaving bold (e.g.) also leaves italics, etc.
|
||||
var left = false;
|
||||
for (var i = 0; i < propVals.length; i++)
|
||||
for (i = 0; i < propVals.length; i++)
|
||||
{
|
||||
var v = propVals[i];
|
||||
if (!left)
|
||||
|
@ -179,7 +181,7 @@ function getDokuWikiFromAtext(pad, atext)
|
|||
}
|
||||
}
|
||||
|
||||
for (var i = propVals.length - 1; i >= 0; i--)
|
||||
for (i = propVals.length - 1; i >= 0; i--)
|
||||
{
|
||||
if (propVals[i] === LEAVE)
|
||||
{
|
||||
|
@ -191,7 +193,7 @@ function getDokuWikiFromAtext(pad, atext)
|
|||
emitCloseTag(i);
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < propVals.length; i++)
|
||||
for (i = 0; i < propVals.length; i++)
|
||||
{
|
||||
if (propVals[i] === ENTER || propVals[i] === STAY)
|
||||
{
|
||||
|
@ -210,7 +212,7 @@ function getDokuWikiFromAtext(pad, atext)
|
|||
|
||||
assem.append(_escapeDokuWiki(s));
|
||||
} // end iteration over spans in line
|
||||
for (var i = propVals.length - 1; i >= 0; i--)
|
||||
for (i = propVals.length - 1; i >= 0; i--)
|
||||
{
|
||||
if (propVals[i])
|
||||
{
|
||||
|
@ -310,7 +312,7 @@ exports.getPadDokuWikiDocument = function (padId, revNum, callback)
|
|||
|
||||
getPadDokuWiki(pad, revNum, callback);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function _escapeDokuWiki(s)
|
||||
{
|
||||
|
@ -321,7 +323,7 @@ function _escapeDokuWiki(s)
|
|||
// copied from ACE
|
||||
var _REGEX_WORDCHAR = /[\u0030-\u0039\u0041-\u005A\u0061-\u007A\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF\u0100-\u1FFF\u3040-\u9FFF\uF900-\uFDFF\uFE70-\uFEFE\uFF10-\uFF19\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFDC]/;
|
||||
var _REGEX_SPACE = /\s/;
|
||||
var _REGEX_URLCHAR = new RegExp('(' + /[-:@a-zA-Z0-9_.,~%+\/\\?=&#;()$]/.source + '|' + _REGEX_WORDCHAR.source + ')');
|
||||
var _REGEX_URLCHAR = new RegExp('(' + (/[\-:@a-zA-Z0-9_.,~%+\/\\?=&#;()$]/).source + '|' + _REGEX_WORDCHAR.source + ')');
|
||||
var _REGEX_URL = new RegExp(/(?:(?:https?|s?ftp|ftps|file|smb|afp|nfs|(x-)?man|gopher|txmt):\/\/|mailto:)/.source + _REGEX_URLCHAR.source + '*(?![:.,;])' + _REGEX_URLCHAR.source, 'g');
|
||||
|
||||
// returns null if no URLs, or [[startIndex1, url1], [startIndex2, url2], ...]
|
||||
|
|
|
@ -55,7 +55,7 @@ function getPadHTML(pad, revNum, callback)
|
|||
|
||||
function (callback)
|
||||
{
|
||||
if (revNum != undefined)
|
||||
if (revNum)
|
||||
{
|
||||
pad.getInternalRevisionAText(revNum, function (err, revisionAtext)
|
||||
{
|
||||
|
@ -171,6 +171,8 @@ function getHTMLFromAtext(pad, atext)
|
|||
var iter = Changeset.opIterator(Changeset.subattribution(attribs, idx, idx + numChars));
|
||||
idx += numChars;
|
||||
|
||||
var tags2close;
|
||||
|
||||
while (iter.hasNext())
|
||||
{
|
||||
var o = iter.next();
|
||||
|
@ -191,7 +193,9 @@ function getHTMLFromAtext(pad, atext)
|
|||
}
|
||||
}
|
||||
});
|
||||
for (var i = 0; i < propVals.length; i++)
|
||||
|
||||
var i;
|
||||
for (i = 0; i < propVals.length; i++)
|
||||
{
|
||||
if (propVals[i] === true)
|
||||
{
|
||||
|
@ -209,7 +213,7 @@ function getHTMLFromAtext(pad, atext)
|
|||
{
|
||||
// leaving bold (e.g.) also leaves italics, etc.
|
||||
var left = false;
|
||||
for (var i = 0; i < propVals.length; i++)
|
||||
for (i = 0; i < propVals.length; i++)
|
||||
{
|
||||
var v = propVals[i];
|
||||
if (!left)
|
||||
|
@ -228,9 +232,9 @@ function getHTMLFromAtext(pad, atext)
|
|||
}
|
||||
}
|
||||
|
||||
var tags2close = [];
|
||||
tags2close = [];
|
||||
|
||||
for (var i = propVals.length - 1; i >= 0; i--)
|
||||
for (i = propVals.length - 1; i >= 0; i--)
|
||||
{
|
||||
if (propVals[i] === LEAVE)
|
||||
{
|
||||
|
@ -247,7 +251,7 @@ function getHTMLFromAtext(pad, atext)
|
|||
|
||||
orderdCloseTags(tags2close);
|
||||
|
||||
for (var i = 0; i < propVals.length; i++)
|
||||
for (i = 0; i < propVals.length; i++)
|
||||
{
|
||||
if (propVals[i] === ENTER || propVals[i] === STAY)
|
||||
{
|
||||
|
@ -272,13 +276,13 @@ function getHTMLFromAtext(pad, atext)
|
|||
assem.append(_escapeHTML(s));
|
||||
} // end iteration over spans in line
|
||||
|
||||
var tags2close = [];
|
||||
for (var i = propVals.length - 1; i >= 0; i--)
|
||||
tags2close = [];
|
||||
for (var x = propVals.length - 1; x >= 0; x--)
|
||||
{
|
||||
if (propVals[i])
|
||||
if (propVals[x])
|
||||
{
|
||||
tags2close.push(i);
|
||||
propVals[i] = false;
|
||||
tags2close.push(x);
|
||||
propVals[x] = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -425,7 +429,7 @@ exports.getPadHTMLDocument = function (padId, revNum, noDocType, callback)
|
|||
callback(null, head + html + foot);
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function _escapeHTML(s)
|
||||
{
|
||||
|
@ -436,7 +440,7 @@ function _escapeHTML(s)
|
|||
re.MAP = {
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'>': '>'
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -447,7 +451,7 @@ function _escapeHTML(s)
|
|||
|
||||
return s.replace(/[^\x21-\x7E\s\t\n\r]/g, function(c)
|
||||
{
|
||||
return "&#" +c.charCodeAt(0) + ";"
|
||||
return "&#" +c.charCodeAt(0) + ";";
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -467,15 +471,19 @@ function _processSpaces(s)
|
|||
{
|
||||
parts.push(m);
|
||||
});
|
||||
|
||||
var i;
|
||||
var p;
|
||||
|
||||
if (doesWrap)
|
||||
{
|
||||
var endOfLine = true;
|
||||
var beforeSpace = false;
|
||||
// last space in a run is normal, others are nbsp,
|
||||
// end of line is nbsp
|
||||
for (var i = parts.length - 1; i >= 0; i--)
|
||||
for (i = parts.length - 1; i >= 0; i--)
|
||||
{
|
||||
var p = parts[i];
|
||||
p = parts[i];
|
||||
if (p == " ")
|
||||
{
|
||||
if (endOfLine || beforeSpace) parts[i] = ' ';
|
||||
|
@ -489,9 +497,9 @@ function _processSpaces(s)
|
|||
}
|
||||
}
|
||||
// beginning of line is nbsp
|
||||
for (var i = 0; i < parts.length; i++)
|
||||
for (i = 0; i < parts.length; i++)
|
||||
{
|
||||
var p = parts[i];
|
||||
p = parts[i];
|
||||
if (p == " ")
|
||||
{
|
||||
parts[i] = ' ';
|
||||
|
@ -505,9 +513,9 @@ function _processSpaces(s)
|
|||
}
|
||||
else
|
||||
{
|
||||
for (var i = 0; i < parts.length; i++)
|
||||
for (i = 0; i < parts.length; i++)
|
||||
{
|
||||
var p = parts[i];
|
||||
p = parts[i];
|
||||
if (p == " ")
|
||||
{
|
||||
parts[i] = ' ';
|
||||
|
@ -521,7 +529,7 @@ function _processSpaces(s)
|
|||
// copied from ACE
|
||||
var _REGEX_WORDCHAR = /[\u0030-\u0039\u0041-\u005A\u0061-\u007A\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF\u0100-\u1FFF\u3040-\u9FFF\uF900-\uFDFF\uFE70-\uFEFE\uFF10-\uFF19\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFDC]/;
|
||||
var _REGEX_SPACE = /\s/;
|
||||
var _REGEX_URLCHAR = new RegExp('(' + /[-:@a-zA-Z0-9_.,~%+\/\\?=&#;()$]/.source + '|' + _REGEX_WORDCHAR.source + ')');
|
||||
var _REGEX_URLCHAR = new RegExp('(' + (/[\-:@a-zA-Z0-9_.,~%+\/\\?=&#;()$]/).source + '|' + _REGEX_WORDCHAR.source + ')');
|
||||
var _REGEX_URL = new RegExp(/(?:(?:https?|s?ftp|ftps|file|smb|afp|nfs|(x-)?man|gopher|txmt):\/\/|mailto:)/.source + _REGEX_URLCHAR.source + '*(?![:.,;])' + _REGEX_URLCHAR.source, 'g');
|
||||
|
||||
// returns null if no URLs, or [[startIndex1, url1], [startIndex2, url2], ...]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* This Module manages all /minified/* requests. It controls the
|
||||
* This Module manages all /minified/\* requests. It controls the
|
||||
* minification && compression of Javascript and CSS.
|
||||
*/
|
||||
|
||||
|
@ -28,7 +28,7 @@ var jsp = require("uglify-js").parser;
|
|||
var pro = require("uglify-js").uglify;
|
||||
var path = require('path');
|
||||
var Buffer = require('buffer').Buffer;
|
||||
var gzip = require('gzip');
|
||||
var zlib = require('zlib');
|
||||
var server = require('../server');
|
||||
var os = require('os');
|
||||
|
||||
|
@ -59,10 +59,12 @@ exports.minifyJS = function(req, res, jsFilename)
|
|||
throw new Error("there is no profile for creating " + name);
|
||||
}
|
||||
|
||||
var fileValues;
|
||||
|
||||
//minifying is enabled
|
||||
if(settings.minify)
|
||||
{
|
||||
var fileValues = {};
|
||||
fileValues = {};
|
||||
var embeds = {};
|
||||
var latestModification = 0;
|
||||
|
||||
|
@ -233,23 +235,12 @@ exports.minifyJS = function(req, res, jsFilename)
|
|||
//write the results compressed in a file
|
||||
function(callback)
|
||||
{
|
||||
//spawn a gzip process if we're on a unix system
|
||||
if(os.type().indexOf("Windows") == -1)
|
||||
{
|
||||
gzip(result, 9, function(err, compressedResult){
|
||||
//weird gzip bug that returns 0 instead of null if everything is ok
|
||||
err = err === 0 ? null : err;
|
||||
zlib.gzip(result, function(err, compressedResult){
|
||||
|
||||
if(ERR(err, callback)) return;
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
fs.writeFile("../var/minified_" + jsFilename + ".gz", compressedResult, callback);
|
||||
});
|
||||
}
|
||||
//skip this step on windows
|
||||
else
|
||||
{
|
||||
callback();
|
||||
}
|
||||
fs.writeFile("../var/minified_" + jsFilename + ".gz", compressedResult, callback);
|
||||
});
|
||||
}
|
||||
],callback);
|
||||
}
|
||||
|
@ -275,12 +266,12 @@ exports.minifyJS = function(req, res, jsFilename)
|
|||
}
|
||||
|
||||
res.sendfile(pathStr, { maxAge: server.maxAge });
|
||||
})
|
||||
});
|
||||
}
|
||||
//minifying is disabled, so put the files together in one file
|
||||
else
|
||||
{
|
||||
var fileValues = {};
|
||||
fileValues = {};
|
||||
|
||||
//read all js files
|
||||
async.forEach(jsFiles, function (item, callback)
|
||||
|
@ -307,7 +298,7 @@ exports.minifyJS = function(req, res, jsFilename)
|
|||
res.end();
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function compressJS(values)
|
||||
{
|
||||
|
|
7
node/utils/cleantext.js
Normal file
7
node/utils/cleantext.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
/**
|
||||
* Copied from the Etherpad source code. It converts Windows line breaks to Unix line breaks and convert Tabs to spaces
|
||||
* @param txt
|
||||
*/
|
||||
exports.cleanText = function (txt) {
|
||||
return txt.replace(/\r\n/g,'\n').replace(/\r/g,'\n').replace(/\t/g, ' ').replace(/\xa0/g, ' ');
|
||||
};
|
|
@ -173,7 +173,7 @@ function makeContentCollector(collectStyles, browser, apool, domInterface, class
|
|||
function _isEmpty(node, state)
|
||||
{
|
||||
// consider clean blank lines pasted in IE to be empty
|
||||
if (dom.nodeNumChildren(node) == 0) return true;
|
||||
if (dom.nodeNumChildren(node) === 0) return true;
|
||||
if (dom.nodeNumChildren(node) == 1 && getAssoc(node, "shouldBeEmpty") && dom.optNodeInnerHTML(node) == " " && !getAssoc(node, "unpasted"))
|
||||
{
|
||||
if (state)
|
||||
|
@ -191,7 +191,7 @@ function makeContentCollector(collectStyles, browser, apool, domInterface, class
|
|||
{
|
||||
var ln = lines.length() - 1;
|
||||
var chr = lines.textOfLine(ln).length;
|
||||
if (chr == 0 && state.listType && state.listType != 'none')
|
||||
if (chr === 0 && state.listType && state.listType != 'none')
|
||||
{
|
||||
chr += 1; // listMarker
|
||||
}
|
||||
|
@ -218,11 +218,11 @@ function makeContentCollector(collectStyles, browser, apool, domInterface, class
|
|||
cc.incrementFlag = function(state, flagName)
|
||||
{
|
||||
state.flags[flagName] = (state.flags[flagName] || 0) + 1;
|
||||
}
|
||||
};
|
||||
cc.decrementFlag = function(state, flagName)
|
||||
{
|
||||
state.flags[flagName]--;
|
||||
}
|
||||
};
|
||||
cc.incrementAttrib = function(state, attribName)
|
||||
{
|
||||
if (!state.attribs[attribName])
|
||||
|
@ -234,12 +234,12 @@ function makeContentCollector(collectStyles, browser, apool, domInterface, class
|
|||
state.attribs[attribName]++;
|
||||
}
|
||||
_recalcAttribString(state);
|
||||
}
|
||||
};
|
||||
cc.decrementAttrib = function(state, attribName)
|
||||
{
|
||||
state.attribs[attribName]--;
|
||||
_recalcAttribString(state);
|
||||
}
|
||||
};
|
||||
|
||||
function _enterList(state, listType)
|
||||
{
|
||||
|
@ -315,14 +315,14 @@ function makeContentCollector(collectStyles, browser, apool, domInterface, class
|
|||
{
|
||||
if (state)
|
||||
{
|
||||
var atBeginningOfLine = lines.textOfLine(lines.length() - 1).length == 0;
|
||||
var atBeginningOfLine = lines.textOfLine(lines.length() - 1).length === 0;
|
||||
if (atBeginningOfLine && state.listType && state.listType != 'none')
|
||||
{
|
||||
_produceListMarker(state);
|
||||
}
|
||||
}
|
||||
lines.startNew();
|
||||
}
|
||||
};
|
||||
cc.notifySelection = function(sel)
|
||||
{
|
||||
if (sel)
|
||||
|
@ -358,12 +358,15 @@ function makeContentCollector(collectStyles, browser, apool, domInterface, class
|
|||
if (isBlock) _ensureColumnZero(state);
|
||||
var startLine = lines.length() - 1;
|
||||
_reachBlockPoint(node, 0, state);
|
||||
|
||||
var i;
|
||||
|
||||
if (dom.isNodeText(node))
|
||||
{
|
||||
var txt = dom.nodeValue(node);
|
||||
var rest = '';
|
||||
var x = 0; // offset into original text
|
||||
if (txt.length == 0)
|
||||
if (txt.length === 0)
|
||||
{
|
||||
if (startPoint && node == startPoint.node)
|
||||
{
|
||||
|
@ -404,7 +407,7 @@ function makeContentCollector(collectStyles, browser, apool, domInterface, class
|
|||
// removing "\n" from pasted HTML will collapse words together.
|
||||
txt2 = "";
|
||||
}
|
||||
var atBeginningOfLine = lines.textOfLine(lines.length() - 1).length == 0;
|
||||
var atBeginningOfLine = lines.textOfLine(lines.length() - 1).length === 0;
|
||||
if (atBeginningOfLine)
|
||||
{
|
||||
// newlines in the source mustn't become spaces at beginning of line box
|
||||
|
@ -425,6 +428,8 @@ function makeContentCollector(collectStyles, browser, apool, domInterface, class
|
|||
}
|
||||
else
|
||||
{
|
||||
var c;
|
||||
|
||||
var tname = (dom.nodeTagName(node) || "").toLowerCase();
|
||||
if (tname == "br")
|
||||
{
|
||||
|
@ -472,9 +477,9 @@ function makeContentCollector(collectStyles, browser, apool, domInterface, class
|
|||
{
|
||||
cc.doAttrib(state, "strikethrough");
|
||||
}
|
||||
var type;
|
||||
if (tname == "ul")
|
||||
{
|
||||
var type;
|
||||
var rr = cls && /(?:^| )list-(bullet[12345678])\b/.exec(cls);
|
||||
type = rr && rr[1] || "bullet" + String(Math.min(_MAX_LIST_LEVEL, (state.listNesting || 0) + 1));
|
||||
oldListTypeOrNull = (_enterList(state, type) || 'none');
|
||||
|
@ -488,9 +493,9 @@ function makeContentCollector(collectStyles, browser, apool, domInterface, class
|
|||
var classes = cls.match(/\S+/g);
|
||||
if (classes && classes.length > 0)
|
||||
{
|
||||
for (var i = 0; i < classes.length; i++)
|
||||
for (i = 0; i < classes.length; i++)
|
||||
{
|
||||
var c = classes[i];
|
||||
c = classes[i];
|
||||
var a = className2Author(c);
|
||||
if (a)
|
||||
{
|
||||
|
@ -503,9 +508,9 @@ function makeContentCollector(collectStyles, browser, apool, domInterface, class
|
|||
}
|
||||
|
||||
var nc = dom.nodeNumChildren(node);
|
||||
for (var i = 0; i < nc; i++)
|
||||
for (i = 0; i < nc; i++)
|
||||
{
|
||||
var c = dom.nodeChild(node, i);
|
||||
c = dom.nodeChild(node, i);
|
||||
cc.collectContent(c, state);
|
||||
}
|
||||
|
||||
|
@ -523,7 +528,7 @@ function makeContentCollector(collectStyles, browser, apool, domInterface, class
|
|||
if (isPre) cc.decrementFlag(state, 'preMode');
|
||||
if (state.localAttribs)
|
||||
{
|
||||
for (var i = 0; i < state.localAttribs.length; i++)
|
||||
for (i = 0; i < state.localAttribs.length; i++)
|
||||
{
|
||||
cc.decrementAttrib(state, state.localAttribs[i]);
|
||||
}
|
||||
|
@ -612,6 +617,30 @@ function makeContentCollector(collectStyles, browser, apool, domInterface, class
|
|||
var buffer = 10; // chars allowed over before wrapping
|
||||
var linesWrapped = 0;
|
||||
var numLinesAfter = 0;
|
||||
|
||||
var fixLineNumber = function fixLineNumber(lineChar)
|
||||
{
|
||||
if (lineChar[0] < 0) return;
|
||||
var n = lineChar[0];
|
||||
var c = lineChar[1];
|
||||
if (n > i)
|
||||
{
|
||||
n += (newStrings.length - 1);
|
||||
}
|
||||
else if (n == i)
|
||||
{
|
||||
var a = 0;
|
||||
while (c > newStrings[a].length)
|
||||
{
|
||||
c -= newStrings[a].length;
|
||||
a++;
|
||||
}
|
||||
n += a;
|
||||
}
|
||||
lineChar[0] = n;
|
||||
lineChar[1] = c;
|
||||
};
|
||||
|
||||
for (var i = lineStrings.length - 1; i >= 0; i--)
|
||||
{
|
||||
var oldString = lineStrings[i];
|
||||
|
@ -620,6 +649,8 @@ function makeContentCollector(collectStyles, browser, apool, domInterface, class
|
|||
{
|
||||
var newStrings = [];
|
||||
var newAttribStrings = [];
|
||||
|
||||
|
||||
while (oldString.length > lineLimit)
|
||||
{
|
||||
//var semiloc = oldString.lastIndexOf(';', lineLimit-1);
|
||||
|
@ -636,28 +667,6 @@ function makeContentCollector(collectStyles, browser, apool, domInterface, class
|
|||
newAttribStrings.push(oldAttribString);
|
||||
}
|
||||
|
||||
function fixLineNumber(lineChar)
|
||||
{
|
||||
if (lineChar[0] < 0) return;
|
||||
var n = lineChar[0];
|
||||
var c = lineChar[1];
|
||||
if (n > i)
|
||||
{
|
||||
n += (newStrings.length - 1);
|
||||
}
|
||||
else if (n == i)
|
||||
{
|
||||
var a = 0;
|
||||
while (c > newStrings[a].length)
|
||||
{
|
||||
c -= newStrings[a].length;
|
||||
a++;
|
||||
}
|
||||
n += a;
|
||||
}
|
||||
lineChar[0] = n;
|
||||
lineChar[1] = c;
|
||||
}
|
||||
fixLineNumber(ss);
|
||||
fixLineNumber(se);
|
||||
linesWrapped++;
|
||||
|
@ -684,7 +693,7 @@ function makeContentCollector(collectStyles, browser, apool, domInterface, class
|
|||
lines: lineStrings,
|
||||
lineAttribs: lineAttribs
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
return cc;
|
||||
}
|
||||
|
|
|
@ -13,15 +13,16 @@
|
|||
"socket.io" : "0.8.7",
|
||||
"ueberDB" : "0.1.3",
|
||||
"async" : "0.1.15",
|
||||
"joose" : "3.50.0",
|
||||
"express" : "2.5.0",
|
||||
"clean-css" : "0.2.4",
|
||||
"uglify-js" : "1.1.1",
|
||||
"gzip" : "0.1.0",
|
||||
"formidable" : "1.0.7",
|
||||
"log4js" : "0.3.9",
|
||||
"log4js" : "0.4.1",
|
||||
"jsdom-nocontextifiy" : "0.2.10",
|
||||
"async-stacktrace" : "0.0.2"
|
||||
},
|
||||
"devDependencies" : {
|
||||
"jshint" : "0.5.5"
|
||||
},
|
||||
"version" : "1.0.0"
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue