Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

ep_comments_page

Package Overview
Dependencies
Maintainers
1
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.0.22 to 0.0.23

static/css/commentIcon.css

44

commentManager.js

@@ -54,2 +54,3 @@ var db = require('ep_etherpad-lite/node/db/DB').db;

"changeTo": data.changeTo,
"changeFrom": data.changeFrom,
"timestamp": new Date().getTime()

@@ -114,2 +115,3 @@ };

"changeTo": data.changeTo || null,
"changeFrom": data.changeFrom || null,
"author": metadata.author,

@@ -129,1 +131,43 @@ "name": metadata.name,

exports.changeAcceptedState = function(padId, commentId, state, callback){
// 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){
readOnlyManager.getPadId(padId, function(err, rwPadId){
padId = rwPadId;
});
};
// 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
db.get(prefix + padId, function(err, comments){
if(ERR(err, callback)) return;
//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;
}
comments[commentId] = comment;
//save the new element back
db.set(prefix + padId, comments);
callback(null, commentId, comment);
});
}

1

ep.json

@@ -23,2 +23,3 @@ {

"eejsBlock_styles": "ep_comments_page/index",
"clientVars": "ep_comments_page/index",
"handleMessageSecurity": "ep_comments_page/index"

@@ -25,0 +26,0 @@ }

var eejs = require('ep_etherpad-lite/node/eejs/');
var settings = require('ep_etherpad-lite/node/utils/Settings');
var formidable = require('formidable');

@@ -62,2 +63,20 @@ var clientIO = require('socket.io-client');

socket.on('revertChange', function(data, callback) {
// 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);
});
});
socket.on('acceptChange', function(data, callback) {
// 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);
});
});
socket.on('addCommentReply', function (data, callback) {

@@ -67,6 +86,9 @@ var padId = data.padId;

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){
commentManager.addCommentReply(padId, data, function (err, replyId, reply, changeTo, changeFrom, changeAccepted, changeReverted){
reply.replyId = replyId;
socket.broadcast.to(padId).emit('pushAddCommentReply', replyId, reply, changeTo);
socket.broadcast.to(padId).emit('pushAddCommentReply', replyId, reply, changeTo, changeFrom, changeAccepted, changeReverted);
callback(replyId, reply);

@@ -115,2 +137,3 @@ });

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);
return cb();

@@ -124,2 +147,7 @@ };

