New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

ep_comments_page

Package Overview
Dependencies
Maintainers
6
Versions
142
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ep_comments_page - npm Package Compare versions

Comparing version 0.1.7 to 0.1.8

LICENSE

360

commentManager.js

@@ -0,231 +1,143 @@

/* global exports, require */
var _ = require('ep_etherpad-lite/static/js/underscore');
var db = require('ep_etherpad-lite/node/db/DB').db;
var ERR = require("ep_etherpad-lite/node_modules/async-stacktrace");
var db = require('ep_etherpad-lite/node/db/DB');
var randomString = require('ep_etherpad-lite/static/js/pad_utils').randomString;
var readOnlyManager = require("ep_etherpad-lite/node/db/ReadOnlyManager.js");
var shared = require('./static/js/shared');
exports.getComments = async function (padId, callback)
{
// We need to change readOnly PadIds to Normal PadIds
var isReadOnly = padId.indexOf("r.") === 0;
if(isReadOnly){
padId = await readOnlyManager.getPadId(padId);
};
exports.getComments = async (padId) => {
// Not sure if we will encouter race conditions here.. Be careful.
//get the globalComments
db.get("comments:" + padId, function(err, comments)
{
if(ERR(err, callback)) return;
//comment does not exists
if(comments == null) comments = {};
callback(null, { comments: comments });
});
// get the globalComments
let comments = await db.get('comments:' + padId);
if (comments == null) comments = {};
return {comments};
};
exports.deleteComment = function (padId, commentId, callback)
{
db.get('comments:' + padId, function(err, comments)
{
if(ERR(err, callback)) return;
// the entry doesn't exist so far, let's create it
if(comments == null) comments = {};
delete comments[commentId];
db.set("comments:" + padId, comments);
callback(padId, commentId);
});
exports.deleteComment = async (padId, commentId) => {
let comments = await db.get('comments:' + padId);
// the entry doesn't exist so far, let's create it
if (comments == null) comments = {};
delete comments[commentId];
await db.set('comments:' + padId, comments);
};
exports.deleteComments = function (padId, callback)
{
db.remove('comments:' + padId, function(err)
{
if(ERR(err, callback)) return;
callback(null);
});
exports.deleteComments = async (padId) => {
await db.remove('comments:' + padId);
};
exports.addComment = function(padId, data, callback)
{
exports.bulkAddComments(padId, [data], function(err, commentIds, comments) {
if(ERR(err, callback)) return;
if(commentIds && commentIds.length > 0 && comments && comments.length > 0) {
callback(null, commentIds[0], comments[0]);
}
});
exports.addComment = async (padId, data) => {
const [commentIds, comments] = await exports.bulkAddComments(padId, [data]);
return [commentIds[0], comments[0]];
};
exports.bulkAddComments = async function(padId, data, callback)
{
// We need to change readOnly PadIds to Normal PadIds
var isReadOnly = padId.indexOf("r.") === 0;
if(isReadOnly){
padId = await readOnlyManager.getPadId(padId);
};
exports.bulkAddComments = async (padId, data) => {
// get the entry
let comments = await db.get('comments:' + padId);
//get the entry
db.get("comments:" + padId, function(err, comments) {
if(ERR(err, callback)) return;
// the entry doesn't exist so far, let's create it
if (comments == null) comments = {};
// the entry doesn't exist so far, let's create it
if(comments == null) comments = {};
const newComments = [];
const commentIds = data.map((commentData) => {
// if the comment was copied it already has a commentID, so we don't need create one
const commentId = commentData.commentId || shared.generateCommentId();
var newComments = [];
var commentIds = _.map(data, function(commentData) {
//if the comment was copied it already has a commentID, so we don't need create one
var commentId = commentData.commentId || shared.generateCommentId();
const comment = {
author: commentData.author || 'empty',
name: commentData.name,
text: commentData.text,
changeTo: commentData.changeTo,
changeFrom: commentData.changeFrom,
timestamp: parseInt(commentData.timestamp) || new Date().getTime(),
};
// add the entry for this pad
comments[commentId] = comment;
var comment = {
"author": commentData.author || "empty",
"name": commentData.name,
"text": commentData.text,
"changeTo": commentData.changeTo,
"changeFrom": commentData.changeFrom,
"timestamp": parseInt(commentData.timestamp) || new Date().getTime()
};
//add the entry for this pad
comments[commentId] = comment;
newComments.push(comment);
return commentId;
});
newComments.push(comment);
return commentId;
});
// save the new element back
await db.set('comments:' + padId, comments);
//save the new element back
db.set("comments:" + padId, comments);
callback(null, commentIds, newComments);
});
return [commentIds, newComments];
};
exports.copyComments = function(originalPadId, newPadID, callback)
{
//get the comments of original pad
db.get('comments:' + originalPadId, function(err, originalComments) {
if(ERR(err, callback)) return;
exports.copyComments = async (originalPadId, newPadID) => {
// get the comments of original pad
const originalComments = await db.get('comments:' + originalPadId);
// make sure we have different copies of the comment between pads
const copiedComments = _.mapObject(originalComments, (thisComment) => _.clone(thisComment));
var copiedComments = _.mapObject(originalComments, function(thisComment, thisCommentId) {
// make sure we have different copies of the comment between pads
return _.clone(thisComment);
});
//save the comments on new pad
db.set('comments:' + newPadID, copiedComments);
callback(null);
});
// save the comments on new pad
await db.set('comments:' + newPadID, copiedComments);
};
exports.getCommentReplies = async function (padId, callback){
// We need to change readOnly PadIds to Normal PadIds
var isReadOnly = padId.indexOf("r.") === 0;
if(isReadOnly){
padId = await readOnlyManager.getPadId(padId);
};
//get the globalComments replies
db.get("comment-replies:" + padId, function(err, replies)
{
if(ERR(err, callback)) return;
//comment does not exists
if(replies == null) replies = {};
callback(null, { replies: replies });
});
exports.getCommentReplies = async (padId) => {
// get the globalComments replies
let replies = await db.get('comment-replies:' + padId);
// comment does not exist
if (replies == null) replies = {};
return {replies};
};
exports.deleteCommentReplies = function (padId, callback){
db.remove('comment-replies:' + padId, function(err)
{
if(ERR(err, callback)) return;
callback(null);
});
exports.deleteCommentReplies = async (padId) => {
await db.remove('comment-replies:' + padId);
};
exports.addCommentReply = function(padId, data, callback){
exports.bulkAddCommentReplies(padId, [data], function(err, replyIds, replies) {
if(ERR(err, callback)) return;
if(replyIds && replyIds.length > 0 && replies && replies.length > 0) {
callback(null, replyIds[0], replies[0]);
}
});
exports.addCommentReply = async (padId, data) => {
const [replyIds, replies] = await exports.bulkAddCommentReplies(padId, [data]);
return [replyIds[0], replies[0]];
};
exports.bulkAddCommentReplies = async function(padId, data, callback){
// We need to change readOnly PadIds to Normal PadIds
var isReadOnly = padId.indexOf("r.") === 0;
if(isReadOnly){
padId = await readOnlyManager.getPadId(padId);
};
exports.bulkAddCommentReplies = async (padId, data) => {
// get the entry
let replies = await db.get('comment-replies:' + padId);
// the entry doesn't exist so far, let's create it
if (replies == null) replies = {};
//get the entry
db.get("comment-replies:" + padId, function(err, replies){
if(ERR(err, callback)) return;
const newReplies = [];
const replyIds = _.map(data, (replyData) => {
// create the new reply id
const replyId = "c-reply-" + randomString(16);
// the entry doesn't exist so far, let's create it
if(replies == null) replies = {};
const metadata = replyData.comment || {};
var newReplies = [];
var replyIds = _.map(data, function(replyData) {
//create the new reply id
var replyId = "c-reply-" + randomString(16);
const reply = {
commentId: replyData.commentId,
text: replyData.reply || replyData.text,
changeTo: replyData.changeTo || null,
changeFrom: replyData.changeFrom || null,
author: metadata.author || 'empty',
name: metadata.name || replyData.name,
timestamp: parseInt(replyData.timestamp) || new Date().getTime()
};
metadata = replyData.comment || {};
// add the entry for this pad
replies[replyId] = reply;
var reply = {
"commentId" : replyData.commentId,
"text" : replyData.reply || replyData.text,
"changeTo" : replyData.changeTo || null,
"changeFrom" : replyData.changeFrom || null,
"author" : metadata.author || "empty",
"name" : metadata.name || replyData.name,
"timestamp" : parseInt(replyData.timestamp) || new Date().getTime()
};
newReplies.push(reply);
return replyId;
});
//add the entry for this pad
replies[replyId] = reply;
// save the new element back
await db.set('comment-replies:' + padId, replies);
newReplies.push(reply);
return replyId;
});
//save the new element back
db.set("comment-replies:" + padId, replies);
callback(null, replyIds, newReplies);
});
return [replyIds, newReplies];
};
exports.copyCommentReplies = function(originalPadId, newPadID, callback){
//get the replies of original pad
db.get('comment-replies:' + originalPadId, function(err, originalReplies){
if(ERR(err, callback)) return;
exports.copyCommentReplies = async (originalPadId, newPadID) => {
// get the replies of original pad
const originalReplies = await db.get('comment-replies:' + originalPadId);
// make sure we have different copies of the reply between pads
const copiedReplies = _.mapObject(originalReplies, (thisReply) => _.clone(thisReply));
var copiedReplies = _.mapObject(originalReplies, function(thisReply, thisReplyId) {
// make sure we have different copies of the reply between pads
return _.clone(thisReply);
});
//save the comment replies on new pad
db.set('comment-replies:' + newPadID, copiedReplies);
callback(null);
});
// save the comment replies on new pad
await db.set('comment-replies:' + newPadID, copiedReplies);
};
exports.changeAcceptedState = async function(padId, commentId, state, callback){
exports.changeAcceptedState = async (padId, commentId, state) => {
// Given a comment we update that comment to say the change was accepted or reverted
// We need to change readOnly PadIds to Normal PadIds
var isReadOnly = padId.indexOf("r.") === 0;
if(isReadOnly){
padId = await readOnlyManager.getPadId(padId);
};
// If we're dealing with comment replies we need to a different query

@@ -237,59 +149,43 @@ var prefix = "comments:";

//get the entry
db.get(prefix + padId, function(err, comments){
// get the entry
const comments = await db.get(prefix + padId);
if(ERR(err, callback)) return;
// add the entry for this pad
const comment = comments[commentId];
//add the entry for this pad
var comment = comments[commentId];
if (state) {
comment.changeAccepted = true;
comment.changeReverted = false;
} else {
comment.changeAccepted = false;
comment.changeReverted = true;
}
if(state){
comment.changeAccepted = true;
comment.changeReverted = false;
}else{
comment.changeAccepted = false;
comment.changeReverted = true;
}
comments[commentId] = comment;
comments[commentId] = comment;
//save the new element back
await db.set(prefix + padId, comments);
};
//save the new element back
db.set(prefix + padId, comments);
exports.changeCommentText = async (padId, commentId, commentText) => {
if (commentText.length <= 0) return true;
callback(null, commentId, comment);
});
}
// Given a comment we update the comment text
exports.changeCommentText = async function(padId, commentId, commentText, callback){
var commentTextIsNotEmpty = commentText.length > 0;
if(commentTextIsNotEmpty){
// Given a comment we update the comment text
// We need to change readOnly PadIds to Normal PadIds
var isReadOnly = padId.indexOf("r.") === 0;
if(isReadOnly){
padId = await readOnlyManager.getPadId(padId);
};
// If we're dealing with comment replies we need to a different query
var prefix = 'comments:';
if (commentId.substring(0,7) === 'c-reply') {
prefix = 'comment-replies:';
}
// If we're dealing with comment replies we need to a different query
var prefix = "comments:";
if(commentId.substring(0,7) === "c-reply"){
prefix = "comment-replies:";
}
// get the entry
const comments = await db.get(prefix + padId);
// update the comment text
comments[commentId].text = commentText;
//get the entry
db.get(prefix + padId, function(err, comments){
if(ERR(err, callback)) return;
// save the comment updated back
await db.set(prefix + padId, comments);
//update the comment text
comments[commentId].text = commentText;
//save the comment updated back
db.set(prefix + padId, comments);
callback(null);
});
}else{// don't save comment text blank
callback(true);
}
}
return null;
};

@@ -0,173 +1,123 @@

/* global exports, require */
var eejs = require('ep_etherpad-lite/node/eejs/');
var settings = require('ep_etherpad-lite/node/utils/Settings');
var formidable = require('ep_etherpad-lite/node_modules/formidable');
var clientIO = require('ep_etherpad-lite/node_modules/socket.io-client');
var commentManager = require('./commentManager');
var comments = require('./comments');
var apiUtils = require('./apiUtils');
var _ = require('ep_etherpad-lite/static/js/underscore');
const readOnlyManager = require('ep_etherpad-lite/node/db/ReadOnlyManager.js');
exports.padRemove = function(hook_name, context, callback) {
commentManager.deleteCommentReplies(context.padID, function() {
commentManager.deleteComments(context.padID, callback);
});
}
exports.padCopy = function(hook_name, context, callback) {
commentManager.copyComments(context.originalPad.id, context.destinationID, function() {
commentManager.copyCommentReplies(context.originalPad.id, context.destinationID, callback);
});
}
let io;
exports.padRemove = async (hookName, context) => {
await Promise.all([
commentManager.deleteCommentReplies(context.padID),
commentManager.deleteComments(context.padID),
]);
};
exports.padCopy = async (hookName, context) => {
await Promise.all([
commentManager.copyComments(context.originalPad.id, context.destinationID),
commentManager.copyCommentReplies(context.originalPad.id, context.destinationID),
]);
};
exports.handleMessageSecurity = function(hook_name, context, callback){
if(context.message && context.message.data && context.message.data.apool){
var apool = context.message.data.apool;
if(apool.numToAttrib && apool.numToAttrib[0] && apool.numToAttrib[0][0]){
if(apool.numToAttrib[0][0] === "comment"){
// Comment change, allow it to override readonly security model!!
callback(true);
}else{
callback();
}
}else{
callback();
}
}else{
callback();
const {message: {data: {apool} = {}} = {}} = context;
if (apool && apool[0] && apool[0][0] === 'comment') {
// Comment change, allow it to override readonly security model!!
return callback(true);
}
return callback();
};
exports.socketio = function (hook_name, args, cb){
var app = args.app;
var io = args.io;
var pushComment;
var padComment = io;
io = args.io.of('/comment');
io.on('connection', (socket) => {
var commentSocket = io
.of('/comment')
.on('connection', function (socket) {
// Join the rooms
socket.on('getComments', function (data, callback) {
var padId = data.padId;
socket.on('getComments', async (data, respond) => {
const {padId} = await readOnlyManager.getIds(data.padId);
// Put read-only and read-write users in the same socket.io "room" so that they can see each
// other's updates.
socket.join(padId);
commentManager.getComments(padId, function (err, comments){
callback(comments);
});
respond(await commentManager.getComments(padId));
});
socket.on('getCommentReplies', function (data, callback) {
var padId = data.padId;
commentManager.getCommentReplies(padId, function (err, replies){
callback(replies);
});
socket.on('getCommentReplies', async (data, respond) => {
const {padId} = await readOnlyManager.getIds(data.padId);
respond(await commentManager.getCommentReplies(padId));
});
// On add events
socket.on('addComment', function (data, callback) {
var padId = data.padId;
socket.on('addComment', async (data, respond) => {
const {padId} = await readOnlyManager.getIds(data.padId);
var content = data.comment;
commentManager.addComment(padId, content, function (err, commentId, comment){
const [commentId, comment] = await commentManager.addComment(padId, content);
if (commentId != null && comment != null) {
socket.broadcast.to(padId).emit('pushAddComment', commentId, comment);
callback(commentId, comment);
});
respond(commentId, comment);
}
});
socket.on('deleteComment', function(data, callback) {
socket.on('deleteComment', async (data, respond) => {
const {padId} = await readOnlyManager.getIds(data.padId);
// delete the comment on the database
commentManager.deleteComment(data.padId, data.commentId, function (){
// Broadcast to all other users that this comment was deleted
socket.broadcast.to(data.padId).emit('commentDeleted', data.commentId);
});
await commentManager.deleteComment(padId, data.commentId);
// Broadcast to all other users that this comment was deleted
socket.broadcast.to(padId).emit('commentDeleted', data.commentId);
});
socket.on('revertChange', function(data, callback) {
socket.on('revertChange', async (data, respond) => {
const {padId} = await readOnlyManager.getIds(data.padId);
// Broadcast to all other users that this change was accepted.
// Note that commentId here can either be the commentId or replyId..
var padId = data.padId;
commentManager.changeAcceptedState(padId, data.commentId, false, function(){
socket.broadcast.to(padId).emit('changeReverted', data.commentId);
});
await commentManager.changeAcceptedState(padId, data.commentId, false);
socket.broadcast.to(padId).emit('changeReverted', data.commentId);
});
socket.on('acceptChange', function(data, callback) {
socket.on('acceptChange', async (data, respond) => {
const {padId} = await readOnlyManager.getIds(data.padId);
// Broadcast to all other users that this change was accepted.
// Note that commentId here can either be the commentId or replyId..
var padId = data.padId;
commentManager.changeAcceptedState(padId, data.commentId, true, function(){
socket.broadcast.to(padId).emit('changeAccepted', data.commentId);
});
await commentManager.changeAcceptedState(padId, data.commentId, true);
socket.broadcast.to(padId).emit('changeAccepted', data.commentId);
});
socket.on('bulkAddComment', function (padId, data, callback) {
commentManager.bulkAddComments(padId, data, function(error, commentsId, comments){
socket.broadcast.to(padId).emit('pushAddCommentInBulk');
var commentWithCommentId = _.object(commentsId, comments); // {c-123:data, c-124:data}
callback(commentWithCommentId)
});
socket.on('bulkAddComment', async (padId, data, respond) => {
padId = (await readOnlyManager.getIds(padId)).padId;
const [commentIds, comments] = await commentManager.bulkAddComments(padId, data);
socket.broadcast.to(padId).emit('pushAddCommentInBulk');
respond(_.object(commentIds, comments)); // {c-123:data, c-124:data}
});
socket.on('bulkAddCommentReplies', function(padId, data, callback){
commentManager.bulkAddCommentReplies(padId, data, function (err, repliesId, replies){
socket.broadcast.to(padId).emit('pushAddCommentReply', repliesId, replies);
var repliesWithReplyId = _.zip(repliesId, replies);
callback(repliesWithReplyId);
});
socket.on('bulkAddCommentReplies', async (padId, data, respond) => {
padId = (await readOnlyManager.getIds(padId)).padId;
const [repliesId, replies] = await commentManager.bulkAddCommentReplies(padId, data);
socket.broadcast.to(padId).emit('pushAddCommentReply', repliesId, replies);
respond(_.zip(repliesId, replies));
});
socket.on('updateCommentText', function(data, callback) {
socket.on('updateCommentText', async (data, respond) => {
const {padId} = await readOnlyManager.getIds(data.padId);
// Broadcast to all other users that the comment text was changed.
// Note that commentId here can either be the commentId or replyId..
var padId = data.padId;
var commentId = data.commentId;
var commentText = data.commentText;
commentManager.changeCommentText(padId, commentId, commentText, function(err) {
if(!err){
socket.broadcast.to(padId).emit('textCommentUpdated', commentId, commentText);
}
callback(err);
});
const failed = await commentManager.changeCommentText(padId, commentId, commentText);
if (!failed) socket.broadcast.to(padId).emit('textCommentUpdated', commentId, commentText);
respond(failed);
});
socket.on('addCommentReply', function (data, callback) {
var padId = data.padId;
var content = data.reply;
var changeTo = data.changeTo || null;
var changeFrom = data.changeFrom || null;
var changeAccepted = data.changeAccepted || null;
var changeReverted = data.changeReverted || null;
var commentId = data.commentId;
commentManager.addCommentReply(padId, data, function (err, replyId, reply, changeTo, changeFrom, changeAccepted, changeReverted){
reply.replyId = replyId;
socket.broadcast.to(padId).emit('pushAddCommentReply', replyId, reply, changeTo, changeFrom, changeAccepted, changeReverted);
callback(replyId, reply);
});
socket.on('addCommentReply', async (data, respond) => {
const {padId} = await readOnlyManager.getIds(data.padId);
const [replyId, reply] = await commentManager.addCommentReply(padId, data);
reply.replyId = replyId;
socket.broadcast.to(padId).emit('pushAddCommentReply', replyId, reply);
respond(replyId, reply);
});
// comment added via API
socket.on('apiAddComments', function (data) {
var padId = data.padId;
var commentIds = data.commentIds;
var comments = data.comments;
for (var i = 0, len = commentIds.length; i < len; i++) {
socket.broadcast.to(padId).emit('pushAddComment', commentIds[i], comments[i]);
}
});
// comment reply added via API
socket.on('apiAddCommentReplies', function (data) {
var padId = data.padId;
var replyIds = data.replyIds;
var replies = data.replies;
for (var i = 0, len = replyIds.length; i < len; i++) {
var reply = replies[i];
var replyId = replyIds[i];
reply.replyId = replyId;
socket.broadcast.to(padId).emit('pushAddCommentReply', replyId, reply);
}
});
});
return cb();
};

@@ -191,4 +141,4 @@

exports.eejsBlock_scripts = function (hook_name, args, cb) {
args.content = args.content + eejs.require("ep_comments_page/templates/comments.html", {}, module);
args.content = args.content + eejs.require("ep_comments_page/templates/commentIcons.html", {}, module);
args.content = args.content + eejs.require("ep_comments_page/templates/comments.html");
args.content = args.content + eejs.require("ep_comments_page/templates/commentIcons.html");
return cb();

@@ -198,3 +148,3 @@ };

exports.eejsBlock_styles = function (hook_name, args, cb) {
args.content = args.content + eejs.require("ep_comments_page/templates/styles.html", {}, module);
args.content = args.content + eejs.require("ep_comments_page/templates/styles.html");
return cb();

@@ -213,3 +163,3 @@ };

exports.expressCreateServer = function (hook_name, args, callback) {
args.app.get('/p/:pad/:rev?/comments', function(req, res) {
args.app.get('/p/:pad/:rev?/comments', async (req, res) => {
var fields = req.query;

@@ -220,43 +170,58 @@ // check the api key

// sanitize pad id before continuing
var padIdReceived = apiUtils.sanitizePadId(req);
const padIdReceived = (await readOnlyManager.getIds(apiUtils.sanitizePadId(req))).padId;
comments.getPadComments(padIdReceived, function(err, data) {
if(err) {
res.json({code: 2, message: "internal error", data: null});
} else {
res.json({code: 0, data: data});
}
});
let data;
try {
data = await commentManager.getComments(padIdReceived);
} catch (err) {
console.error(err.stack ? err.stack : err.toString());
res.json({code: 2, message: 'internal error', data: null});
return;
}
if (data == null) return;
res.json({code: 0, data});
});
args.app.post('/p/:pad/:rev?/comments', function(req, res) {
new formidable.IncomingForm().parse(req, function (err, fields, files) {
// check the api key
if(!apiUtils.validateApiKey(fields, res)) return;
args.app.post('/p/:pad/:rev?/comments', async (req, res) => {
const [fields, files] = await new Promise((resolve, reject) => {
(new formidable.IncomingForm()).parse(req, (err, fields, files) => {
if (err != null) return reject(err);
resolve([fields, files]);
});
});
// check required fields from comment data
if(!apiUtils.validateRequiredFields(fields, ['data'], res)) return;
// check the api key
if (!apiUtils.validateApiKey(fields, res)) return;
// sanitize pad id before continuing
var padIdReceived = apiUtils.sanitizePadId(req);
// check required fields from comment data
if (!apiUtils.validateRequiredFields(fields, ['data'], res)) return;
// create data to hold comment information:
try {
var data = JSON.parse(fields.data);
// sanitize pad id before continuing
const padIdReceived = (await readOnlyManager.getIds(apiUtils.sanitizePadId(req))).padId;
comments.bulkAddPadComments(padIdReceived, data, function(err, commentIds, comments) {
if(err) {
res.json({code: 2, message: "internal error", data: null});
} else {
broadcastCommentsAdded(padIdReceived, commentIds, comments);
res.json({code: 0, commentIds: commentIds});
}
});
} catch(e) {
res.json({code: 1, message: "data must be a JSON", data: null});
}
});
// create data to hold comment information:
let data;
try {
data = JSON.parse(fields.data);
} catch (err) {
res.json({code: 1, message: "data must be a JSON", data: null});
return;
}
let commentIds, comments;
try {
[commentIds, comments] = await commentManager.bulkAddComments(padIdReceived, data);
} catch (err) {
console.error(err.stack ? err.stack : err.toString());
res.json({code: 2, message: "internal error", data: null});
return;
}
if (commentIds == null) return;
for (let i = 0; i < commentIds.length; i++) {
io.to(padIdReceived).emit('pushAddComment', commentIds[i], comments[i]);
}
res.json({code: 0, commentIds: commentIds});
});
args.app.get('/p/:pad/:rev?/commentReplies', function(req, res){
args.app.get('/p/:pad/:rev?/commentReplies', async (req, res) => {
//it's the same thing as the formidable's fields

@@ -268,69 +233,59 @@ var fields = req.query;

//sanitize pad id before continuing
var padIdReceived = apiUtils.sanitizePadId(req);
const padIdReceived = (await readOnlyManager.getIds(apiUtils.sanitizePadId(req))).padId;
// call the route with the pad id sanitized
comments.getPadCommentReplies(padIdReceived, function(err, data) {
if(err) {
res.json({code: 2, message: "internal error", data:null})
} else {
res.json({code: 0, data: data});
}
});
let data;
try {
data = await commentManager.getCommentReplies(padIdReceived);
} catch (err) {
console.error(err.stack ? err.stack : err.toString());
res.json({code: 2, message: "internal error", data:null});
return;
}
if (data == null) return;
res.json({code: 0, data: data});
});
args.app.post('/p/:pad/:rev?/commentReplies', function(req, res) {
new formidable.IncomingForm().parse(req, function (err, fields, files) {
// check the api key
if(!apiUtils.validateApiKey(fields, res)) return;
// check required fields from comment data
if(!apiUtils.validateRequiredFields(fields, ['data'], res)) return;
// sanitize pad id before continuing
var padIdReceived = apiUtils.sanitizePadId(req);
// create data to hold comment reply information:
try {
var data = JSON.parse(fields.data);
comments.bulkAddPadCommentReplies(padIdReceived, data, function(err, replyIds, replies) {
if(err) {
res.json({code: 2, message: "internal error", data: null});
} else {
broadcastCommentRepliesAdded(padIdReceived, replyIds, replies);
res.json({code: 0, replyIds: replyIds});
}
});
} catch(e) {
res.json({code: 1, message: "data must be a JSON", data: null});
}
args.app.post('/p/:pad/:rev?/commentReplies', async (req, res) => {
const [fields, files] = await new Promise((resolve, reject) => {
(new formidable.IncomingForm()).parse(req, (err, fields, files) => {
if (err != null) return reject(err);
resolve([fields, files]);
});
});
});
}
// check the api key
if (!apiUtils.validateApiKey(fields, res)) return;
var broadcastCommentsAdded = function(padId, commentIds, comments) {
var socket = clientIO.connect(broadcastUrl);
// check required fields from comment data
if (!apiUtils.validateRequiredFields(fields, ['data'], res)) return;
var data = {
padId: padId,
commentIds: commentIds,
comments: comments
};
// sanitize pad id before continuing
const padIdReceived = (await readOnlyManager.getIds(apiUtils.sanitizePadId(req))).padId;
socket.emit('apiAddComments', data);
}
// create data to hold comment reply information:
let data;
try {
data = JSON.parse(fields.data);
} catch (err) {
res.json({code: 1, message: "data must be a JSON", data: null});
return;
}
var broadcastCommentRepliesAdded = function(padId, replyIds, replies) {
var socket = clientIO.connect(broadcastUrl);
var data = {
padId: padId,
replyIds: replyIds,
replies: replies
};
socket.emit('apiAddCommentReplies', data);
let replyIds, replies;
try {
[replyIds, replies] = await commentManager.bulkAddCommentReplies(padIdReceived, data);
} catch (err) {
console.error(err.stack ? err.stack : err.toString());
res.json({code: 2, message: "internal error", data: null});
return;
}
if (replyIds == null) return;
for (let i = 0; i < replyIds.length; i++) {
replies[i].replyId = replyIds[i];
io.to(padIdReceived).emit('pushAddCommentReply', replyIds[i], replies[i]);
}
res.json({code: 0, replyIds: replyIds});
});
return callback();
}
var broadcastUrl = apiUtils.broadcastUrlFor("/comment");

@@ -21,34 +21,20 @@ {

"ep_comments_page.comments_template.reply.placeholder" : "Reply",
"ep_comments_page.time.seconds.past" : "{{count}} seconds ago",
"ep_comments_page.time.seconds.future" : "{{count}} seconds from now",
"ep_comments_page.time.one_minute.past" : "1 minute ago",
"ep_comments_page.time.one_minute.future" : "1 minute from now",
"ep_comments_page.time.minutes.past" : "{{count}} minutes ago",
"ep_comments_page.time.minutes.future" : "{{count}} minutes from now",
"ep_comments_page.time.one_hour.past" : "1 hour ago",
"ep_comments_page.time.one_hour.future" : "1 hour from now",
"ep_comments_page.time.hours.past" : "{{count}} hours ago",
"ep_comments_page.time.hours.future" : "{{count}} hours from now",
"ep_comments_page.time.one_day.past" : "yesterday",
"ep_comments_page.time.one_day.future" : "tomorrow",
"ep_comments_page.time.days.past" : "{{count}} days ago",
"ep_comments_page.time.days.future" : "{{count}} days from now",
"ep_comments_page.time.one_week.past" : "last week",
"ep_comments_page.time.one_week.future" : "next week",
"ep_comments_page.time.weeks.past" : "{{count}} weeks ago",
"ep_comments_page.time.weeks.future" : "{{count}} weeks from now",
"ep_comments_page.time.one_month.past" : "last month",
"ep_comments_page.time.one_month.future" : "next month",
"ep_comments_page.time.months.past" : "{{count}} months ago",
"ep_comments_page.time.months.future" : "{{count}} months from now",
"ep_comments_page.time.one_year.past" : "last year",
"ep_comments_page.time.one_year.future" : "next year",
"ep_comments_page.time.years.past" : "{{count}} years ago",
"ep_comments_page.time.years.future" : "{{count}} years from now",
"ep_comments_page.time.one_century.past" : "last century",
"ep_comments_page.time.one_century.future" : "next century",
"ep_comments_page.time.centuries.past" : "{{count}} centuries ago",
"ep_comments_page.time.centuries.future" : "{{count}} centuries from now",
"ep_comments_page.time.seconds.past": "{{count}} {[ plural(count) one: second, other: seconds ]} ago",
"ep_comments_page.time.seconds.future": "{{count}} {[ plural(count) one: second, other: seconds ]} from now",
"ep_comments_page.time.minutes.past": "{{count}} {[ plural(count) one: minute, other: minutes ]} ago",
"ep_comments_page.time.minutes.future": "{{count}} {[ plural(count) one: minute, other: minutes ]} from now",
"ep_comments_page.time.hours.past": "{{count}} {[ plural(count) one: hour, other: hours ]} ago",
"ep_comments_page.time.hours.future": "{{count}} {[ plural(count) one: hour, other: hours ]} from now",
"ep_comments_page.time.days.past": "{[ plural(count) one: yesterday, other: {{count}} days ago ]}",
"ep_comments_page.time.days.future": "{[ plural(count) one: tomorrow, other: {{count}} days from now ]}",
"ep_comments_page.time.weeks.past": "{[ plural(count) one: last week, other: {{count}} weeks ago ]}",
"ep_comments_page.time.weeks.future": "{[ plural(count) one: next week, other: {{count}} weeks from now ]}",
"ep_comments_page.time.months.past": "{[ plural(count) one: last month, other: {{count}} months ago ]}",
"ep_comments_page.time.months.future": "{[ plural(count) one: next month, other: {{count}} months from now ]}",
"ep_comments_page.time.years.past": "{[ plural(count) one: last year, other: {{count}} years ago ]}",
"ep_comments_page.time.years.future": "{[ plural(count) one: next year, other: {{count}} years from now ]}",
"ep_comments_page.time.centuries.past": "{[ plural(count) one: last century, other: {{count}} centuries ago ]}",
"ep_comments_page.time.centuries.future": "{[ plural(count) one: next century, other: {{count}} centuries from now ]}",
"ep_comments_page.comments_template.edit_comment.save" : "save",
"ep_comments_page.comments_template.edit_comment.cancel" :"cancel"
}
{
"description": "Adds comments on sidebar and link it to the text. For no-skin use ep_page_view.",
"name": "ep_comments_page",
"version": "0.1.7",
"version": "0.1.8",
"author": {

@@ -9,2 +9,3 @@ "name": "Nicolas Lescop",

},
"license": "Apache-2.0",
"contributors": [

@@ -25,7 +26,7 @@ {

"dependencies": {
"formidable": "*",
"socket.io-client": "*"
"formidable": "*"
},
"devDependencies": {
"request": "*"
"request": "*",
"socket.io-client": "*"
},

@@ -32,0 +33,0 @@ "engines": {

@@ -0,1 +1,3 @@

/* global clearTimeout, clientVars, exports, html10n, pad, require, setTimeout */
/* TODO:

@@ -1105,17 +1107,10 @@ - lable reply textarea

ep_comments.prototype.commentRepliesListen = function(){
var self = this;
var socket = this.socket;
socket.on('pushAddCommentReply', function (replyId, reply, changeTo, changeFrom){
// console.warn("pAcR response", replyId, reply, changeTo, changeFrom);
// callback(replyId, reply);
// self.collectCommentReplies();
self.getCommentReplies(function (replies){
this.socket.on('pushAddCommentReply', (replyId, reply) => {
this.getCommentReplies((replies) => {
if (!$.isEmptyObject(replies)){
// console.log("collecting comment replies");
self.commentReplies = replies;
self.collectCommentReplies();
this.commentReplies = replies;
this.collectCommentReplies();
}
});
});
};

@@ -1197,3 +1192,3 @@

// Init pad comments
postAceInit: function(hook, context){
postAceInit: function(hookName, context, cb) {
if(!pad.plugins) pad.plugins = {};

@@ -1211,5 +1206,6 @@ var Comments = new ep_comments(context);

}
return cb();
},
aceEditEvent: function(hook, context){
aceEditEvent: function(hookName, context, cb) {
if(!pad.plugins) pad.plugins = {};

@@ -1224,4 +1220,4 @@ // first check if some text is being marked/unmarked to add comment to it

if(eventType == "setup" || eventType == "setBaseText" || eventType == "importText") return;
if (eventType == 'setup' || eventType == 'setBaseText' || eventType == 'importText') return cb();
if(context.callstack.docTextChanged && pad.plugins.ep_comments_page){

@@ -1243,17 +1239,19 @@ pad.plugins.ep_comments_page.setYofComments();

}
return cb();
},
// Insert comments classes
aceAttribsToClasses: function(hook, context){
aceAttribsToClasses: function(hookName, context, cb) {
if(context.key === 'comment' && context.value !== "comment-deleted") {
return ['comment', context.value];
return cb(['comment', context.value]);
}
// only read marks made by current user
if(context.key === preCommentMark.MARK_CLASS && context.value === clientVars.userId) {
return [preCommentMark.MARK_CLASS, context.value];
return cb([preCommentMark.MARK_CLASS, context.value]);
}
return cb();
},
aceEditorCSS: function(){
return cssFiles;
aceEditorCSS: function(hookName, context, cb) {
return cb(cssFiles);
}

@@ -1359,3 +1357,3 @@

// Once ace is initialized, we set ace_doInsertHeading and bind it to the context
exports.aceInitialized = function(hook, context){
exports.aceInitialized = function(hookName, context, cb) {
var editorInfo = context.editorInfo;

@@ -1365,3 +1363,3 @@ editorInfo.ace_getRepFromSelector = _(getRepFromSelector).bind(context);

editorInfo.ace_hasCommentOnSelection = _(hasCommentOnSelection).bind(context);
return cb();
}
var randomString = require('ep_etherpad-lite/static/js/pad_utils').randomString;
var collectContentPre = function(hook, context){
var collectContentPre = function(hookName, context, cb) {
var comment = /(?:^| )(c-[A-Za-z0-9]*)/.exec(context.cls);

@@ -20,2 +20,3 @@ var fakeComment = /(?:^| )(fakecomment-[A-Za-z0-9]*)/.exec(context.cls);

}
return cb();
};

@@ -22,0 +23,0 @@

@@ -1,36 +0,13 @@

var localizable = typeof html10n !== "undefined";
/* global exports, html10n */
l10nKeys = {
"seconds" : "ep_comments_page.time.seconds",
"1 minute ago" : "ep_comments_page.time.one_minute",
"minutes" : "ep_comments_page.time.minutes",
"1 hour ago" : "ep_comments_page.time.one_hour",
"hours" : "ep_comments_page.time.hours",
"yesterday" : "ep_comments_page.time.one_day",
"days" : "ep_comments_page.time.days",
"last week" : "ep_comments_page.time.one_week",
"weeks" : "ep_comments_page.time.weeks",
"last month" : "ep_comments_page.time.one_month",
"months" : "ep_comments_page.time.months",
"last year" : "ep_comments_page.time.one_year",
"years" : "ep_comments_page.time.years",
"last century" : "ep_comments_page.time.one_century",
"centuries" : "ep_comments_page.time.centuries"
}
const localizable = typeof html10n !== 'undefined';
var time_formats = [
const time_formats = [
[60, 'seconds', 1], // 60
[120, '1 minute ago', '1 minute from now'], // 60*2
[3600, 'minutes', 60], // 60*60, 60
[7200, '1 hour ago', '1 hour from now'], // 60*60*2
[86400, 'hours', 3600], // 60*60*24, 60*60
[172800, 'yesterday', 'tomorrow'], // 60*60*24*2
[604800, 'days', 86400], // 60*60*24*7, 60*60*24
[1209600, 'last week', 'next week'], // 60*60*24*7*4*2
[2419200, 'weeks', 604800], // 60*60*24*7*4, 60*60*24*7
[4838400, 'last month', 'next month'], // 60*60*24*7*4*2
[29030400, 'months', 2419200], // 60*60*24*7*4*12, 60*60*24*7*4
[58060800, 'last year', 'next year'], // 60*60*24*7*4*12*2
[2903040000, 'years', 29030400], // 60*60*24*7*4*12*100, 60*60*24*7*4*12
[5806080000, 'last century', 'next century'], // 60*60*24*7*4*12*100*2
[58060800000, 'centuries', 2903040000] // 60*60*24*7*4*12*100*20, 60*60*24*7*4*12*100

@@ -40,38 +17,19 @@ ];

function prettyDate(time){
/*
var time = ('' + date_str).replace(/-/g,"/").replace(/[TZ]/g," ").replace(/^\s\s*/ /*rappel , '').replace(/\s\s*$/, '');
if(time.substr(time.length-4,1)==".") time =time.substr(0,time.length-4);
*/
var seconds = (new Date() - new Date(time)) / 1000;
// var seconds = new Date() - new Date(time) / 1000;
var token = 'ago',
list_choice = 1,
l10n_appendix = '.past';
const now = new Date();
const then = new Date(time);
const seconds = Math.abs((now - then) / 1000);
const future = now < then;
const token = future ? 'from now' : 'ago';
const list_choice = future ? 2 : 1;
const l10n_appendix = future ? '.future' : '.past';
if (seconds < 0) {
seconds = Math.abs(seconds);
token = 'from now';
l10n_appendix = '.future';
list_choice = 2;
}
var i = 0, format;
while (format = time_formats[i++])
for (const format of time_formats) {
if (seconds < format[0]) {
var count = Math.floor(seconds / format[2]);
var formatted_time;
const count = Math.floor(seconds / format[2]);
if (localizable) {
var key = l10nKeys[format[1]] + l10n_appendix;
formatted_time = html10n.get(key, { count: count });
return html10n.get(`ep_comments_page.time.${format[1]}${l10n_appendix}`, {count});
}
// Wasn't able to localize properly the date, so use the default:
if (formatted_time === undefined) {
if (typeof format[2] == 'string')
formatted_time = format[list_choice];
else
formatted_time = count + ' ' + format[1] + ' ' + token;
}
return formatted_time;
return `${count} ${count === 1 ? format[1].slice(0, -1) : format[1]} ${token}`;
}
}
return time;

@@ -78,0 +36,0 @@ }

describe("ep_comments_page - Comment icons", function() {
//create a new pad with comment before each test run
beforeEach(function(cb){
helper.newPad(function() {
// make sure Etherpad has enough space to display comment icons
enlargeScreen(function() {
// force sidebar comments to be shown
chooseToShowComments(true, function() {
createComment(cb);
});
});
});
beforeEach(async function() {
await new Promise((resolve) => helper.newPad(resolve));
// make sure Etherpad has enough space to display comment icons
enlargeScreen();
// force sidebar comments to be shown
chooseToShowComments(true);
await createComment();
this.timeout(60000);
});
after(function(cb) {
after(async function() {
// undo frame resize that was done on before()
$('#iframe-container iframe').css("max-width", "");
cb();
});
it("adds a comment icon on the same height of commented text", function(done) {
it('adds a comment icon on the same height of commented text', async function() {
// we only run test if icons are enabled
finishTestIfIconsAreNotEnabled(done, function(){
await finishTestIfIconsAreNotEnabled(async () => {
var inner$ = helper.padInner$;
var outer$ = helper.padOuter$;
var commentId = getCommentId();
const commentId = await getCommentId();
var $commentIcon = outer$("#commentIcons #icon-"+commentId);

@@ -37,10 +33,8 @@

expect($commentIcon.offset().top).to.be(expectedTop);
done();
});
});
// TODO: Needs fixing
xit("does not show comment icon when commented text is removed", function(done) {
xit('does not show comment icon when commented text is removed', async function() {
// we only run test if icons are enabled
finishTestIfIconsAreNotEnabled(done, function(){
await finishTestIfIconsAreNotEnabled(async () => {
var inner$ = helper.padInner$;

@@ -53,33 +47,29 @@ var outer$ = helper.padOuter$;

// wait until comment deletion is done
helper.waitFor(function() {
await helper.waitForPromise(() => {
// check icon is not visible
var $commentIcons = outer$("#commentIcons .comment-icon:visible");
return $commentIcons.length === 0;
})
.done(done);
});
});
});
// TODO: Needs fixing
xit("does not show comment icon when comment is deleted", function(done) {
xit('does not show comment icon when comment is deleted', async function() {
// we only run test if icons are enabled
finishTestIfIconsAreNotEnabled(done, function(){
await finishTestIfIconsAreNotEnabled(async () => {
var inner$ = helper.padInner$;
var outer$ = helper.padOuter$;
deleteComment(function() {
// check icon is not visible
var $commentIcons = outer$("#commentIcons .comment-icon:visible");
expect($commentIcons.length).to.be(0);
done();
});
await deleteComment();
// check icon is not visible
var $commentIcons = outer$("#commentIcons .comment-icon:visible");
expect($commentIcons.length).to.be(0);
});
});
it("updates comment icon height when commented text is moved to another line", function(done) {
it('updates comment icon height when commented text is moved to another line', async function() {
// we only run test if icons are enabled
finishTestIfIconsAreNotEnabled(done, function(){
await finishTestIfIconsAreNotEnabled(async () => {
var inner$ = helper.padInner$;
var outer$ = helper.padOuter$;
var commentId = getCommentId();
const commentId = await getCommentId();

@@ -91,29 +81,23 @@ // adds some new lines on the beginning of the text

// wait until the new lines are split into separated .ace-line's
helper.waitFor(function() {
return inner$("div").length > 2;
})
.done(function() {
// wait until comment is visible again
helper.waitFor(function() {
var $commentIcons = outer$("#commentIcons .comment-icon:visible");
return $commentIcons.length !== 0;
})
.done(function() {
// check height is the same
var $commentIcon = outer$("#commentIcons #icon-"+commentId);
var $commentedText = inner$("."+commentId);
var expectedTop = $commentedText.offset().top + 5; // all icons are +5px down to adjust position
expect($commentIcon.offset().top).to.be(expectedTop);
await helper.waitForPromise(() => inner$('div').length > 2);
done();
});
// wait until comment is visible again
await helper.waitForPromise(() => {
var $commentIcons = outer$("#commentIcons .comment-icon:visible");
return $commentIcons.length !== 0;
});
// check height is the same
var $commentIcon = outer$("#commentIcons #icon-"+commentId);
var $commentedText = inner$("."+commentId);
var expectedTop = $commentedText.offset().top + 5; // all icons are +5px down to adjust position
expect($commentIcon.offset().top).to.be(expectedTop);
});
});
it("shows comment when user clicks on comment icon", function(done) {
it('shows comment when user clicks on comment icon', async function() {
// we only run test if icons are enabled
finishTestIfIconsAreNotEnabled(done, function(){
await finishTestIfIconsAreNotEnabled(async () => {
var outer$ = helper.padOuter$;
var commentId = getCommentId();
const commentId = await getCommentId();

@@ -127,12 +111,10 @@ // click on the icon

expect($openedSidebarComments.length).to.be(1);
done();
});
});
it("hides comment when user clicks on comment icon twice", function(done) {
it('hides comment when user clicks on comment icon twice', async function() {
// we only run test if icons are enabled
finishTestIfIconsAreNotEnabled(done, function(){
await finishTestIfIconsAreNotEnabled(async () => {
var outer$ = helper.padOuter$;
var commentId = getCommentId();
const commentId = await getCommentId();

@@ -147,12 +129,10 @@ // click on the icon to open, then click again to close

expect($openedSidebarComments.length).to.be(0);
done();
});
});
it("hides comment when user clicks outside of comment box", function(done) {
it('hides comment when user clicks outside of comment box', async function() {
// we only run test if icons are enabled
finishTestIfIconsAreNotEnabled(done, function(){
await finishTestIfIconsAreNotEnabled(async () => {
var outer$ = helper.padOuter$;
var commentId = getCommentId();
const commentId = await getCommentId();

@@ -169,10 +149,8 @@ // click on the icon to open

expect($openedSidebarComments.length).to.be(0);
done();
});
});
it("hides first comment and shows second comment when user clicks on one icon then on another icon", function(done) {
it('hides first comment and shows second comment when user clicks on one icon then on another icon', async function() {
// we only run test if icons are enabled
finishTestIfIconsAreNotEnabled(done, function(){
await finishTestIfIconsAreNotEnabled(async () => {
var inner$ = helper.padInner$;

@@ -186,25 +164,19 @@ var outer$ = helper.padOuter$;

// wait until the new line is split into a separated .ace-line
helper.waitFor(function() {
return inner$("div").length > 2;
})
.done(function() {
// ... then add a comment to second line
var $secondLine = inner$("div").eq(1);
$secondLine.sendkeys('{selectall}');
addComment("Second Comment", function() {
// click on the icon of first comment...
var $firstCommentIcon = outer$("#commentIcons #icon-"+getCommentId(0)).first();
$firstCommentIcon.click();
// ... then click on the icon of last comment
var $secondCommentIcon = outer$("#commentIcons #icon-"+getCommentId(1)).first();
$secondCommentIcon.click();
await helper.waitForPromise(() => inner$('div').length > 2);
// check modal is visible
var $commentText = outer$("#comments .sidebar-comment:visible .comment-text").text();
expect($commentText).to.be("Second Comment");
// ... then add a comment to second line
var $secondLine = inner$("div").eq(1);
$secondLine.sendkeys('{selectall}');
await addComment('Second Comment');
done();
// click on the icon of first comment...
var $firstCommentIcon = outer$("#commentIcons #icon-"+(await getCommentId(0))).first();
$firstCommentIcon.click();
// ... then click on the icon of last comment
var $secondCommentIcon = outer$("#commentIcons #icon-"+(await getCommentId(1))).first();
$secondCommentIcon.click();
});
});
// check modal is visible
var $commentText = outer$("#comments .sidebar-comment:visible .comment-text").text();
expect($commentText).to.be("Second Comment");
});

@@ -215,3 +187,3 @@ });

var createComment = function(callback) {
const createComment = async () => {
var inner$ = helper.padInner$;

@@ -227,16 +199,13 @@

// wait until the two lines are split into two .ace-line's
helper.waitFor(function() {
return inner$("div").length > 1;
})
.done(function() {
// add comment to last line of the text
var $lastTextElement = inner$("div").first();
$lastTextElement.sendkeys('{selectall}'); // need to select content to add comment to
await helper.waitForPromise(() => inner$("div").length > 1);
addComment("My comment", callback);
});
// add comment to last line of the text
var $lastTextElement = inner$("div").first();
$lastTextElement.sendkeys('{selectall}'); // need to select content to add comment to
await addComment('My comment');
}
// Assumes text is already selected, then add comment to the selected text
var addComment = function(commentText, callback) {
const addComment = async (commentText) => {
var inner$ = helper.padInner$;

@@ -265,9 +234,18 @@ var outer$ = helper.padOuter$;

// wait until comment is created and comment id is set
helper.waitFor(function() {
return getCommentId(numberOfComments) !== null;
})
.done(callback);
}
let running = false;
let success = false;
await helper.waitForPromise(() => {
if (success) return true;
if (!running) {
running = true;
getCommentId(numberOfComments).then((id) => {
running = false;
success = id != null;
});
}
return success;
});
};
var deleteComment = function(callback) {
const deleteComment = async () => {
var chrome$ = helper.padChrome$;

@@ -280,31 +258,25 @@ var outer$ = helper.padOuter$;

helper.waitFor(function() {
return chrome$(".sidebar-comment").is(":visible") === false;
})
.done(callback);
}
await helper.waitForPromise(() => chrome$('.sidebar-comment').is(':visible') === false);
};
var getCommentId = function(numberOfComments) {
const getCommentId = async (numberOfComments) => {
var nthComment = numberOfComments || 0;
helper.waitFor(function(){
var inner$ = helper.padInner$;
if(inner$) return true;
}).done(function(){
var inner$ = helper.padInner$;
var comment = inner$(".comment").eq(nthComment);
var cls = comment.attr('class');
var classCommentId = /(?:^| )(c-[A-Za-z0-9]*)/.exec(cls);
var commentId = (classCommentId) ? classCommentId[1] : null;
return commentId;
});
}
const p = helper.waitFor(() => helper.padInner$);
p.fail(() => {}); // Prevent p from throwing an uncatchable exception on error.
await p;
var inner$ = helper.padInner$;
var comment = inner$(".comment").eq(nthComment);
var cls = comment.attr('class');
var classCommentId = /(?:^| )(c-[A-Za-z0-9]*)/.exec(cls);
var commentId = (classCommentId) ? classCommentId[1] : null;
return commentId;
};
var finishTestIfIconsAreNotEnabled = function(done, theTest) {
const finishTestIfIconsAreNotEnabled = async (theTest) => {
// #commentIcons will only be inserted if icons are enabled
if (helper.padOuter$("#commentIcons").length === 0) done();
else theTest(done);
}
if (helper.padOuter$('#commentIcons').length !== 0) await theTest();
};
var chooseToShowComments = function(shouldShowComments, callback) {
const chooseToShowComments = (shouldShowComments) => {
var chrome$ = helper.padChrome$;

@@ -322,11 +294,8 @@

$settingsButton.click();
};
callback();
}
var enlargeScreen = function(callback) {
const enlargeScreen = () => {
$('#iframe-container iframe').css("max-width", "1000px");
callback();
}
};
});

@@ -20,3 +20,7 @@ describe('ep_comments_page - Comment copy and paste', function () {

helper.selectLines($firstLine, $firstLine, 1, 8); //'omethin'
event = helperFunctions.copyLine();
try{
event = helperFunctions.copyLine();
}catch(e){
// suppress e.preventDefault issue with certain browsers
};
cb();

@@ -107,4 +111,12 @@ });

helperFunctions.addComentAndReplyToLine(FIRST_LINE, commentText, replyText, function(){
event = helperFunctions.copyLine();
helperFunctions.pasteTextOnLine(event, SECOND_LINE);
try{
event = helperFunctions.copyLine();
}catch(e){
// suppress e.preventDefault issue with certain browsers
};
try{
helperFunctions.pasteTextOnLine(event, SECOND_LINE);
}catch(e){
// allowing helper to fail silently.
};
cb();

@@ -111,0 +123,0 @@ });

@@ -5,5 +5,2 @@ var appUrl = 'http://localhost:9001';

var supertest = require('ep_etherpad-lite/node_modules/supertest'),
fs = require('fs'),
path = require('path'),
// io = require('socket.io-client'),
request = require('ep_etherpad-lite/node_modules/request'),

@@ -13,12 +10,4 @@ api = supertest(appUrl),

// Loads the APIKEY.txt content into a string, and returns it.
var getApiKey = function() {
var etherpad_root = '/../../../ep_etherpad-lite/../..';
var filePath = path.join(__dirname, etherpad_root + '/APIKEY.txt');
var apiKey = fs.readFileSync(filePath, {encoding: 'utf-8'});
return apiKey.replace(/\n$/, "");
}
const apiKey = require('ep_etherpad-lite/node/handler/APIHandler.js').exportedForTestingOnly.apiKey;
var apiKey = getApiKey();
// Functions to validate API responses:

@@ -25,0 +14,0 @@ var codeToBe = function(expectedCode, res) {

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc