nodebb-shoutbox-plugin: how to add @mention completion and emoji completion in the plugin

Solved Technical Support
  • Hello,

    I am modifying for my personal use the nodebb-plugin-shoutbox plugin : https://github.com/NodeBB-Community/nodebb-plugin-shoutbox

    I finished the French translation and I proposed it on the github.
    On the other hand, the translation of the admin.json & shoutbox.json files on language directory is not enough.
    You have to modify the text of other files for a complete translation.

    I managed to modify the default commands and add new ones (text and sound) but there are 2 things I can't do for now, hence the creation of this topic :

      1. Add @mention user completion :

    a5707014-4912-420f-b803-6c5726dfc28b-image.png

      1. add emojis completion :

    c082f61d-5619-4573-8212-3289bdd0a772-image.png

    --> If anyone could help me on these 2 topics or direct me to the right approach, I would be grateful.

    Have a nice day

  • thought about using the nodebb-plugin-mention plugin but I'm not sure how to integrate it.

    for the completion of the emoji I don't really know.

  • Anyone ?

  • Take a look at how it is done for chats.

    https://github.com/NodeBB/NodeBB/blob/master/public/src/client/chats.js#L376-L398

    You can probably use this same code but pass in the text input element of the shoutbox.

  • You will probably add the code into the shoutbox init code here https://github.com/NodeBB-Community/nodebb-plugin-shoutbox/blob/master/public/js/lib/base.js#L4

  • I Test this but doesn't work @baris :

    'use strict';
    
    (function (Shoutbox) {
    	var Instance = function (container, options) {
    		var self = this;
    
    		this.options = options || {};
    
    		setupDom.apply(this, [container]);
    		setupVars.apply(this);
    		setupDependencies.apply(this);
    
    		this.settings.load();
    		getShouts();
    
    		window.sb = this;
    
    		function getShouts() {
    			self.sockets.getShouts(function (err, shouts) {
    				if (err) {
    					return app.alertError(err);
    				}
    				shouts = shouts.filter(function (el) {
    					return el !== null;
    				});
    
    				if (shouts.length === 0) {
    					self.utils.showOverlay(self.vars.messages.empty);
    				} else {
    					self.addShouts(shouts);
    				}
    			});
    		}
    
    
    		Chats.createAutoComplete = function (element) {
    			if (!element.length) {
    				return;
    			}
    	
    			const data = {
    				element: element,
    				strategies: [],
    				options: {
    					style: {
    						'z-index': 20000,
    						flex: 0,
    						top: 'inherit',
    					},
    					placement: 'top',
    				},
    			};
    	
    			$(window).trigger('chat:autocomplete:init', data);
    			if (data.strategies.length) {
    				autocomplete.setup(data);
    			}
    		};
    
    		
    	};
    
    	function setupDependencies() {
    		this.utils = Shoutbox.utils.init(this);
    		this.sockets = Shoutbox.sockets.init(this);
    		this.settings = Shoutbox.settings.init(this);
    		this.actions = Shoutbox.actions.init(this);
    		this.commands = Shoutbox.commands.init(this);
    	}
    
    	Instance.prototype.addShouts = function (shouts) {
    		if (!shouts.length) {
    			return;
    		}
    		var self = this;
    		var lastUid = this.vars.lastUid;
    		var lastSid = this.vars.lastSid;
    		var uid;
    		var sid;
    
    
    		for (let i = shouts.length - 1; i > 0; i -= 1) {
    			var s = shouts[i];
    			var prev = shouts[i - 1];
    			if (parseInt(s.fromuid, 10) === parseInt(prev.fromuid, 10)) {
    				prev.timestamp = s.timestamp;
    			}
    		}
    
    		shouts = shouts.map(function (el) {
    			uid = parseInt(el.fromuid, 10);
    			sid = parseInt(el.sid, 10);
    
    			// Own shout
    			el.isOwn = parseInt(app.user.uid, 10) === uid;
    
    			// Permissions
    			el.user.isMod = el.isOwn || app.user.isAdmin || app.user.isGlobalMod;
    
    			// Add shout chain information to shout
    			el.isChained = lastUid === uid;
    
    			// Add timeString to shout
    			// jQuery.timeago only works properly with ISO timestamps
    			el.timeString = (new Date(parseInt(el.timestamp, 10)).toISOString());
    
    			// Extra classes
    			el.typeClasses = el.isOwn ? 'shoutbox-shout-self ' : '';
    			el.typeClasses += el.user.isAdmin ? 'shoutbox-shout-admin ' : '';
    
    			lastUid = uid;
    			lastSid = sid;
    
    			return el;
    		});
    
    		this.vars.lastUid = lastUid;
    		this.vars.lastSid = lastSid;
    
    		app.parseAndTranslate('shoutbox/shouts', {
    			shouts: shouts,
    		}, function (html) {
    			self.dom.shoutsContainer.append(html);
    			html.find('.timeago').timeago();
    			self.utils.scrollToBottom(shouts.length > 1);
    		});
    	};
    
    	Instance.prototype.updateUserStatus = function (uid, status) {
    		var self = this;
    		var setStatus = function (uid, status) {
    			self.dom.shoutsContainer.find('[data-uid="' + uid + '"].shoutbox-avatar').removeClass().addClass('shoutbox-avatar ' + status);
    		};
    
    		var getStatus = function (uid) {
    			self.sockets.getUserStatus(uid, function (err, data) {
    				if (err) {
    					return app.alertError(err);
    				}
    				setStatus(uid, data.status);
    			});
    		};
    
    		if (!uid) {
    			uid = [];
    
    			self.dom.shoutsContainer.find('[data-uid].shoutbox-avatar').each(function (index, el) {
    				uid.push($(el).data('uid'));
    			});
    
    			uid = uid.filter(function (el, index) {
    				return uid.indexOf(el) === index;
    			});
    		}
    
    		if (!status) {
    			if (typeof uid === 'number') {
    				getStatus(uid);
    			} else if (Array.isArray(uid)) {
    				for (let i = 0, l = uid.length; i < l; i++) {
    					getStatus(uid[i]);
    				}
    			}
    		} else if (typeof uid === 'number') {
    			setStatus(uid, status);
    		} else if (Array.isArray(uid)) {
    			for (let i = 0, l = uid.length; i < l; i++) {
    				setStatus(uid[i], status);
    			}
    		}
    	};
    
    	Instance.prototype.showUserPanel = function () {
    		this.dom.onlineUsers.parent().removeClass('hidden');
    	};
    
    	Instance.prototype.hideUserPanel = function () {
    		this.dom.onlineUsers.parent().addClass('hidden');
    	};
    
    	Instance.prototype.startUserPanelUpdater = function () {
    		var self = this;
    
    		update();
    
    		function update() {
    			this.sockets.getUsers({ set: 'users:online', after: 0 }, function (err, data) {
    				if (err) {
    					return app.alertError(err);
    				}
    				var userCount = data.users.length;
    				var usernames = data.users.map(function (i) {
    					return (i.username === null ? 'Anonymous' : i.username);
    				});
    				var userString = usernames.join('; ');
    
    				self.dom.onlineUsers.find('.panel-body').text(userString);
    				self.dom.onlineUsers.find('.panel-title').text('Users (' + userCount + ')');
    			});
    
    			setInterval(update, 10000);
    		}
    	};
    
    	function setupDom(container) {
    		this.dom = {};
    		this.dom.container = container;
    		this.dom.overlay = container.find('.shoutbox-content-overlay');
    		this.dom.overlayMessage = this.dom.overlay.find('.shoutbox-content-overlay-message');
    		this.dom.shoutsContainer = container.find('.shoutbox-content');
    		this.dom.settingsMenu = container.find('.shoutbox-settings-menu');
    		this.dom.textInput = container.find('.shoutbox-message-input');
    		this.dom.sendButton = container.find('.shoutbox-message-send-btn');
    		this.dom.onlineUsers = container.parents('.shoutbox-row').find('.shoutbox-users');
    
    		if (this.options.showUserPanel) {
    			this.showUserPanel();
    			this.startUserPanelUpdater();
    		}
    	}
    
    	function setupVars() {
    		this.vars = {
    			lastUid: -1,
    			lastSid: -1,
    			scrollBreakpoint: 50,
    			messages: {
    				alert: '[%u] - New Msg !',
    				empty: 'La shoutbox est vide, commencez à discuter !',
    				scrolled: '<a href="#" id="shoutbox-content-overlay-scrolldown">Défiler vers le bas</a>',
    			},
    			userCheck: 0,
    		};
    	}
    
    	Shoutbox.base = {
    		init: function (container, options) {
    			return new Instance(container, options);
    		},
    	};
    }(window.Shoutbox));
    
    

    Continue to search

  • Afk but composer is the main used case for it... I believe it's a self-contained code you can copy over (uses textcomplete I think...?)

  • DownPWD DownPW referenced this topic on
  • @DownPW shoutbox has autocomplete for emojis and usernames now, see how it's done in this commit https://github.com/NodeBB-Community/nodebb-plugin-shoutbox/commit/5e90e3c49d3b7be439b6af7cd72e88ede4d2ef30

  • Ha yes very good things and thank again @baris

    I don't think I would have found the trick

    I will test as soon as possible.

  • Hello @baris

    I have upgrade the plugin to 1.0.7 (upgrade, rebuild and restart, clear cache) but seems to doesn't work

    image.png

    image.png

  • You will need to update composer default to 9.2.5 as well

  • Ok my lord 😀😆

  • Hello @baris

    Thanks again.

    For information, it seems 9.2.5 version is not proposed by default when I use an npm upgrade command :

    npm update nodebb-plugin-composer-default
    

    I must use install command specifying the version number :

    npm install [email protected]
    

    Otherwise, I have just modified the placement of auto-complete on top rather than bottom.
    I find it more elegant. Like this, it does not protrude from the shoutbox. Maybe include it in the github repo ? 😉

    require(['composer/autocomplete'], function (autocomplete) {
    			const data = {
    				element: element,
    				strategies: [],
    				options: {
    					style: {
    						'z-index': 20000,
    						flex: 0,
    						top: 'inherit',
    					},
    					placement: 'top',
    				},
    			};
    

    ba7d0c34-7c1b-4e19-a8c8-2bdba1ea44ef-image.png

    --> Other things : do you think it's easy for me to integrate a hook for another plugin?

  • DownPWD DownPW has marked this topic as solved on
  • Hello @baris

    We have upgrade nodebb 2.8.6 to 2.8.9 and it seems that functionnality is broken now.
    Any suggestion for resolve that ?

    • nodebb 2.8.9
    • nodebb-plugin-composer-default 9.2.5
    • nodebb-plugin-shoutbox 1.0.8

    thanks in advance my friend

  • @DownPW works for me on on those versions. Did you check your browser console for errors?

    image.png

  • There is a permission file problem on nodebb/build/public

    After change permission and rebuild, it's ok now

    Thanks @baris


Suggested Topics