exports.clientVars = function (hook, context, cb) {
var displayCommentAsIcon = settings.ep_comments_page ? settings.ep_comments_page.displayCommentAsIcon : false;
return cb({ "displayCommentAsIcon": displayCommentAsIcon });
};
exports.expressCreateServer = function (hook_name, args, callback) {

@@ -142,3 +170,6 @@ args.app.post('/p/:pad/:rev?/comments', function(req, res) {

text: fields.text,
changeTo: fields.changeTo
changeTo: fields.changeTo,
changeFrom: fields.changeFrom,
changeAccepted: fields.changeAccepted,
changeReverted: fields.changeReverted
};

@@ -145,0 +176,0 @@

3

locales/en.json

@@ -8,2 +8,3 @@ {

"ep_comments_page.comments_template.suggested_change" : "Suggested Change:",
"ep_comments_page.comments_template.suggested_change_from" : "From:",
"ep_comments_page.comments_template.accept_change.value" : "Accept Change",

@@ -45,2 +46,2 @@ "ep_comments_page.comments_template.suggest_change_from" : "Suggest change From:",

"ep_comments_page.time.centuries.future" : "{{count}} centuries from now"
}
}
{
"description": "Adds comments on sidebar and link it to the text. Support for Page View, requires ep_page_view",
"name": "ep_comments_page",
"version": "0.0.22",
"version": "0.0.23",
"author": {

@@ -6,0 +6,0 @@ "name": "Nicolas Lescop",

@@ -13,2 +13,15 @@ # Comments and annotations for Etherpad

## Alternative comment display
The plugin also provides an alternative way to display comments. Instead of having all comments visible on the right of the page, you can have just an icon on the right margin of the page. Comment details are displayed when user clicks on the comment icon:
![Screen shot](http://i.imgur.com/cEo7PdL.png)
To use this way of displaying comments, add the following to your `settings.json`:
```
// Display comments as icons, not boxes
"ep_comments_page": {
"displayCommentAsIcon": true,
},
```
## Creating comment via API

@@ -15,0 +28,0 @@ If you need to add a comment to a pad:

@@ -7,4 +7,6 @@ var _, $, jQuery;

var prettyDate = require('ep_comments_page/static/js/timeFormat').prettyDate;
var commentBoxes = require('ep_comments_page/static/js/commentBoxes');
var commentIcons = require('ep_comments_page/static/js/commentIcons');
var cssFiles = ['ep_comments_page/static/css/comment.css'];
var cssFiles = ['ep_comments_page/static/css/comment.css', 'ep_comments_page/static/css/commentIcon.css'];

@@ -14,2 +16,3 @@ /************************************************************************/

/************************************************************************/
// Container

@@ -52,2 +55,5 @@ function ep_comments(context){

// Init icons container
commentIcons.insertContainer();
// Get all comments

@@ -111,2 +117,19 @@ this.getComments(function (comments){

// When screen size changes (user changes device orientation, for example),
// we need to make sure all sidebar comments are on the correct place
this.waitForResizeToFinishThenCall(function() {
commentIcons.adjustIconsForNewScreenSize();
// We try increasing timeouts, to make sure user gets the response as fast as we can
setTimeout(function() {
if (!self.allCommentsOnCorrectYPosition()) self.adjustCommentPositions();
setTimeout(function() {
if (!self.allCommentsOnCorrectYPosition()) self.adjustCommentPositions();
setTimeout(function() {
if (!self.allCommentsOnCorrectYPosition()) self.adjustCommentPositions();
}, 1000);
}, 500);
}, 250);
});
// On click comment icon toolbar

@@ -148,3 +171,3 @@ $('.addComment').on('click', function(e){

var currentString = padInner.contents().find("."+commentId).html();
$(this).parent().parent().find(".reply-comment-suggest-from").html(currentString);
$(this).parent().parent().find(".reply-comment-changeFrom-value").html(currentString);
$(this).parent().parent().find('.reply-suggestion').show();

@@ -162,12 +185,24 @@ }else{

// DUPLICATE CODE REQUIRED FOR COMMENT REPLIES, see below for slightly different version
this.container.on("click", ".comment-reply-changeTo-approve", function(e){
this.container.on("click", ".comment-reply-changeTo-approve > input", function(e){
e.preventDefault();
var commentId = $(this).parent().parent().parent().parent()[0].id;
var newString = $(this).parent().contents().find(".comment-changeTo-value").html();
var data = {};
data.commentId = $(this).parent().parent().parent().parent().parent()[0].id;
data.padId = clientVars.padId;
data.replyId = $(this).parent().parent().parent()[0].id;
var padOuter = $('iframe[name="ace_outer"]').contents();
var padInner = padOuter.find('iframe[name="ace_inner"]');
// Are we reverting a change?
var submitButton = $(this);
var isRevert = submitButton.hasClass("revert");
if(isRevert){
var newString = $(this).parent().parent().parent().contents().find(".comment-changeFrom-value").html();
}else{
var newString = $(this).parent().parent().parent().contents().find(".comment-changeTo-value").html();
}
// Nuke all that aren't first lines of this comment
padInner.contents().find("."+commentId+":not(:first)").html("");
var padCommentContent = padInner.contents().find("."+commentId).first();
padInner.contents().find("."+data.commentId+":not(:first)").html("");
var padCommentContent = padInner.contents().find("."+data.commentId).first();
newString = newString.replace(/(?:\r\n|\r|\n)/g, '<br />');

@@ -177,2 +212,18 @@

$(padCommentContent).html(newString);
// We change commentId to replyId in the data object so it's properly processed by the server.. This is hacky
data.commentId = data.replyId;
if(isRevert){
// Tell all users this change was reverted
self.socket.emit('revertChange', data, function (){});
self.showChangeAsReverted(data.replyId);
}else{
// Tell all users this change was accepted
self.socket.emit('acceptChange', data, function (){});
// Update our own comments container with the accepted change
self.showChangeAsAccepted(data.replyId);
}
});

@@ -184,3 +235,2 @@

var data = self.getCommentData();
var newString = $(this).parent().contents().find(".comment-changeTo-value").html();
data.commentId = $(this).parent()[0].id;

@@ -190,2 +240,11 @@ var padOuter = $('iframe[name="ace_outer"]').contents();

// Are we reverting a change?
var submitButton = $(this).contents().find("input[type='submit']");
var isRevert = submitButton.hasClass("revert");
if(isRevert){
var newString = $(this).parent().contents().find(".comment-changeFrom-value").html();
}else{
var newString = $(this).parent().contents().find(".comment-changeTo-value").html();
}
// Nuke all that aren't first lines of this comment

@@ -195,6 +254,18 @@ padInner.contents().find("."+data.commentId+":not(:first)").html("");

var padCommentContent = padInner.contents().find("."+data.commentId).first();
newString = newString.replace(/(?:\r\n|\r|\n)/g, '<br />');
newString = newString.replace(/(?:\r\n|\r)/g, '<br />');
// Write the new pad contents
$(padCommentContent).html(newString);
if(isRevert){
// Tell all users this change was reverted
self.socket.emit('revertChange', data, function (){});
self.showChangeAsReverted(data.commentId);
}else{
// Tell all users this change was accepted
self.socket.emit('acceptChange', data, function (){});
// Update our own comments container with the accepted change
self.showChangeAsAccepted(data.commentId);
}
});

@@ -209,2 +280,3 @@

data.changeTo = $(this).find(".reply-comment-suggest-to").val() || null;
data.changeFrom = $(this).find(".reply-comment-changeFrom-value").text() || null;
self.socket.emit('addCommentReply', data, function (){

@@ -263,4 +335,5 @@ // Append the reply to the comment

window.setTimeout(function() {
self.newCommentContainer.find('#newComment').removeClass("hidden").addClass("visible");
}, 0);
$('iframe[name="ace_outer"]').contents().find('.suggestion').hide(); // Hides suggestion in case of a cancel
self.newCommentContainer.find('#newComment').removeClass("hidden").addClass("visible");
}, 0);
}

@@ -273,4 +346,4 @@

window.setTimeout(function() {
self.newCommentContainer.removeClass("active");
}, 500);
self.newCommentContainer.removeClass("active");
}, 500);
}

@@ -290,2 +363,3 @@

var commentId = (classCommentId) ? classCommentId[1] : null;
if(!commentId){

@@ -305,2 +379,3 @@ // console.log("returning due to no comment id, probably due to a deleted comment");

var commentElm = container.find('#'+ commentId);
var comment = comments[commentId];

@@ -313,2 +388,3 @@ if(comment){

commentElm = container.find('#'+ commentId);
$(this).on('click', function(){

@@ -339,2 +415,13 @@ markerTop = $(this).position().top;

commentElm.css({ 'top': commentPos });
// Should we show "Revert" instead of "Accept"
// Comment Replies are NOT handled here..
if(comments[commentId]){
var showRevert = comments[commentId].data.changeAccepted;
}
if(showRevert){
self.showChangeAsAccepted(commentId);
}
});

@@ -358,18 +445,24 @@ // now if we apply a class such as mouseover to the editor it will go shitty

// hover event
this.padInner.contents().on("mouseover", ".comment" ,function(e){
self.highlightComment(e);
this.padInner.contents().on("mouseover", ".comment", function(e){
var commentId = self.commentIdOf(e);
commentBoxes.highlightComment(commentId, e);
});
// click event
this.padInner.contents().on("click", ".comment" ,function(e){
self.highlightComment(e);
this.padInner.contents().on("click", ".comment", function(e){
var commentId = self.commentIdOf(e);
commentBoxes.highlightComment(commentId, e);
});
this.padInner.contents().on("mouseleave", ".comment" ,function(e){
var cls = e.currentTarget.classList;
var classCommentId = /(?:^| )(c-[A-Za-z0-9]*)/.exec(cls);
var commentId = (classCommentId) ? classCommentId[1] : null;
var commentElm = $('iframe[name="ace_outer"]').contents().find("#comments").find('#'+ commentId);
commentElm.removeClass('mouseover');
$('iframe[name="ace_outer"]').contents().find('.comment-modal').hide();
this.padInner.contents().on("mouseleave", ".comment", function(e){
var commentOpenedByClickOnIcon = commentIcons.isCommentOpenedByClickOnIcon();
// only hides comment if it was not opened by a click on the icon
if (!commentOpenedByClickOnIcon) {
var cls = e.currentTarget.classList;
var classCommentId = /(?:^| )(c-[A-Za-z0-9]*)/.exec(cls);
var commentId = (classCommentId) ? classCommentId[1] : null;
commentBoxes.hideComment(commentId);
}
});

@@ -381,3 +474,3 @@ self.setYofComments();

ep_comments.prototype.collectCommentReplies = function(callback){
// console.warn("collectCommentReplies", this.commentReplies);
console.warn("collectCommentReplies", this.commentReplies);
var self = this;

@@ -389,2 +482,6 @@ var container = this.container;

var commentId = replies.commentId;
// tell comment icon that this comment has 1+ replies
commentIcons.commentHasReply(commentId);
var existsAlready = $('iframe[name="ace_outer"]').contents().find('#'+replyId).length;

@@ -394,27 +491,22 @@ if(existsAlready) return;

replies.replyId = replyId;
var content = $("#replyTemplate").tmpl(replies);
$('iframe[name="ace_outer"]').contents().find('#'+commentId + ' .comment-reply-input').before(content);
// Should we show "Revert" instead of "Accept"
// Comment Replies ARE handled here..
if(replies.changeAccepted){
self.showChangeAsAccepted(replyId);
}
});
};
ep_comments.prototype.highlightComment = function(e){
ep_comments.prototype.commentIdOf = function(e){
var cls = e.currentTarget.classList;
var classCommentId = /(?:^| )(c-[A-Za-z0-9]*)/.exec(cls);
var commentId = (classCommentId) ? classCommentId[1] : null;
var commentElm = $('iframe[name="ace_outer"]').contents().find("#comments").find('#'+ commentId);
var commentsVisible = this.container.is(":visible");
if(commentsVisible){
// sidebar view highlight
commentElm.addClass('mouseover');
}else{
var commentElm = $('iframe[name="ace_outer"]').contents().find("#comments").find('#'+ commentId);
$('iframe[name="ace_outer"]').contents().find('.comment-modal').show().css({
left: e.clientX +"px",
top: e.clientY + 25 +"px"
});
// hovering comment view
$('iframe[name="ace_outer"]').contents().find('.comment-modal-comment').html(commentElm.html());
}
}
return (classCommentId) ? classCommentId[1] : null;
};
// Insert comment container in sidebar

@@ -448,6 +540,8 @@ ep_comments.prototype.insertContainers = function(){

var text = form.find('.comment-content').val();
var changeTo = form.find('.comment-suggest-to').val();
var changeFrom = form.find('.comment-suggest-from').val();
var changeTo = form.find('.comment-suggest-to').val() || null;
var comment = {};
comment.text = text;
if(changeTo){
comment.changeFrom = changeFrom;
comment.changeTo = changeTo;

@@ -503,6 +597,8 @@ }

}
this.setYofComments();
// insert icon
if (!isNew) commentIcons.addIcon(commentId, comment);
};
// Set all comments ot be inline with their target REP
// Set all comments to be inline with their target REP
ep_comments.prototype.setYofComments = function(){

@@ -513,18 +609,70 @@ // for each comment in the pad

var inlineComments = padInner.contents().find(".comment");
padOuter.find("#comments").children("div").each(function(){
// hide each outer comment
$(this).hide();
});
var commentsToBeShown = [];
// hide each outer comment...
commentBoxes.hideAllComments();
// ... and hide comment icons too
commentIcons.hideIcons();
$.each(inlineComments, function(){
var y = this.offsetTop;
y = y-5;
var commentId = /(?:^| )c-([A-Za-z0-9]*)/.exec(this.className); // classname is the ID of the comment
if(commentId){
var commentEle = padOuter.find('#c-'+commentId[1]) // find the comment
commentEle.css("top", y+"px").show();
var commentId = /(?:^| )(c-[A-Za-z0-9]*)/.exec(this.className); // classname is the ID of the comment
if(commentId) {
// adjust outer comment...
var commentEle = commentBoxes.adjustTopOf(commentId[1], y);
// ... and adjust icons too
commentIcons.adjustTopOf(commentId[1], y);
// mark this comment to be displayed if it was visible before we start adjusting its position
if (commentIcons.shouldShow(commentEle)) commentsToBeShown.push(commentEle);
}
});
// re-display comments that were visible before
_.each(commentsToBeShown, function(commentEle) {
commentEle.show();
});
};
// Some browsers trigger resize several times while resizing the window, so
// we need to make sure resize is done to avoid calling the callback multiple
// times.
// Based on: https://css-tricks.com/snippets/jquery/done-resizing-event/
ep_comments.prototype.waitForResizeToFinishThenCall = function(callback){
var resizeTimer;
$(window).on("resize", function() {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(callback, 200);
});
}
// Adjusts position on the screen for sidebar comments and comment icons
ep_comments.prototype.adjustCommentPositions = function(){
commentIcons.adjustIconsForNewScreenSize();
this.setYofComments();
}
// Indicates if all comments are on the correct Y position, and don't need to
// be adjusted
ep_comments.prototype.allCommentsOnCorrectYPosition = function(){
// for each comment in the pad
var padOuter = $('iframe[name="ace_outer"]').contents();
var padInner = padOuter.find('iframe[name="ace_inner"]');
var inlineComments = padInner.contents().find(".comment");
var allCommentsAreCorrect = true;
$.each(inlineComments, function(){
var y = this.offsetTop;
var commentId = /(?:^| )(c-[A-Za-z0-9]*)/.exec(this.className);
if(commentId) {
if (!commentBoxes.isOnTop(commentId[1], y)) { // found one comment on the incorrect place
allCommentsAreCorrect = false;
return false; // to break loop
}
}
});
return allCommentsAreCorrect;
}
ep_comments.prototype.localize = function(element) {

@@ -603,3 +751,3 @@ html10n.translateElement(html10n.translations, element.get(0));

data.comment.author = clientVars.userId;
data.comment.name = clientVars.userName;
data.comment.name = pad.myUserInfo.name;
data.comment.timestamp = new Date().getTime();

@@ -700,2 +848,3 @@

if(comment.changeTo){
data.comment.changeFrom = comment.changeFrom;
data.comment.changeTo = comment.changeTo;

@@ -730,4 +879,4 @@ }

var socket = this.socket;
socket.on('pushAddCommentReply', function (replyId, reply, changeTo){
console.warn("pAcR response", replyId, reply, changeTo);
socket.on('pushAddCommentReply', function (replyId, reply, changeTo, changeFrom){
// console.warn("pAcR response", replyId, reply, changeTo, changeFrom);
// callback(replyId, reply);

@@ -744,12 +893,36 @@ // self.collectCommentReplies();

});
};
ep_comments.prototype.showChangeAsAccepted = function(commentId){
var self = this;
// Get the comment
var comment = self.container.find("#"+commentId);
comment.find("input[type='submit']").val("Revert");
comment.find("input[type='submit']").addClass("revert");
}
ep_comments.prototype.showChangeAsReverted = function(commentId){
var self = this;
// Get the comment
var comment = self.container.find("#"+commentId);
comment.find("input[type='submit']").val("Accept");
comment.find("input[type='submit']").removeClass("revert");
}
// Push comment from collaborators
ep_comments.prototype.pushComment = function(eventType, callback){
var socket = this.socket;
var self = this;
// console.error("eventType", eventType);
socket.on('changeAccepted', function(commentId){
self.showChangeAsAccepted(commentId);
});
socket.on('changeReverted', function(commentId){
self.showChangeAsReverted(commentId);
});
// On collaborator add a comment in the current pad

@@ -791,23 +964,11 @@ if (eventType == 'add'){

aceEditEvent: function(hook, context){
var padOuter = $('iframe[name="ace_outer"]').contents();
// var padOuter = $('iframe[name="ace_outer"]').contents();
// padOuter.find('#sidediv').removeClass("sidedivhidden"); // TEMPORARY to do removing authorship colors can add sidedivhidden class to sidesiv!
if(!context.callstack.docTextChanged) return;
// for each comment
// NOTE this is duplicate code because of the way this is written, ugh, this needs fixing
var padInner = padOuter.find('iframe[name="ace_inner"]');
var inlineComments = padInner.contents().find(".comment");
padOuter.find("#comments").children().each(function(){
// hide each outer comment
$(this).hide();
});
$.each(inlineComments, function(){
var y = this.offsetTop;
var commentId = /(?:^| )c-([A-Za-z0-9]*)/.exec(this.className);
if(commentId){
var commentEle = padOuter.find('#c-'+commentId[1]);
y = y-5;
commentEle.css("top", y+"px").show();
}
});
// only adjust comments if plugin was already initialized,
// otherwise there's nothing to adjust anyway
if (pad.plugins && pad.plugins.ep_comments_page) {
pad.plugins.ep_comments_page.setYofComments();
}
},

@@ -908,1 +1069,2 @@

}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

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