ep_comments_page 0.1.98 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -4,7 +4,7 @@ const AttributePool = require('ep_etherpad-lite/static/js/AttributePool');
4
4
  const Changeset = require('ep_etherpad-lite/static/js/Changeset');
5
5
  const eejs = require('ep_etherpad-lite/node/eejs/');
6
6
  const settings = require('ep_etherpad-lite/node/utils/Settings');
7
- const formidable = require('formidable');
7
+ const {Formidable} = require('formidable');
8
8
  const commentManager = require('./commentManager');
9
9
  const apiUtils = require('./apiUtils');
10
10
  const _ = require('underscore');
@@ -226,10 +226,7 @@ exports.expressCreateServer = (hookName, args, callback) => {
226
226
 
227
227
  args.app.post('/p/:pad/:rev?/comments', async (req, res) => {
228
228
  const fields = await new Promise((resolve, reject) => {
229
- (new formidable.IncomingForm()).parse(req, (err, fields) => {
230
- if (err != null) return reject(err);
231
- resolve(fields);
232
- });
229
+ new Formidable().parse(req, (err, fields) => err ? reject(err) : resolve(fields));
233
230
  });
234
231
 
235
232
  // check the api key
@@ -289,10 +286,7 @@ exports.expressCreateServer = (hookName, args, callback) => {
289
286
 
290
287
  args.app.post('/p/:pad/:rev?/commentReplies', async (req, res) => {
291
288
  const fields = await new Promise((resolve, reject) => {
292
- (new formidable.IncomingForm()).parse(req, (err, fields) => {
293
- if (err != null) return reject(err);
294
- resolve(fields);
295
- });
289
+ new Formidable().parse(req, (err, fields) => err ? reject(err) : resolve(fields));
296
290
  });
297
291
 
298
292
  // check the api key
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "description": "Adds comments on sidebar and link it to the text. For no-skin use ep_page_view.",
3
3
  "name": "ep_comments_page",
4
- "version": "0.1.98",
4
+ "version": "1.0.2",
5
5
  "author": {
6
6
  "name": "Nicolas Lescop",
7
7
  "email": "limplementeur@gmail.com"
@@ -23,14 +23,14 @@
23
23
  ],
24
24
  "dependencies": {
25
25
  "cheerio": "^0.22.0",
26
- "formidable": "^1.2.2",
27
- "underscore": "^1.13.1"
26
+ "formidable": "^2.0.1",
27
+ "underscore": "^1.13.2"
28
28
  },
29
29
  "devDependencies": {
30
- "eslint": "^8.10.0",
31
- "eslint-config-etherpad": "^3.0.4",
30
+ "eslint": "^8.11.0",
31
+ "eslint-config-etherpad": "^3.0.9",
32
32
  "socket.io-client": "^2.3.0",
33
- "superagent": "^6.1.0",
33
+ "superagent": "^7.1.1",
34
34
  "typescript": "^4.6.2"
35
35
  },
36
36
  "scripts": {
@@ -60,7 +60,7 @@ const EpComments = function (context) {
60
60
  this.mapFakeComments = [];
61
61
  this.mapOriginalCommentsId = [];
62
62
  this.shouldCollectComment = false;
63
- this.init();
63
+ this.initDone = this.init();
64
64
  this.preCommentMarker = preCommentMark.init(this.ace);
65
65
  };
66
66
 
@@ -590,6 +590,10 @@ EpComments.prototype.insertComment = function (commentId, comment, index) {
590
590
  comment.commentId = commentId;
591
591
  comment.reply = true;
592
592
  content = $('#commentsTemplate').tmpl(comment);
593
+ content.find('.from-label')[0].dataset.l10nArgs = JSON.stringify({
594
+ changeFrom: comment.changeFrom,
595
+ changeTo: comment.changeTo,
596
+ });
593
597
  if (comment.author !== clientVars.userId) {
594
598
  $(content).find('.comment-actions-wrapper').addClass('hidden');
595
599
  }
@@ -897,12 +901,6 @@ EpComments.prototype.displayNewCommentForm = function () {
897
901
  // Write the text to the changeFrom form
898
902
  $('#newComment').find('.from-value').text(selectedText);
899
903
 
900
- // Display form
901
- setTimeout(() => {
902
- const position = getXYOffsetOfRep(rep);
903
- newComment.showNewCommentPopup(position);
904
- });
905
-
906
904
  // Check if the first element selected is visible in the viewport
907
905
  const $firstSelectedElement = this.getFirstElementSelected();
908
906
  const firstSelectedElementInViewport = this.isElementInViewport($firstSelectedElement);
@@ -911,8 +909,9 @@ EpComments.prototype.displayNewCommentForm = function () {
911
909
  this.scrollViewportIfSelectedTextIsNotVisible($firstSelectedElement);
912
910
  }
913
911
 
914
- // Adjust focus on the form
915
- $('#newComment').find('.comment-content').focus();
912
+ // Display form
913
+ const position = getXYOffsetOfRep(rep);
914
+ newComment.showNewCommentPopup(position);
916
915
  };
917
916
 
918
917
  EpComments.prototype.scrollViewportIfSelectedTextIsNotVisible = function ($firstSelectedElement) {
@@ -1226,9 +1225,10 @@ EpComments.prototype.pushComment = function (eventType, callback) {
1226
1225
  const hooks = {
1227
1226
 
1228
1227
  // Init pad comments
1229
- postAceInit: (hookName, context, cb) => {
1228
+ postAceInit: async (hookName, context) => {
1230
1229
  if (!pad.plugins) pad.plugins = {};
1231
1230
  const Comments = new EpComments(context);
1231
+ await Comments.initDone;
1232
1232
  pad.plugins.ep_comments_page = Comments;
1233
1233
 
1234
1234
  if (!$('#editorcontainerbox').hasClass('flex-layout')) {
@@ -1240,7 +1240,6 @@ const hooks = {
1240
1240
  class_name: 'error',
1241
1241
  });
1242
1242
  }
1243
- return cb();
1244
1243
  },
1245
1244
 
1246
1245
  postToolbarInit: (hookName, args, cb) => {
@@ -2,6 +2,8 @@
2
2
 
3
3
  const commentL10n = require('ep_comments_page/static/js/commentL10n');
4
4
 
5
+ let $newComment = $();
6
+
5
7
  // Create a comment object with data filled on the given form
6
8
  const buildCommentFrom = (form) => {
7
9
  const text = form.find('.comment-content').val();
@@ -26,15 +28,16 @@ const cancelNewComment = () => {
26
28
  // Callback for new comment Submit
27
29
  const submitNewComment = (callback) => {
28
30
  const index = 0;
29
- const form = $('#newComment');
30
- const comment = buildCommentFrom(form);
31
+ const comment = buildCommentFrom($newComment);
31
32
  if (comment.text.length > 0 || comment.changeTo && comment.changeTo.length > 0) {
32
- form.find('.comment-content, .to-value').removeClass('error');
33
+ $newComment.find('.comment-content, .to-value').removeClass('error');
33
34
  hideNewCommentPopup();
34
35
  callback(comment, index);
35
36
  } else {
36
- if (comment.text.length === 0) form.find('.comment-content').addClass('error');
37
- if (comment.changeTo && comment.changeTo.length === 0) form.find('.to-value').addClass('error');
37
+ if (comment.text.length === 0) $newComment.find('.comment-content').addClass('error');
38
+ if (comment.changeTo && comment.changeTo.length === 0) {
39
+ $newComment.find('.to-value').addClass('error');
40
+ }
38
41
  }
39
42
  return false;
40
43
  };
@@ -42,36 +45,35 @@ const submitNewComment = (callback) => {
42
45
  /* ***** Public methods: ***** */
43
46
 
44
47
  const localizenewCommentPopup = () => {
45
- const newCommentPopup = $('#newComment');
46
- if (newCommentPopup.length !== 0) commentL10n.localize(newCommentPopup);
48
+ if ($newComment.length !== 0) commentL10n.localize($newComment);
47
49
  };
48
50
 
49
51
  // Insert new Comment Form
50
52
  const insertNewCommentPopupIfDontExist = (comment, callback) => {
51
- $('#newComment').remove();
53
+ $newComment.remove();
52
54
 
53
55
  comment.commentId = '';
54
- const newCommentPopup = $('#newCommentTemplate').tmpl(comment);
55
- newCommentPopup.appendTo($('#editorcontainerbox'));
56
+ $newComment = $('#newCommentTemplate').tmpl(comment);
57
+ $newComment.appendTo($('#editorcontainerbox'));
56
58
 
57
59
  localizenewCommentPopup();
58
60
 
59
61
  // Listen for include suggested change toggle
60
- $('#newComment').find('.suggestion-checkbox').change(function () {
61
- $('#newComment').find('.suggestion').toggle($(this).is(':checked'));
62
+ $newComment.find('.suggestion-checkbox').change(function () {
63
+ $newComment.find('.suggestion').toggle($(this).is(':checked'));
62
64
  });
63
65
 
64
66
  // Cancel btn
65
- newCommentPopup.find('#comment-reset').on('click', () => {
67
+ $newComment.find('#comment-reset').on('click', () => {
66
68
  cancelNewComment();
67
69
  });
68
70
  // Create btn
69
- $('#newComment').on('submit', (e) => {
71
+ $newComment.on('submit', (e) => {
70
72
  e.preventDefault();
71
73
  return submitNewComment(callback);
72
74
  });
73
75
 
74
- return newCommentPopup;
76
+ return $newComment;
75
77
  };
76
78
 
77
79
  const showNewCommentPopup = (position) => {
@@ -82,27 +84,28 @@ const showNewCommentPopup = (position) => {
82
84
  left = $('.toolbar .addComment').offset().left;
83
85
  }
84
86
  const top = position[1];
85
- $('#newComment').css('left', left);
87
+ $newComment.css('left', left);
86
88
  if (left === position[0]) {
87
- $('#newComment').css('top', top);
89
+ $newComment.css('top', top);
88
90
  }
89
91
  // Reset form to make sure it is all clear
90
- $('#newComment').find('.suggestion-checkbox').prop('checked', false).trigger('change');
91
- $('#newComment').find('textarea').val('');
92
- $('#newComment').find('.comment-content, .to-value').removeClass('error');
92
+ $newComment.find('.suggestion-checkbox').prop('checked', false).trigger('change');
93
+ $newComment.find('textarea').val('');
94
+ $newComment.find('.comment-content, .to-value').removeClass('error');
93
95
 
94
96
  // Show popup
95
- $('#newComment').addClass('popup-show');
97
+ $newComment.addClass('popup-show');
98
+ $newComment.find('.comment-content').focus();
96
99
 
97
100
  // mark selected text, so it is clear to user which text range the comment is being applied to
98
101
  pad.plugins.ep_comments_page.preCommentMarker.markSelectedText();
99
102
  };
100
103
 
101
104
  const hideNewCommentPopup = () => {
102
- $('#newComment').removeClass('popup-show');
105
+ $newComment.removeClass('popup-show');
103
106
 
104
107
  // force focus to be lost, so virtual keyboard is hidden on mobile devices
105
- $('#newComment').find(':focus').blur();
108
+ $newComment.find(':focus').blur();
106
109
 
107
110
  // unmark selected text, as now there is no text being commented
108
111
  pad.plugins.ep_comments_page.preCommentMarker.unmarkSelectedText();
@@ -1,110 +1,87 @@
1
1
  'use strict';
2
2
 
3
- describe('ep_comments_page - Comment Delete', function () {
4
- let helperFunctions;
5
- const textOfComment = 'original comment';
6
- const textOfReply = 'original reply';
7
- const FIRST_LINE = 0;
3
+ const utils = require('../utils');
8
4
 
9
- // create pad with a comment and a reply
10
- beforeEach(function (done) {
11
- helperFunctions = commentDelete;
12
- helperFunctions.createPad(this, () => {
13
- helperFunctions.addComentAndReplyToLine(FIRST_LINE, textOfComment, textOfReply, done);
14
- });
15
- });
5
+ let helperFunctions;
6
+ const textOfComment = 'original comment';
7
+ const textOfReply = 'original reply';
8
+ const FIRST_LINE = 0;
16
9
 
17
- context('when user presses the delete button on a comment', function () {
18
- it('should delete comment', function (done) {
19
- const outer$ = helper.padOuter$;
20
- const inner$ = helper.padInner$;
21
- outer$('.comment-delete').click();
22
- helper.waitFor(() => inner$('.comment').length === 0).done(() => {
23
- if (inner$('.comment').length !== 0) throw new Error('Error deleting comment');
24
- done();
25
- });
10
+ // create pad with a comment and a reply
11
+ beforeEach(async function () {
12
+ helperFunctions = commentDelete;
13
+ await helperFunctions.createPad(this);
14
+ await helperFunctions.addCommentAndReplyToLine(FIRST_LINE, textOfComment, textOfReply);
15
+ });
16
+
17
+ context('when user presses the delete button on a comment', function () {
18
+ it('should delete comment', function (done) {
19
+ const outer$ = helper.padOuter$;
20
+ const inner$ = helper.padInner$;
21
+ outer$('.comment-delete').click();
22
+ helper.waitFor(() => inner$('.comment').length === 0).done(() => {
23
+ if (inner$('.comment').length !== 0) throw new Error('Error deleting comment');
24
+ done();
26
25
  });
27
26
  });
27
+ });
28
28
 
29
- context('when user presses the delete button on other users comment', function () {
30
- it('should not delete comment', async function () {
31
- let outer$ = helper.padOuter$;
32
- await new Promise((resolve) => setTimeout(resolve, 500));
33
- await new Promise((resolve) => helper.newPad(resolve, helperFunctions.padId));
34
- await helper.waitForPromise(() => {
35
- outer$ = helper.padOuter$;
36
- return !!outer$ && outer$('.comment-delete').length;
37
- });
38
- outer$('.comment-delete').click();
39
- await helper.waitForPromise(() => {
40
- const chrome$ = helper.padChrome$;
41
- return chrome$('#gritter-container').find('.error').length > 0;
42
- });
43
- const inner$ = helper.padInner$;
44
- if (inner$('.comment').length === 0) throw new Error('Comment should not have been deleted');
29
+ context('when user presses the delete button on other users comment', function () {
30
+ it('should not delete comment', async function () {
31
+ let outer$ = helper.padOuter$;
32
+ await new Promise((resolve) => setTimeout(resolve, 500));
33
+ await utils.aNewPad({id: helperFunctions.padId});
34
+ await helper.waitForPromise(() => {
35
+ outer$ = helper.padOuter$;
36
+ return !!outer$ && outer$('.comment-delete').length;
37
+ });
38
+ outer$('.comment-delete').click();
39
+ await helper.waitForPromise(() => {
40
+ const chrome$ = helper.padChrome$;
41
+ return chrome$('#gritter-container').find('.error').length > 0;
45
42
  });
43
+ const inner$ = helper.padInner$;
44
+ if (inner$('.comment').length === 0) throw new Error('Comment should not have been deleted');
46
45
  });
47
46
  });
48
47
 
49
48
  const commentDelete = {
50
49
  padId: undefined,
51
- createPad(test, cb) {
52
- const self = this;
53
- this.padId = helper.newPad(() => {
54
- self.enlargeScreen(() => {
55
- self.createOrResetPadText(() => {
56
- cb();
57
- });
58
- });
59
- });
50
+ async createPad(test) {
60
51
  test.timeout(60000);
52
+ this.padId = await utils.aNewPad();
53
+ this.enlargeScreen();
54
+ await this.createOrResetPadText();
61
55
  },
62
- createOrResetPadText(cb) {
63
- this.cleanPad(() => {
56
+ async createOrResetPadText() {
57
+ await this.cleanPad();
58
+ const inner$ = helper.padInner$;
59
+ inner$('div').first().sendkeys('something\n anything');
60
+ await helper.waitForPromise(() => {
64
61
  const inner$ = helper.padInner$;
65
- inner$('div').first().sendkeys('something\n anything');
66
- helper.waitFor(() => {
67
- const inner$ = helper.padInner$;
68
- const lineLength = inner$('div').length;
69
-
70
- return lineLength > 1;
71
- }).done(cb);
62
+ const lineLength = inner$('div').length;
63
+ return lineLength > 1;
72
64
  });
73
65
  },
74
- reloadPad(test, cb) {
75
- test.timeout(20000);
76
- const self = this;
77
- const padId = this.padId;
78
- // we do nothing for a second while we wait for content to be collected before reloading
79
- // this may be hacky, but we need time for CC to run so... :?
80
- setTimeout(() => {
81
- helper.newPad(() => {
82
- self.enlargeScreen(cb);
83
- }, padId);
84
- }, 1000);
85
- },
86
- cleanPad(callback) {
66
+ async cleanPad() {
87
67
  const inner$ = helper.padInner$;
88
68
  const $padContent = inner$('#innerdocbody');
89
69
  $padContent.html(' ');
90
70
 
91
71
  // wait for Etherpad to re-create first line
92
- helper.waitFor(() => {
72
+ await helper.waitForPromise(() => {
93
73
  const lineNumber = inner$('div').length;
94
74
  return lineNumber === 1;
95
- }, 20000).done(callback);
75
+ }, 20000);
96
76
  },
97
- enlargeScreen(callback) {
77
+ enlargeScreen() {
98
78
  $('#iframe-container iframe').css('max-width', '3000px');
99
- callback();
100
79
  },
101
- addComentAndReplyToLine(line, textOfComment, textOfReply, callback) {
102
- const self = this;
103
- this.addCommentToLine(line, textOfComment, () => {
104
- self.addCommentReplyToLine(line, textOfReply, callback);
105
- });
80
+ async addCommentAndReplyToLine(line, textOfComment, textOfReply) {
81
+ await this.addCommentToLine(line, textOfComment);
82
+ await this.addCommentReplyToLine(line, textOfReply);
106
83
  },
107
- addCommentToLine(line, textOfComment, callback) {
84
+ async addCommentToLine(line, textOfComment) {
108
85
  const chrome$ = helper.padChrome$;
109
86
  const $line = this.getLine(line);
110
87
  $line.sendkeys('{selectall}'); // needs to select content to add comment to
@@ -118,9 +95,9 @@ const commentDelete = {
118
95
  $submittButton.click();
119
96
 
120
97
  // wait until comment is created and comment id is set
121
- this.createdCommentOnLine(line, callback);
98
+ await this.createdCommentOnLine(line);
122
99
  },
123
- addCommentReplyToLine(line, textOfReply, callback) {
100
+ async addCommentReplyToLine(line, textOfReply) {
124
101
  const outer$ = helper.padOuter$;
125
102
  const commentId = this.getCommentIdOfLine(line);
126
103
  const existingReplies = outer$('.sidebar-comment-reply').length;
@@ -141,19 +118,18 @@ const commentDelete = {
141
118
  $submitReplyButton.click();
142
119
 
143
120
  // wait for the reply to be saved
144
- helper.waitFor(() => {
121
+ await helper.waitForPromise(() => {
145
122
  const hasSavedReply = outer$('.sidebar-comment-reply').length === existingReplies + 1;
146
123
  return hasSavedReply;
147
- }).done(callback);
124
+ });
148
125
  },
149
126
  getLine(lineNum) {
150
127
  const inner$ = helper.padInner$;
151
128
  const $line = inner$('div').slice(lineNum, lineNum + 1);
152
129
  return $line;
153
130
  },
154
- createdCommentOnLine(line, cb) {
155
- const self = this;
156
- helper.waitFor(() => self.getCommentIdOfLine(line) != null).done(cb);
131
+ async createdCommentOnLine(line) {
132
+ await helper.waitForPromise(() => this.getCommentIdOfLine(line) != null);
157
133
  },
158
134
  getCommentIdOfLine(line) {
159
135
  const $line = this.getLine(line);
@@ -167,40 +143,4 @@ const commentDelete = {
167
143
  commentIconsEnabled() {
168
144
  return helper.padOuter$('#commentIcons').length > 0;
169
145
  },
170
- clickEditCommentButton() {
171
- const outer$ = helper.padOuter$;
172
- const $editButton = outer$('.comment-edit').first();
173
- $editButton.click();
174
- },
175
- clickEditCommentReplyButton() {
176
- const outer$ = helper.padOuter$;
177
- const $editButton = outer$('.comment-edit').last();
178
- $editButton.click();
179
- },
180
- getEditForm() {
181
- const outer$ = helper.padOuter$;
182
- return outer$('.comment-edit-form');
183
- },
184
- checkIfOneFormEditWasAdded() {
185
- expect(this.getEditForm().length).to.be(1);
186
- },
187
- checkIfOneFormEditWasRemoved() {
188
- expect(this.getEditForm().length).to.be(0);
189
- },
190
- checkIfCommentFieldIsHidden(fieldClass) {
191
- const outer$ = helper.padOuter$;
192
- const $field = outer$(`.${fieldClass}`).first();
193
- expect($field.is(':visible')).to.be(false);
194
- },
195
- pressCancel() {
196
- const $cancelButton = this.getEditForm().find('.comment-edit-cancel');
197
- $cancelButton.click();
198
- },
199
- pressSave() {
200
- const $saveButton = this.getEditForm().find('.comment-edit-submit');
201
- $saveButton.click();
202
- },
203
- writeCommentText(commentText) {
204
- this.getEditForm().find('.comment-edit-text').text(commentText);
205
- },
206
146
  };