@nodebb/nodebb-plugin-reactions 1.0.3 → 2.0.1

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/README.md CHANGED
@@ -1,2 +1,12 @@
1
1
  # nodebb-plugin-reactions
2
2
  Reactions plugin for NodeBB
3
+
4
+ # Screenshots
5
+
6
+ ## Reactions:
7
+ ![CleanShot 2023-05-11 at 08 53 48@2x](https://github.com/ShlomoCode/nodebb-plugin-reactions/assets/78599753/613cb49e-994a-4869-a721-c1eeb00959ff)
8
+
9
+
10
+ ## ACP:
11
+ ![CleanShot 2023-05-11 at 04 09 11@2x](https://github.com/ShlomoCode/nodebb-plugin-reactions/assets/78599753/f4a4e5cb-f060-4415-a337-222a157a6e59)
12
+
@@ -2,5 +2,17 @@
2
2
  "reactions": "Reactions",
3
3
  "add-reaction": "Add reaction",
4
4
  "error.invalid-reaction": "Invalid reaction",
5
- "error.maximum-reached": "Maximum reactions reached"
5
+ "error.maximum-reached": "Maximum reactions reached",
6
+ "error.maximum-per-user-per-post-reached": "Maximum reactions per user per post reached",
7
+ "settings.title": "Reactions plugin settings",
8
+ "settings.max-reactions-per-post": "Maximum unique reactions per post (0 for unlimited, default: 4)",
9
+ "settings.max-reactions-per-user-per-post": "Maximum reactions per user per post (0 for unlimited)",
10
+ "settings.max-reactions-per-user-per-post-help": "The limit is enforced only when adding a new reaction and not when joining an existing reaction.",
11
+ "settings.reaction-reputations": "Reaction Reputations (Optional)",
12
+ "settings.reaction-reputations-help": "You can assign a reputation to individual reactions. When a reaction is applied to a post, the owner of that post will get this reputation.",
13
+ "settings.reaction-reputations.add": "Add Rule",
14
+ "settings.reaction-reputations.reaction": "Reaction",
15
+ "settings.reaction-reputations.reputation": "Reputation",
16
+ "settings.reaction-reputations.remove": "Delete",
17
+ "settings.reaction-reputations.edit": "Edit"
6
18
  }
@@ -0,0 +1,18 @@
1
+ {
2
+ "reactions": "Reactions",
3
+ "add-reaction": "הוסף תגובה",
4
+ "error.invalid-reaction": "תגובה לא חוקית",
5
+ "error.maximum-reached": "הגעת למספר התגובות המקסימלי לפוסט",
6
+ "error.maximum-per-user-per-post-reached": "הגעת למספר התגובות המקסימלי למשתמש לפוסט",
7
+ "settings.title": "הגדרות תגובות",
8
+ "settings.max-reactions-per-post": "מספר התגובות המקסימלי לפוסט (0 = ללא הגבלה, ברירת מחדל: 4)",
9
+ "settings.max-reactions-per-user-per-post": "מספר התגובות המקסימלי למשתמש לפוסט (0 = ללא הגבלה)",
10
+ "settings.max-reactions-per-user-per-post-help": ".ההגבלה נאכפת רק בהוספת תגובה חדשה ולא בהצטרפות לתגובה קיימת",
11
+ "settings.reaction-reputations": "מוניטין תגובה (אופציונלי)",
12
+ "settings.reaction-reputations-help": "אתה יכול להקצות מוניטין לתגובות מסוימות. כאשר התגובה נוספת לפוסט, בעל הפוסט יקבל את המוניטין שנקבע.",
13
+ "settings.reaction-reputations.add": "הוסף כלל",
14
+ "settings.reaction-reputations.reaction": "תגובה",
15
+ "settings.reaction-reputations.reputation": "מוניטין",
16
+ "settings.reaction-reputations.remove": "הסר",
17
+ "settings.reaction-reputations.edit": "ערוך"
18
+ }
package/library.js CHANGED
@@ -13,7 +13,7 @@ const emojiParser = require.main.require('nodebb-plugin-emoji/build/lib/parse.js
13
13
  const emojiTable = require.main.require('nodebb-plugin-emoji/build/emoji/table.json');
14
14
  const emojiAliases = require.main.require('nodebb-plugin-emoji/build/emoji/aliases.json');
15
15
 
16
- const DEFAULT_MAX_EMOTES = 5;
16
+ const DEFAULT_MAX_EMOTES = 4;
17
17
 
18
18
  function parse(name) {
19
19
  return emojiParser.buildEmoji(emojiTable[name] || emojiTable[emojiAliases[name]], '');
@@ -71,7 +71,7 @@ ReactionsPlugin.getReactions = async function (data) {
71
71
 
72
72
  if (reactionsList && reactionsList.length > 0) {
73
73
  pidToReactionsMap.set(pid, reactionsList);
74
- pidToIsMaxReactionsReachedMap.set(pid, reactionsCount >= maximumReactions);
74
+ pidToIsMaxReactionsReachedMap.set(pid, reactionsCount > maximumReactions);
75
75
  reactionSets = reactionSets.concat(reactionsList.map(reaction => `pid:${pid}:reaction:${reaction}`));
76
76
  }
77
77
  } catch (e) {
@@ -203,33 +203,42 @@ SocketPlugins.reactions = {
203
203
 
204
204
  data.uid = socket.uid;
205
205
 
206
- try {
207
- const settings = await meta.settings.get('reactions');
208
- const maximumReactions = settings.maximumReactions || DEFAULT_MAX_EMOTES;
209
- const [totalReactions, isMember, alreadyReacted, reactionReputation] = await Promise.all([
210
- db.setCount(`pid:${data.pid}:reactions`),
211
- db.isSetMember(`pid:${data.pid}:reactions`, data.reaction),
212
- db.isSetMember(`pid:${data.pid}:reaction:${data.reaction}`, socket.uid),
213
- getReactionReputation(data.reaction),
214
- ]);
206
+ const settings = await meta.settings.get('reactions');
207
+ const maximumReactions = settings.maximumReactions || DEFAULT_MAX_EMOTES;
208
+ const [totalReactions, emojiIsAlreadyExist, alreadyReacted, reactionReputation] = await Promise.all([
209
+ db.setCount(`pid:${data.pid}:reactions`),
210
+ db.isSetMember(`pid:${data.pid}:reactions`, data.reaction),
211
+ db.isSetMember(`pid:${data.pid}:reaction:${data.reaction}`, socket.uid),
212
+ getReactionReputation(data.reaction),
213
+ ]);
215
214
 
216
- if (!isMember && totalReactions >= maximumReactions) {
217
- throw new Error('[[reactions:error.maximum-reached]]');
215
+ if (!emojiIsAlreadyExist) {
216
+ if (totalReactions > maximumReactions) {
217
+ throw new Error(`[[reactions:error.maximum-reached]] (${maximumReactions})`);
218
218
  }
219
-
220
- await Promise.all([
221
- db.setAdd(`pid:${data.pid}:reactions`, data.reaction),
222
- db.setAdd(`pid:${data.pid}:reaction:${data.reaction}`, socket.uid),
223
- ]);
224
-
225
- if (!alreadyReacted && reactionReputation > 0) {
226
- await giveOwnerReactionReputation(reactionReputation, data.pid);
219
+
220
+ const maximumReactionsPerUserPerPost = settings.maximumReactionsPerUserPerPost ? parseInt(settings.maximumReactionsPerUserPerPost, 10) : 0;
221
+ if (maximumReactionsPerUserPerPost > 0) {
222
+ const emojiesInPost = await db.getSetMembers(`pid:${data.pid}:reactions`);
223
+ const userPostReactions = await db.isMemberOfSets(emojiesInPost.map(emojiName => `pid:${data.pid}:reaction:${emojiName}`), socket.uid);
224
+ const userPostReactionCount = userPostReactions.filter(Boolean).length;
225
+ if (userPostReactionCount > maximumReactionsPerUserPerPost) {
226
+ throw new Error(`[[reactions:error.maximum-per-user-per-post-reached]] (${maximumReactionsPerUserPerPost})`);
227
+ }
227
228
  }
229
+ }
230
+
228
231
 
229
- await sendEvent(data, 'event:reactions.addPostReaction');
230
- } catch (e) {
231
- console.error(e);
232
+ await Promise.all([
233
+ db.setAdd(`pid:${data.pid}:reactions`, data.reaction),
234
+ db.setAdd(`pid:${data.pid}:reaction:${data.reaction}`, socket.uid),
235
+ ]);
236
+
237
+ if (!alreadyReacted && reactionReputation > 0) {
238
+ await giveOwnerReactionReputation(reactionReputation, data.pid);
232
239
  }
240
+
241
+ await sendEvent(data, 'event:reactions.addPostReaction');
233
242
  },
234
243
  removePostReaction: async function (socket, data) {
235
244
  if (!socket.uid) {
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@nodebb/nodebb-plugin-reactions",
3
- "version": "1.0.3",
3
+ "version": "2.0.1",
4
4
  "nbbpm": {
5
- "compatibility": "^1.19.7"
5
+ "compatibility": "^3.0.0"
6
6
  },
7
7
  "description": "Reactions plugin for NodeBB",
8
8
  "main": "library.js",
@@ -33,15 +33,14 @@
33
33
  "url": "https://github.com/barisusakli"
34
34
  }
35
35
  ],
36
- "dependencies": {},
37
36
  "peerDependencies": {
38
- "nodebb-plugin-emoji": "^4.0.0"
37
+ "nodebb-plugin-emoji": "^5.0.0"
39
38
  },
40
39
  "license": "MIT",
41
40
  "devDependencies": {
42
- "eslint": "^7.32.0",
43
- "eslint-config-nodebb": "0.0.2",
44
- "eslint-plugin-import": "^2.24.1"
41
+ "eslint": "^8.40.0",
42
+ "eslint-config-nodebb": "^0.2.1",
43
+ "eslint-plugin-import": "^2.27.5"
45
44
  },
46
45
  "scripts": {
47
46
  "lint": "eslint ."
package/plugin.json CHANGED
@@ -2,12 +2,12 @@
2
2
  "id": "nodebb-plugin-reactions",
3
3
  "name": "NodeBB Reactions",
4
4
  "description": "Reactions plugin for NodeBB",
5
- "url": "https://github.com/pichalite/nodebb-plugin-reactions",
5
+ "url": "https://github.com/NodeBB-Community/nodebb-plugin-reactions",
6
6
  "library": "./library.js",
7
7
  "templates": "templates",
8
8
  "languages": "languages",
9
- "less": [
10
- "less/reactions.less"
9
+ "scss": [
10
+ "scss/reactions.scss"
11
11
  ],
12
12
  "scripts": [
13
13
  "public/client.js"
package/public/admin.js CHANGED
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  define('admin/plugins/reactions', [
4
- 'settings', 'alerts', 'hooks', 'emoji-dialog', 'emoji',
4
+ 'settings', 'alerts', 'hooks', 'emoji-dialog', 'emoji',
5
5
  ], function (Settings, alerts, hooks, emojiDialog, emoji) {
6
6
  var ACP = {};
7
7
  ACP.init = function () {
@@ -16,7 +16,7 @@ define('admin/plugins/reactions', [
16
16
  if (reactionEl.length) {
17
17
  const reaction = reactionEl.attr('data-reaction');
18
18
  if (reaction) {
19
- const foundEmoji = emoji.table[reaction]
19
+ const foundEmoji = emoji.table[reaction];
20
20
  if (foundEmoji) {
21
21
  reactionEl.html(emoji.buildEmoji(foundEmoji));
22
22
  }
@@ -45,6 +45,7 @@ define('admin/plugins/reactions', [
45
45
  alert_id: 'reactions-saved',
46
46
  title: 'Settings Saved',
47
47
  message: 'Reactions plugin settings saved',
48
+ timeout: 3000,
48
49
  });
49
50
  });
50
51
  });
package/public/client.js CHANGED
@@ -74,13 +74,13 @@ $(document).ready(function () {
74
74
  }
75
75
 
76
76
  function updateReactionCount(data) {
77
- var maxReactionsReached = parseInt(data.totalReactions, 10) >= config.maximumReactions;
77
+ var maxReactionsReached = parseInt(data.totalReactions, 10) > config.maximumReactions;
78
78
  $('[component="post/reaction/add"][data-pid="' + data.pid + '"]').toggleClass('max-reactions', maxReactionsReached);
79
79
 
80
- var reactionEl = $('[component="post/reaction"][data-pid="' + data.pid + '"][data-reaction="' + data.reaction + '"]');
80
+ var reactionEl = $(`[component="post/reaction"][data-pid="${data.pid}"][data-reaction="${data.reaction}"]`);
81
81
 
82
82
  if (parseInt(data.reactionCount, 10) === 0) {
83
- reactionEl.tooltip('destroy');
83
+ reactionEl.tooltip('dispose');
84
84
  reactionEl.remove();
85
85
  }
86
86
 
@@ -94,21 +94,23 @@ $(document).ready(function () {
94
94
  reactionImage: data.reactionImage,
95
95
  }, function (html) {
96
96
  $('[component="post/reactions"][data-pid="' + data.pid + '"]').append(html);
97
- createReactionTooltips();
98
97
  });
99
98
  } else {
100
99
  reactionEl.find('.reaction-emoji-count').attr('data-count', data.reactionCount);
101
- reactionEl.attr('data-original-title', data.usernames);
100
+ reactionEl.attr('data-bs-original-title', data.usernames);
101
+ reactionEl.attr('aria-label', data.usernames);
102
102
  reactionEl.toggleClass('reacted', !(parseInt(data.uid, 10) === app.user.uid));
103
103
  }
104
+ createReactionTooltips();
104
105
  }
105
106
 
106
107
  function createReactionTooltips() {
107
108
  $('.reaction, .reaction-add').each(function () {
108
109
  if (!utils.isTouchDevice()) {
110
+ $(this).tooltip('dispose');
109
111
  $(this).tooltip({
110
112
  placement: 'top',
111
- title: $(this).attr('title'),
113
+ title: $(this).attr('title') || $(this).attr('data-bs-original-title'),
112
114
  });
113
115
  }
114
116
  });
@@ -0,0 +1,29 @@
1
+ .reactions {
2
+ .reaction {
3
+ border: 1px solid #9ddefe;
4
+ display: inline-block;
5
+ border-radius: 4px;
6
+ padding: 2px 4px;
7
+ margin: 0 1px;
8
+ cursor: pointer;
9
+ .emoji {
10
+ height: 18px;
11
+ }
12
+ &.reacted {
13
+ border: 1px solid #039BE5;
14
+ }
15
+ .reaction-emoji-count {
16
+ margin-left: 5px;
17
+ &:before {
18
+ content: attr(data-count);
19
+ }
20
+ }
21
+ }
22
+ .reaction-add {
23
+ margin-right: 10px;
24
+ cursor: pointer;
25
+ &.max-reactions {
26
+ display: none !important;
27
+ }
28
+ }
29
+ }
@@ -1,10 +1,10 @@
1
1
  <form>
2
2
  <div class="form-group">
3
- <label for="reaction">Reaction</label>
4
- <input type="text" id="reaction" name="reaction" class="form-control" placeholder="Reaction" />
3
+ <label for="reaction">[[reactions:settings.reaction-reputations.reaction]]</label>
4
+ <input type="text" id="reaction" name="reaction" class="form-control" placeholder="[[reactions:settings.reaction-reputations.reaction]]" />
5
5
  </div>
6
6
  <div class="form-group">
7
- <label for="reputation">Reputation</label>
8
- <input type="number" id="reputation" name="reputation" class="form-control" placeholder="reputation" />
7
+ <label for="reputation">[[reactions:settings.reaction-reputations.reputation]]</label>
8
+ <input type="number" id="reputation" name="reputation" class="form-control" placeholder="[[reactions:settings.reaction-reputations.reputation]]" />
9
9
  </div>
10
10
  </form>
@@ -2,11 +2,11 @@
2
2
  <div class="row">
3
3
  <div class="col-xs-9">
4
4
  <span data-reaction="{reaction}"></span><strong> {reaction}</strong><br />
5
- <small>Reputation: {reputation}</small>
5
+ <small>[[reactions:settings.reaction-reputations.reaction]]: {reputation}</small>
6
6
  </div>
7
7
  <div class="col-xs-3 text-right">
8
- <button type="button" data-type="edit" class="btn btn-info">Edit</button>
9
- <button type="button" data-type="remove" class="btn btn-danger">Delete</button>
8
+ <button type="button" data-type="edit" class="btn btn-info">[[reactions:settings.reaction-reputations.edit]]</button>
9
+ <button type="button" data-type="remove" class="btn btn-danger">[[reactions:settings.reaction-reputations.remove]]</button>
10
10
  </div>
11
11
  </div>
12
12
  </li>
@@ -1,31 +1,33 @@
1
1
  <form role="form" class="reactions-settings">
2
2
  <div class="row">
3
- <div class="col-sm-2 col-xs-12 settings-header">Reactions plugin settings</div>
3
+ <div class="col-sm-2 col-xs-12 settings-header">[[reactions:settings.title]]</div>
4
4
  <div class="col-sm-10 col-xs-12">
5
5
  <div class="form-group">
6
- <label>Maximum unique reactions per post</label>
7
- <input type="text" class="form-control" id="maximumReactions" name="maximumReactions">
6
+ <label>[[reactions:settings.max-reactions-per-post]]</label>
7
+ <input type="number" min="0" class="form-control" id="maximumReactions" name="maximumReactions">
8
+
9
+ <label>[[reactions:settings.max-reactions-per-user-per-post]]</label>
10
+ <input type="number" min="0" class="form-control" id="maximumReactionsPerUserPerPost" name="maximumReactionsPerUserPerPost">
11
+ <p class="help-text">
12
+ [[reactions:settings.max-reactions-per-user-per-post-help]]
13
+ </p>
8
14
  </div>
9
15
  </div>
10
16
  </div>
11
- <div class="row">
12
- <div class="col-sm-2 col-xs-12 settings-header">Reaction Reputations (Optional)</div>
17
+
18
+ <div class="row mt-3">
19
+ <div class="col-sm-2 col-xs-12 settings-header">[[reactions:settings.reaction-reputations]]</div>
13
20
  <div class="col-sm-10 col-xs-12">
14
21
  <p class="help-text">
15
- You can assign a reputation to individual reactions. When a reaction is applied to a post, the owner of that post will get this reputation.
22
+ [[reactions:settings.reaction-reputations-help]]
16
23
  </p>
17
24
  <div class="form-group" data-type="sorted-list" data-sorted-list="reaction-reputations" data-item-template="admin/plugins/reactions/partials/sorted-list/emoji-item" data-form-template="admin/plugins/reactions/partials/sorted-list/emoji-form">
18
25
  <ul data-type="list" class="list-group"></ul>
19
- <button type="button" data-type="add" class="btn btn-info">Add Item</button>
26
+ <button type="button" data-type="add" class="btn btn-info mt-2">[[reactions:settings.reaction-reputations.add]]</button>
20
27
  </div>
21
28
  </div>
22
29
  </div>
23
30
  </form>
24
31
 
25
32
 
26
-
27
-
28
-
29
- <button id="save" class="floating-button mdl-button mdl-js-button mdl-button--fab mdl-js-ripple-effect mdl-button--colored">
30
- <i class="material-icons">save</i>
31
- </button>
33
+ <!-- IMPORT admin/partials/save_button.tpl -->
@@ -1,5 +1,5 @@
1
1
  <span class="reactions" component="post/reactions" data-pid="{./pid}">
2
- <span class="reaction-add {{{ if ./maxReactionsReached }}}max-reactions{{{ end }}}" component="post/reaction/add" data-pid="{./pid}" title="[[reactions:add-reaction]]">
2
+ <span class="reaction-add d-inline-block px-2 mx-1 btn-ghost-sm {{{ if ./maxReactionsReached }}}max-reactions{{{ end }}}" component="post/reaction/add" data-pid="{./pid}" title="[[reactions:add-reaction]]">
3
3
  <i class="fa fa-plus-square-o"></i>
4
4
  </span>
5
5
  {{{ each ./reactions }}}
@@ -1,38 +0,0 @@
1
- @primary-color: #039BE5;
2
-
3
- .reactions {
4
-
5
- .reaction {
6
- border: 1px solid lighten(@primary-color, 35%);
7
- display: inline-block;
8
- border-radius: 4px;
9
- padding: 2px 4px;
10
- margin: 0 1px;
11
- cursor: pointer;
12
-
13
- .emoji {
14
- height: 18px;
15
- }
16
-
17
- &.reacted {
18
- border: 1px solid @primary-color;
19
- }
20
-
21
- .reaction-emoji-count {
22
- margin-left: 5px;
23
-
24
- &:before {
25
- content: attr(data-count);
26
- }
27
- }
28
- }
29
-
30
- .reaction-add {
31
- margin-right: 10px;
32
- cursor: pointer;
33
-
34
- &.max-reactions {
35
- display: none;
36
- }
37
- }
38
- }