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

nodebb-plugin-shoutbox

Package Overview
Dependencies
Maintainers
2
Versions
42
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

nodebb-plugin-shoutbox - npm Package Compare versions

Comparing version 0.3.4 to 1.0.0

.eslintrc

51

lib/commands.js

@@ -1,43 +0,36 @@

"use strict";
'use strict';
var NodeBB = module.require('./nodebb'),
Sockets = require('./sockets'),
const NodeBB = module.require('./nodebb');
const Sockets = require('./sockets');
Commands = {};
const slugify = require.main.require('./src/slugify');
const Commands = {};
Commands.sockets = {
wobble: soundCommand('wobble'),
cena: soundCommand('cena')
cena: soundCommand('cena'),
};
function soundCommand(sound) {
return function(socket, data, callback) {
if (!socket.uid || !data) return callback(new Error('invalid-data'));
return async function (socket, data) {
if (!socket.uid || !data) {
throw new Error('[[error:invalid-data]]');
}
if (data.victim && data.victim.length) {
NodeBB.User.getUidByUserslug(data.victim, function(err, uid) {
if (err) return callback(err);
if (uid) {
//We only update this index when a user requests shouts or sends one
//So we can't guarantee we have the correct socket
//Lucky user who manages to evade this ;)
var userSocket = Sockets.uidIndex[uid];
if (userSocket) {
userSocket.emit('event:shoutbox.' + sound);
}
}
});
const userslug = slugify(data.victim);
const uid = await NodeBB.User.getUidByUserslug(userslug);
if (uid) {
NodeBB.SocketIndex.in(`uid_${uid}`).emit(`event:shoutbox.${sound}`);
}
} else {
socket.emit('event:shoutbox.' + sound);
socket.emit(`event:shoutbox.${sound}`);
}
}
};
}
Object.keys(Commands.sockets).forEach((s) => {
Sockets.events[s] = Commands.sockets[s];
});
for (var s in Commands.sockets) {
if (Commands.sockets.hasOwnProperty(s)) {
Sockets.events[s] = Commands.sockets[s];
}
}
module.exports = Commands;
module.exports = Commands;

@@ -1,65 +0,63 @@

"use strict";
'use strict';
var packageInfo = require('../package.json'),
pluginInfo = require('../plugin.json'),
pluginId = pluginInfo.id.replace('nodebb-plugin-', ''),
const packageInfo = require('../package.json');
const pluginInfo = require('../plugin.json');
NodeBB = require('./nodebb'),
const pluginId = pluginInfo.id.replace('nodebb-plugin-', '');
const NodeBB = require('./nodebb');
async = require('async'),
const Config = {};
Config = {},
const features = [
{
name: 'Gists',
id: 'gist',
description: 'Easily create Gists',
icon: 'fa-github-alt',
button: 'Create Gist',
enabled: true,
},
{
name: 'Archive',
id: 'archive',
description: 'View older posts',
icon: 'fa-archive',
button: 'View Archive',
enabled: true,
},
{
name: 'Bugs',
id: 'bug',
description: 'Report bugs quickly',
icon: 'fa-bug',
button: 'Report Bug',
enabled: false,
},
];
features = [
{
name: 'Gists',
id: 'gist',
description: 'Easily create Gists',
icon: 'fa-github-alt',
button: 'Create Gist',
enabled: true
},
{
name: 'Archive',
id: 'archive',
description: 'View older posts',
icon: 'fa-archive',
button: 'View Archive',
enabled: true
},
{
name: 'Bugs',
id: 'bug',
description: 'Report bugs quickly',
icon: 'fa-bug',
button: 'Report Bug',
enabled: false
}
],
const adminDefaults = {
toggles: {
guestsAllowed: false,
headerLink: false,
features: (function () {
const defaults = {};
features.forEach((el) => {
defaults[el.id] = el.enabled;
});
adminDefaults = {
toggles: {
guestsAllowed: false,
headerLink: false,
features: (function() {
var defaults = {};
features.forEach(function(el) {
defaults[el.id] = el.enabled;
});
return defaults;
})()
},
limits: {
shoutLimit: "25"
},
version: ''
return defaults;
}()),
},
limits: {
shoutLimit: '25',
},
version: '',
};
userDefaults = {
'toggles:sound': 1,
'toggles:notification': 1,
'toggles:hide': 0,
'muted': ''
};
const userDefaults = {
'toggles:sound': 1,
'toggles:notification': 1,
'toggles:hide': 0,
muted: '',
};

@@ -71,17 +69,8 @@ Config.plugin = {

description: packageInfo.description,
icon: 'fa-bullhorn'
icon: 'fa-bullhorn',
};
Config.init = function(callback) {
Config.global = new NodeBB.Settings(Config.plugin.id, Config.plugin.version, adminDefaults, function() {
var oldVersion = Config.global.get('version');
if (oldVersion < Config.plugin.version) {
Config.global.set('version', Config.plugin.version);
Config.global.persist(function() {
require('./upgrade').doUpgrade(oldVersion, Config.plugin.version, callback);
});
} else {
callback();
}
Config.init = function (callback) {
Config.global = new NodeBB.Settings(Config.plugin.id, Config.plugin.version, adminDefaults, () => {
callback();
});

@@ -93,8 +82,8 @@ };

Config.adminSockets = {
sync: function() {
sync: function () {
Config.global.sync();
},
getDefaults: function(socket, data, callback) {
getDefaults: function (socket, data, callback) {
callback(null, Config.global.createDefaultWrapper());
}
},
};

@@ -105,85 +94,71 @@

Config.user.get = function(data, callback) {
if (!data || !data.uid) {
if (parseInt(data.uid, 10) === 0) {
return callback(null, data);
} else {
return callback(new Error('invalid-data'));
}
Config.user.get = async function (data) {
if (!data) {
throw new Error('[[error:invalid-data]]');
}
var prefix = Config.plugin.id + ':';
NodeBB.User.getUserFields(data.uid, Object.keys(userDefaults).map(function(k){
return prefix + k;
}), function(err, result) {
if (err) {
return callback(err);
}
const prefix = `${Config.plugin.id}:`;
if (!data.settings) {
data.settings = {};
}
if (!data.settings) {
data.settings = {};
}
Object.keys(userDefaults).forEach((key) => {
const fullKey = prefix + key;
data.settings[fullKey] = data.settings.hasOwnProperty(fullKey) ? data.settings[fullKey] : userDefaults[key];
});
var fullKey;
for (var key in userDefaults) {
fullKey = prefix + key;
if (userDefaults.hasOwnProperty(key)) {
data.settings[fullKey] = result.hasOwnProperty(fullKey) ? result[fullKey] : userDefaults[key];
}
}
data.settings['shoutbox:shoutLimit'] = parseInt(Config.global.get('limits.shoutLimit'), 10);
return data;
};
data.settings['shoutbox:shoutLimit'] = parseInt(Config.global.get('limits.shoutLimit'), 10);
callback(null, data);
// get user shoutbox settings
Config.user.load = async function (uid) {
const settings = await NodeBB.User.getSettings(uid);
const sbSettings = {};
const prefix = `${Config.plugin.id}:`;
Object.keys(userDefaults).forEach((key) => {
const fullKey = prefix + key;
sbSettings[fullKey] = settings.hasOwnProperty(fullKey) ? settings[fullKey] : userDefaults[key];
});
sbSettings['shoutbox:shoutLimit'] = parseInt(Config.global.get('limits.shoutLimit'), 10);
return sbSettings;
};
Config.user.save = function(data, callback) {
if (!data || !data.uid || !data.settings) {
return callback(new Error('invalid-data'));
Config.user.save = async function (hookData) {
if (!hookData || !hookData.uid || !hookData.settings) {
throw new Error('[[error:invalid-data]]');
}
var prefix = Config.plugin.id + ':';
async.each(Object.keys(userDefaults), function(key, next) {
key = prefix + key;
if (!data.settings.hasOwnProperty(key)) {
return next();
Object.keys(userDefaults).forEach((key) => {
const fullKey = `${Config.plugin.id}:${key}`;
if (hookData.data.hasOwnProperty(fullKey)) {
hookData.settings[fullKey] = hookData.data[fullKey];
}
NodeBB.User.setUserField(data.uid, key, data.settings[key], next);
}, function(err) {
if (err) {
return callback(new Error('invalid-data'));
}
if (typeof(callback) === 'function' && !err) {
// Return the new config with the callback
Config.user.get(data, callback);
}
});
return hookData;
};
Config.user.sockets.getSettings = function(socket, data, callback) {
Config.user.sockets.getSettings = async function (socket) {
if (!socket.uid) {
return callback(new Error('not-logged-in'));
throw new Error('not-logged-in');
}
Config.user.get({uid: socket.uid, settings: {}}, callback);
return {
settings: await Config.user.load(socket.uid),
};
};
Config.user.sockets.saveSettings = function(socket, data, callback) {
Config.user.sockets.saveSettings = async function (socket, data) {
if (!socket.uid || !data || !data.settings) {
return callback(new Error('invalid-data'));
throw new Error('[[error:invalid-data]]');
}
data.uid = socket.uid;
Config.user.save(data, callback);
await NodeBB.api.users.updateSettings(socket, data);
};
Config.getTemplateData = function(callback) {
var featureConfig = Config.global.get('toggles.features'),
data = {};
Config.getTemplateData = function () {
const featureConfig = Config.global.get('toggles.features');
const data = {};
data.features = features.slice(0).map(function(item) {
data.features = features.slice(0).map((item) => {
item.enabled = featureConfig[item.id];

@@ -193,5 +168,5 @@ return item;

callback(data);
return data;
};
module.exports = Config;

@@ -1,15 +0,16 @@

"use strict";
'use strict';
(function(NodeBB) {
module.exports = {
Settings: NodeBB.require('./src/settings'),
Meta: NodeBB.require('./src/meta'),
User: NodeBB.require('./src/user'),
Plugins: NodeBB.require('./src/plugins'),
SocketIndex: NodeBB.require('./src/socket.io/index'),
SocketPlugins: NodeBB.require('./src/socket.io/plugins'),
SocketAdmin: NodeBB.require('./src/socket.io/admin').plugins,
db: NodeBB.require('./src/database'),
winston: NodeBB.require('winston')
}
})(require.main);
module.exports = {
Settings: require.main.require('./src/settings'),
Meta: require.main.require('./src/meta'),
User: require.main.require('./src/user'),
Plugins: require.main.require('./src/plugins'),
SocketIndex: require.main.require('./src/socket.io/index'),
SocketPlugins: require.main.require('./src/socket.io/plugins'),
SocketAdmin: require.main.require('./src/socket.io/admin').plugins,
db: require.main.require('./src/database'),
winston: require.main.require('winston'),
translator: require.main.require('./src/translator'),
utils: require.main.require('./src/utils'),
api: require.main.require('./src/api'),
};

@@ -1,216 +0,168 @@

"use strict";
'use strict';
var NodeBB = require('./nodebb'),
const NodeBB = require('./nodebb');
async = require('async'),
const Shouts = module.exports;
Shouts = {};
Shouts.addShout = function(fromuid, content, callback) {
NodeBB.db.incrObjectField('global', 'nextSid', function(err, sid) {
if (err) return callback(err);
var shout = {
sid: sid,
content: content,
timestamp: Date.now(),
fromuid: fromuid,
deleted: '0'
};
async.parallel([
async.apply(NodeBB.db.setObject, 'shout:' + sid, shout),
async.apply(NodeBB.db.listAppend, 'shouts', sid)
], function(err) {
if (err) return callback(err);
getShouts([sid], callback);
});
});
Shouts.addShout = async function (fromuid, content) {
const sid = await NodeBB.db.incrObjectField('global', 'nextSid');
const shout = {
sid: sid,
content: content,
timestamp: Date.now(),
fromuid: fromuid,
deleted: '0',
};
await Promise.all([
NodeBB.db.setObject(`shout:${sid}`, shout),
NodeBB.db.listAppend('shouts', sid),
]);
return await getShouts([sid]);
};
Shouts.getPlainShouts = function(sids, callback) {
var keys = sids.map(function(sid) {
return 'shout:' + sid;
});
NodeBB.db.getObjects(keys, callback);
Shouts.getPlainShouts = async function (sids) {
const keys = sids.map(sid => `shout:${sid}`);
const shouts = await NodeBB.db.getObjects(keys);
return addSids(shouts, sids);
};
Shouts.getShouts = function(start, end, callback) {
NodeBB.db.getListRange('shouts', start, end, function(err, sids) {
if (err) return callback(err);
if (!Array.isArray(sids) || !sids.length) {
return callback(null, []);
function addSids(shouts, sids) {
shouts.forEach((s, index) => {
if (s && !s.hasOwnProperty('sid')) {
s.sid = sids[index];
}
getShouts(sids, callback);
});
};
return shouts;
}
function getShouts(sids, callback) {
var keys = sids.map(function(sid) {
return 'shout:' + sid;
}), userData, uids,
userFields = ['uid', 'username', 'userslug', 'picture', 'status'];
Shouts.getShouts = async function (start, end) {
const sids = await NodeBB.db.getListRange('shouts', start, end);
if (!Array.isArray(sids) || !sids.length) {
return [];
}
NodeBB.db.getObjects(keys, function(err, shouts) {
if (err) return callback(err);
return await getShouts(sids);
};
// Get a list of unique uids of the users of non-deleted shouts
uids = shouts.map(function(s) {
return parseInt(s.deleted, 10) !== 1 ? parseInt(s.fromuid, 10) : null;
}).filter(function(u, index, self) {
return u === null ? false : self.indexOf(u) === index;
});
async function getShouts(sids) {
const keys = sids.map(sid => `shout:${sid}`);
const shouts = await NodeBB.db.getObjects(keys);
addSids(shouts, sids);
NodeBB.User.getUsersFields(uids, userFields, function(err, usersData) {
if (err) return callback(err);
// Get a list of unique uids of the users of non-deleted shouts
const uniqUids = shouts.map(s => (parseInt(s.deleted, 10) !== 1 ? parseInt(s.fromuid, 10) : null))
.filter((u, index, self) => (u === null ? false : self.indexOf(u) === index));
async.map(shouts, function(shout, next) {
if (parseInt(shout.deleted, 10) === 1) return next();
userData = usersData[uids.indexOf(parseInt(shout.fromuid, 10))];
const usersData = await NodeBB.User.getUsersFields(uniqUids, ['uid', 'username', 'userslug', 'picture', 'status']);
const uidToUserData = {};
uniqUids.forEach((uid, index) => {
uidToUserData[uid] = usersData[index];
});
return await Promise.all(shouts.map(async (shout) => {
if (parseInt(shout.deleted, 10) === 1) {
return null;
}
Shouts.parse(shout.content, userData, function(err, s) {
shout.user = s.user;
shout.content = s.content;
const userData = uidToUserData[parseInt(shout.fromuid, 10)];
next(null, shout);
});
}, callback);
});
});
const s = await Shouts.parse(shout.content, userData);
shout.user = s.user;
shout.content = s.content;
return shout;
}));
}
Shouts.parse = function(raw, userData, callback) {
async.parallel({
parsed: async.apply(NodeBB.Plugins.fireHook, 'filter:parse.raw', raw),
isAdmin: async.apply(NodeBB.User.isAdministrator, userData.uid),
isMod: async.apply(NodeBB.User.isGlobalModerator, userData.uid),
status: function(next) {
NodeBB.User.isOnline(userData.uid, function(err, isOnline) {
next(null, isOnline ? (userData.status || 'online') : 'offline');
});
}
}, function(err, result) {
if (err) {
callback(null, {
user: userData,
content: raw
});
}
Shouts.parse = async function (raw, userData) {
const [parsed, isAdmin, isMod, status] = await Promise.all([
NodeBB.Plugins.hooks.fire('filter:parse.raw', raw),
NodeBB.User.isAdministrator(userData.uid),
NodeBB.User.isGlobalModerator(userData.uid),
NodeBB.User.isOnline(userData.uid),
]);
userData.status = result.status;
userData.isAdmin = result.isAdmin;
userData.isMod = result.isMod;
userData.status = status ? (userData.status || 'online') : 'offline';
userData.isAdmin = isAdmin;
userData.isMod = isMod;
return {
user: userData,
content: parsed,
};
};
callback(null, {
user: userData,
content: result.parsed
});
});
Shouts.removeShout = async function (sid, uid) {
const [isAdmin, isMod, fromUid] = await Promise.all([
NodeBB.User.isAdministrator(uid),
NodeBB.User.isGlobalModerator(uid),
NodeBB.db.getObjectField(`shout:${sid}`, 'fromuid'),
]);
if (isAdmin || isMod || parseInt(fromUid, 10) === parseInt(uid, 10)) {
await NodeBB.db.setObjectField(`shout:${sid}`, 'deleted', '1');
return true;
}
throw new Error('[[error:no-privileges]]');
};
Shouts.removeShout = function(sid, uid, callback) {
async.parallel({
isAdmin: async.apply(NodeBB.User.isAdministrator, uid),
isMod: async.apply(NodeBB.User.isGlobalModerator, uid),
fromUid: async.apply(NodeBB.db.getObjectField, 'shout:' + sid, 'fromuid')
}, function(err, result) {
if (err) return callback(err);
Shouts.editShout = async function (sid, msg, uid) {
const [isAdmin, isMod, fromUid] = await Promise.all([
NodeBB.User.isAdministrator(uid),
NodeBB.User.isGlobalModerator(uid),
NodeBB.db.getObjectField(`shout:${sid}`, 'fromuid'),
]);
if (result.isAdmin || result.isMod || parseInt(result.fromUid, 10) === parseInt(uid, 10)) {
NodeBB.db.setObjectField('shout:' + sid, 'deleted', '1', function (err, result) {
if (err) return callback(err);
return callback(null, true);
});
} else {
return callback(new Error('not-authorized'));
}
});
if (isAdmin || isMod || parseInt(fromUid, 10) === parseInt(uid, 10)) {
await NodeBB.db.setObjectField(`shout:${sid}`, 'content', msg);
return await getShouts([sid]);
}
throw new Error('[[error:no-privileges]]');
};
Shouts.editShout = function(sid, msg, uid, callback) {
async.parallel({
isAdmin: async.apply(NodeBB.User.isAdministrator, uid),
isMod: async.apply(NodeBB.User.isGlobalModerator, uid),
fromUid: async.apply(NodeBB.db.getObjectField, 'shout:' + sid, 'fromuid')
}, function(err, result) {
if (err) return callback(err);
Shouts.pruneDeleted = async function (uid) {
const isAdmin = await NodeBB.User.isAdministrator(uid);
if (!isAdmin) {
throw new Error('[[error:no-privileges]]');
}
if (result.isAdmin || result.isMod || parseInt(result.fromUid, 10) === parseInt(uid, 10)) {
NodeBB.db.setObjectField('shout:' + sid, 'content', msg, function(err, result) {
if (err) return callback(err);
const sids = await NodeBB.db.getListRange('shouts', 0, -1);
if (!sids || !sids.length) {
return;
}
getShouts([sid], callback);
});
} else {
return callback(new Error('not-authorized'));
const keys = sids.map(sid => `shout:${sid}`);
const items = await NodeBB.db.getObjectsFields(keys, ['deleted']);
const toDelete = [];
items.forEach((shout, index) => {
shout.sid = sids[index];
if (parseInt(shout.deleted, 10) === 1) {
toDelete.push(shout);
}
});
};
Shouts.pruneDeleted = function(uid, callback) {
NodeBB.User.isAdministrator(uid, function(err, isAdmin) {
if (!isAdmin) return callback(new Error('not-authorized'));
NodeBB.db.getListRange('shouts', 0, -1, function(err, sids) {
if (err || !sids || !sids.length) return callback(err);
var keys = sids.map(function(sid) {
return 'shout:' + sid;
});
NodeBB.db.getObjectsFields(keys, ['sid', 'deleted'], function(err, items) {
async.map(items, function(item, next) {
if (parseInt(item.deleted, 10) === 0) {
return next();
}
NodeBB.db.listRemoveAll('shouts', item.sid, function(err, result) {
next(null, item.sid);
});
}, function(err, sids) {
var keys = sids.map(function(sid) {
return 'shout:' + sid;
});
NodeBB.db.deleteAll(keys, function(err, result) {
if (err) return callback(err);
callback(null, true);
});
});
});
});
});
await Promise.all([
NodeBB.db.listRemoveAll('shouts', toDelete.map(s => s.sid)),
NodeBB.db.deleteAll(toDelete.map(s => `shout:${s.sid}`)),
]);
return true;
};
Shouts.removeAll = function(uid, callback) {
NodeBB.User.isAdministrator(uid, function(err, isAdmin) {
if (!isAdmin) return callback(new Error('not-authorized'));
Shouts.removeAll = async function (uid) {
const isAdmin = await NodeBB.User.isAdministrator(uid);
if (!isAdmin) {
throw new Error('not-authorized');
}
NodeBB.db.getListRange('shouts', 0, -1, function (err, sids) {
if (err || !sids || !sids.length) return callback(err);
const sids = await NodeBB.db.getListRange('shouts', 0, -1);
if (!sids || !sids.length) {
return;
}
var keys = sids.map(function (sid) {
return 'shout:' + sid;
});
const keys = sids.map(sid => `shout:${sid}`);
async.parallel([
async.apply(NodeBB.db.deleteAll, keys),
async.apply(NodeBB.db.delete, 'shouts'),
async.apply(NodeBB.db.setObjectField, 'global', 'nextSid', 0)
], function(err, result) {
if (err) return callback(err);
callback(null, true);
});
});
});
await Promise.all([
NodeBB.db.deleteAll(keys),
NodeBB.db.delete('shouts'),
NodeBB.db.setObjectField('global', 'nextSid', 0),
]);
return true;
};
module.exports = Shouts;

@@ -1,12 +0,10 @@

"use strict";
'use strict';
var Config = require('./config'),
Shouts = require('./shouts'),
const Config = require('./config');
const Shouts = require('./shouts');
NodeBB = require('./nodebb'),
const NodeBB = require('./nodebb');
S = require('string'),
const Sockets = module.exports;
Sockets = {};
Sockets.events = {

@@ -22,15 +20,13 @@ get: getShouts,

getSettings: Config.user.sockets.getSettings,
saveSetting: Config.user.sockets.saveSettings
saveSetting: Config.user.sockets.saveSettings,
};
Sockets.uidIndex = {};
async function getShouts(socket, data) {
const shoutLimit = parseInt(Config.global.get('limits.shoutLimit'), 10);
const guestsAllowed = Boolean(Config.global.get('toggles.guestsAllowed'));
let start = (-shoutLimit);
let end = -1;
function getShouts(socket, data, callback) {
var shoutLimit = parseInt(Config.global.get('limits.shoutLimit'), 10),
guestsAllowed = Boolean(Config.global.get('toggles.guestsAllowed')),
start = (-shoutLimit),
end = -1;
if (data && data.start) {
var parsedStart = parseInt(data.start, 10);
const parsedStart = parseInt(data.start, 10);

@@ -43,84 +39,65 @@ if (!isNaN(parsedStart)) {

if (!socket.uid && !guestsAllowed) {
return callback(null, []);
if (socket.uid <= 0 && !guestsAllowed) {
return [];
}
Shouts.getShouts(start, end, callback);
updateUidIndex(socket);
return await Shouts.getShouts(start, end);
}
function sendShout(socket, data, callback) {
async function sendShout(socket, data) {
if (!socket.uid || !data || !data.message || !data.message.length) {
return callback(new Error('invalid-data'));
throw new Error('[[error:invalid-data]]');
}
var msg = S(data.message).stripTags().trim().s;
const msg = NodeBB.utils.stripHTMLTags(data.message, NodeBB.utils.stripTags);
if (msg.length) {
Shouts.addShout(socket.uid, msg, function(err, shout) {
if (err) return callback(err);
emitEvent('event:shoutbox.receive', shout);
callback(null, true);
});
updateUidIndex(socket);
const shout = await Shouts.addShout(socket.uid, msg);
emitEvent('event:shoutbox.receive', shout);
return true;
}
}
function editShout(socket, data, callback) {
if (!socket.uid || !data || !data.sid
|| isNaN(parseInt(data.sid, 10))
|| !data.edited || !data.edited.length) {
return callback(new Error('invalid-data'));
async function editShout(socket, data) {
if (!socket.uid || !data || !data.sid || isNaN(parseInt(data.sid, 10)) || !data.edited || !data.edited.length) {
throw new Error('[[error:invalid-data]]');
}
var msg = S(data.edited).stripTags().s;
const msg = NodeBB.utils.stripHTMLTags(data.edited, NodeBB.utils.stripTags);
if (msg.length) {
Shouts.editShout(data.sid, msg, socket.uid, function(err, result) {
if (err) return callback(err);
emitEvent('event:shoutbox.edit', result);
callback(err, true);
});
updateUidIndex(socket);
const result = await Shouts.editShout(data.sid, msg, socket.uid);
emitEvent('event:shoutbox.edit', result);
return true;
}
}
function getPlainShout(socket, data, callback) {
async function getPlainShout(socket, data) {
if (!socket.uid || !data || !data.sid || isNaN(parseInt(data.sid, 10))) {
return callback(new Error('invalid-data'));
throw new Error('[[error:invalid-data]]');
}
Shouts.getPlainShouts([data.sid], callback);
return await Shouts.getPlainShouts([data.sid]);
}
function removeShout(socket, data, callback) {
async function removeShout(socket, data) {
if (!socket.uid || !data || !data.sid || isNaN(parseInt(data.sid, 10))) {
return callback(new Error('invalid-data'));
throw new Error('[[error:invalid-data]]');
}
Shouts.removeShout(data.sid, socket.uid, function(err, result) {
if (result === true) {
emitEvent('event:shoutbox.delete', {sid: data.sid});
}
callback(err, result);
});
const result = await Shouts.removeShout(data.sid, socket.uid);
if (result === true) {
emitEvent('event:shoutbox.delete', { sid: data.sid });
}
return result;
}
function removeAllShouts(socket, data, callback) {
async function removeAllShouts(socket, data) {
if (!socket.uid || !data || !data.which || !data.which.length) {
return callback(new Error('invalid-data'));
throw new Error('[[error:invalid-data]]');
}
switch (data.which) {
case 'all':
Shouts.removeAll(socket.uid, callback);
break;
case 'deleted':
Shouts.pruneDeleted(socket.uid, callback);
break;
default:
callback(new Error('invalid-data'));
if (data.which === 'all') {
return await Shouts.removeAll(socket.uid);
} else if (data.which === 'deleted') {
return await Shouts.pruneDeleted(socket.uid);
}
throw new Error('invalid-data');
}

@@ -134,3 +111,3 @@

if (socket.listeners('disconnect').length === 0) {
socket.on('disconnect', function() {
socket.on('disconnect', () => {
notifyStopTyping(socket.uid);

@@ -162,15 +139,1 @@ });

}
function updateUidIndex(socket) {
if (socket.uid && !socket.isBot) {
Sockets.uidIndex[socket.uid] = socket;
if (socket.listeners('disconnect').length === 0) {
socket.on('disconnect', function() {
delete Sockets.uidIndex[socket.uid];
});
}
}
}
module.exports = Sockets;

@@ -1,11 +0,11 @@

"use strict";
'use strict';
var NodeBB = require('./lib/nodebb'),
Config = require('./lib/config'),
Sockets = require('./lib/sockets'),
Commands = require('./lib/commands'),
const NodeBB = require('./lib/nodebb');
const Config = require('./lib/config');
const Sockets = require('./lib/sockets');
require('./lib/commands');
app,
let app;
Shoutbox = {};
const Shoutbox = module.exports;

@@ -16,22 +16,15 @@ Shoutbox.init = {};

Shoutbox.init.load = function(params, callback) {
function renderGlobal(req, res, next) {
Config.getTemplateData(function(data) {
res.render(Config.plugin.id, data);
});
}
Shoutbox.init.load = function (params, callback) {
const { router, middleware } = params;
const routeHelpers = require.main.require('./src/routes/helpers');
routeHelpers.setupPageRoute(router, `/${Config.plugin.id}`, middleware, [], async (req, res) => {
const data = Config.getTemplateData();
res.render(Config.plugin.id, data);
});
function renderAdmin(req, res, next) {
Config.getTemplateData(function(data) {
res.render('admin/plugins/' + Config.plugin.id, data);
});
}
routeHelpers.setupAdminPageRoute(router, `/admin/plugins/${Config.plugin.id}`, middleware, [], async (req, res) => {
const data = Config.getTemplateData();
res.render(`admin/plugins/${Config.plugin.id}`, data);
});
var router = params.router;
router.get('/' + Config.plugin.id, params.middleware.buildHeader, renderGlobal);
router.get('/api/' + Config.plugin.id, renderGlobal);
router.get('/admin/plugins/' + Config.plugin.id, params.middleware.admin.buildHeader, renderAdmin);
router.get('/api/admin/plugins/' + Config.plugin.id, renderAdmin);
NodeBB.SocketPlugins[Config.plugin.id] = Sockets.events;

@@ -45,20 +38,13 @@ NodeBB.SocketAdmin[Config.plugin.id] = Config.adminSockets;

Shoutbox.init.addGlobalNavigation = function(header, callback) {
if (Config.global.get('toggles.headerLink')) {
header.navigation.push({
class: '',
iconClass: 'fa fa-fw ' + Config.plugin.icon,
route: '/' + Config.plugin.id,
text: Config.plugin.name
});
}
callback(null, header);
Shoutbox.init.filterConfigGet = async (config) => {
config.shoutbox = Config.getTemplateData();
config.shoutbox.settings = await Config.user.load(config.uid);
return config;
};
Shoutbox.init.addAdminNavigation = function(header, callback) {
Shoutbox.init.addAdminNavigation = function (header, callback) {
header.plugins.push({
route: '/plugins/' + Config.plugin.id,
route: `/plugins/${Config.plugin.id}`,
icon: Config.plugin.icon,
name: Config.plugin.name
name: Config.plugin.name,
});

@@ -69,10 +55,3 @@

Shoutbox.init.getSounds = function(sounds, callback) {
sounds.push(__dirname + '/public/sounds/shoutbox-notification.mp3');
sounds.push(__dirname + '/public/sounds/shoutbox-wobble.mp3');
sounds.push(__dirname + '/public/sounds/shoutbox-cena.mp3');
callback(null, sounds);
};
Shoutbox.widget.define = function(widgets, callback) {
Shoutbox.widget.define = function (widgets, callback) {
widgets.push({

@@ -82,3 +61,3 @@ name: Config.plugin.name,

description: Config.plugin.description,
content: ''
content: '',
});

@@ -89,38 +68,43 @@

Shoutbox.widget.render = function(widget, callback) {
//Remove any container
Shoutbox.widget.render = async function (widget) {
// Remove any container
widget.data.container = '';
Config.user.get({ uid: widget.uid, settings: {} }, function(err, result) {
Config.getTemplateData(function(data) {
const settings = await Config.user.load(widget.uid);
const data = Config.getTemplateData();
data.hiddenStyle = '';
if (!err && result && result.settings && parseInt(result.settings['shoutbox:toggles:hide'], 10) == 1) {
data.hiddenStyle = 'display: none;';
}
data.hiddenStyle = '';
if (settings && parseInt(settings['shoutbox:toggles:hide'], 10) === 1) {
data.hiddenStyle = 'display: none;';
}
widget.html = await app.renderAsync('shoutbox/panel', data);
return widget;
};
app.render('shoutbox/panel', data, callback);
});
Shoutbox.settings.addUserSettings = async function (settings) {
const html = await app.renderAsync('shoutbox/user/settings', { settings: settings.settings });
settings.customSettings.push({
title: Config.plugin.name,
content: html,
});
return settings;
};
Shoutbox.settings.addUserSettings = function(settings, callback) {
app.render('shoutbox/user/settings', { settings: settings.settings }, function(err, html) {
settings.customSettings.push({
title: Config.plugin.name,
content: html
});
Shoutbox.settings.addUserFieldWhitelist = function (data, callback) {
data.whitelist.push('shoutbox:toggles:sound');
data.whitelist.push('shoutbox:toggles:notification');
data.whitelist.push('shoutbox:toggles:hide');
callback(null, settings);
});
data.whitelist.push('shoutbox:muted');
callback(null, data);
};
Shoutbox.settings.getUserSettings = function(data, callback) {
Config.user.get(data, callback);
Shoutbox.settings.filterUserGetSettings = async function (data) {
return await Config.user.get(data);
};
Shoutbox.settings.saveUserSettings = function(data) {
Config.user.save(data);
Shoutbox.settings.filterUserSaveSettings = async function (hookData) {
return await Config.user.save(hookData);
};
module.exports = Shoutbox;
{
"name": "nodebb-plugin-shoutbox",
"version": "0.3.4",
"version": "1.0.0",
"description": "NodeBB Shoutbox Plugin",
"main": "library.js",
"scripts": {
"lint": "eslint .",
"test": "echo \"Error: no test specified\" && exit 1"

@@ -27,5 +28,10 @@ },

},
"devDependencies": {
"eslint": "7.32.0",
"eslint-config-nodebb": "^0.0.2",
"eslint-plugin-import": "^2.24.2"
},
"nbbpm": {
"compatibility": "^1.6.1"
"compatibility": "^1.18.3"
}
}

@@ -9,9 +9,10 @@ {

{ "hook": "static:app.load", "method": "init.load" },
{ "hook": "filter:config.get", "method": "init.filterConfigGet" },
{ "hook": "filter:admin.header.build", "method": "init.addAdminNavigation" },
{ "hook": "filter:header.build", "method": "init.addGlobalNavigation" },
{ "hook": "filter:sounds.get", "method": "init.getSounds" },
{ "hook": "filter:user.customSettings", "method": "settings.addUserSettings" },
{ "hook": "filter:user.getSettings", "method": "settings.getUserSettings" },
{ "hook": "action:user.saveSettings", "method": "settings.saveUserSettings" },
{ "hook": "filter:user.getSettings", "method": "settings.filterUserGetSettings" },
{ "hook": "filter:user.saveSettings", "method": "settings.filterUserSaveSettings" },
{ "hook": "filter:user.whitelistFields", "method": "settings.addUserFieldWhitelist" },

@@ -22,3 +23,4 @@ { "hook": "filter:widgets.getWidgets", "method": "widget.define" },

"staticDirs": {
"public": "./public"
"public": "./public",
"assets": "./assets"
},

@@ -35,3 +37,4 @@ "less": [

],
"languages": "languages",
"templates": "./templates"
}
'use strict';
/* globals $, app, socket */
define('admin/plugins/shoutbox', ['settings'], function(Settings) {
define('admin/plugins/shoutbox', ['settings'], function (Settings) {
var wrapper;

@@ -9,3 +8,3 @@

ACP.init = function() {
ACP.init = function () {
wrapper = $('.shoutbox-settings');

@@ -15,3 +14,3 @@

$('#save').on('click', function() {
$('#save').on('click', function () {
save();

@@ -24,3 +23,3 @@ });

function save() {
Settings.persist('shoutbox', wrapper, function() {
Settings.persist('shoutbox', wrapper, function () {
socket.emit('admin.plugins.shoutbox.sync');

@@ -31,11 +30,10 @@ });

function prepareButtons() {
$('#shoutbox-remove-deleted-button').off('click').on('click', function(e) {
bootbox.confirm('Are you sure you wish to remove all shouts marked as deleted from the database?', function(confirm) {
$('#shoutbox-remove-deleted-button').off('click').on('click', function () {
bootbox.confirm('Are you sure you wish to remove all shouts marked as deleted from the database?', function (confirm) {
if (confirm) {
socket.emit('plugins.shoutbox.removeAll', {'which':'deleted'}, function(err, result) {
if(err) {
socket.emit('plugins.shoutbox.removeAll', { which: 'deleted' }, function (err) {
if (err) {
return app.alertError(err.message);
} else {
return app.alertSuccess('Successfully removed all shouts marked as deleted from the database');
}
app.alertSuccess('Successfully removed all shouts marked as deleted from the database');
});

@@ -46,11 +44,10 @@ }

$('#shoutbox-remove-all-button').off('click').on('click', function(e) {
bootbox.confirm('Are you sure you wish to remove all shouts from the database?', function(confirm) {
$('#shoutbox-remove-all-button').off('click').on('click', function () {
bootbox.confirm('Are you sure you wish to remove all shouts from the database?', function (confirm) {
if (confirm) {
socket.emit('plugins.shoutbox.removeAll', {'which':'all'}, function(err, result) {
if(err) {
socket.emit('plugins.shoutbox.removeAll', { which: 'all' }, function (err) {
if (err) {
return app.alertError(err.message);
} else {
return app.alertSuccess('Successfully removed all shouts from the database');
}
app.alertSuccess('Successfully removed all shouts from the database');
});

@@ -63,2 +60,2 @@ }

return ACP;
});
});

@@ -1,9 +0,9 @@

"use strict";
'use strict';
(function(Shoutbox) {
(function (Shoutbox) {
var allActions = [];
var Actions = function(sbInstance) {
var Actions = function (sbInstance) {
var action;
allActions.forEach(function(actObj) {
allActions.forEach(function (actObj) {
action = new actObj.obj(sbInstance);

@@ -15,15 +15,14 @@ action.register();

};
Shoutbox.actions = {
init: function(sbInstance) {
init: function (sbInstance) {
return new Actions(sbInstance);
},
register: function(name, obj) {
register: function (name, obj) {
allActions.push({
name: name,
obj: obj
obj: obj,
});
}
},
};
})(window.Shoutbox);
}(window.Shoutbox));

@@ -1,13 +0,14 @@

"use strict";
'use strict';
(function(Shoutbox) {
var Bug = function(sbInstance) {
this.register = function() {
sbInstance.dom.container.find('.shoutbox-button-bug').off('click').on('click', function() {
window.open('https://github.com/Schamper/nodebb-plugin-shoutbox/issues/new', '_blank').focus();
(function (Shoutbox) {
var Bug = function (sbInstance) {
this.register = function () {
sbInstance.dom.container.find('.shoutbox-button-bug').off('click').on('click', function () {
window.open('https://github.com/NodeBB-Community/nodebb-plugin-shoutbox/issues/new', '_blank').focus();
});
};
};
Shoutbox.actions.register('bug', Bug);
})(window.Shoutbox);
$(window).on('action:app.load', function () {
Shoutbox.actions.register('bug', Bug);
});
}(window.Shoutbox));

@@ -1,8 +0,7 @@

/* global app, utils, $ */
"use strict";
'use strict';
(function(Shoutbox) {
(function (Shoutbox) {
var DefaultActions = {
typing: function(sbInstance) {
this.register = function() {
typing: function (sbInstance) {
this.register = function () {
sbInstance.dom.container.find('.shoutbox-message-input')

@@ -20,4 +19,4 @@ .off('keyup.typing').on('keyup.typing', handle);

},
overlay: function(sbInstance) {
this.register = function() {
overlay: function (sbInstance) {
this.register = function () {
sbInstance.dom.overlay

@@ -33,10 +32,10 @@ .off('click.overlay', '.shoutbox-content-overlay-close')

},
scrolling: function(sbInstance) {
this.register = function() {
var t,
shoutContent = sbInstance.dom.shoutsContainer;
scrolling: function (sbInstance) {
this.register = function () {
var t;
var shoutContent = sbInstance.dom.shoutsContainer;
shoutContent.scroll(function() {
shoutContent.scroll(function () {
clearTimeout(t);
t = setTimeout(function() {
t = setTimeout(function () {
handle();

@@ -48,3 +47,3 @@ }, 200);

.off('click.overlay', '#shoutbox-content-overlay-scrolldown')
.on('click.overlay', '#shoutbox-content-overlay-scrolldown', function(e) {
.on('click.overlay', '#shoutbox-content-overlay-scrolldown', function () {
shoutContent.scrollTop(

@@ -58,9 +57,9 @@ shoutContent[0].scrollHeight - shoutContent.height()

function handle() {
var shoutContent = sbInstance.dom.shoutsContainer,
shoutOverlay = sbInstance.dom.overlay,
scrollHeight = Shoutbox.utils.getScrollHeight(shoutContent),
var shoutContent = sbInstance.dom.shoutsContainer;
var shoutOverlay = sbInstance.dom.overlay;
var scrollHeight = Shoutbox.utils.getScrollHeight(shoutContent);
overlayActive = shoutOverlay.hasClass('active'),
pastScrollBreakpoint = scrollHeight >= sbInstance.vars.scrollBreakpoint,
scrollMessageShowing = sbInstance.vars.scrollMessageShowing;
var overlayActive = shoutOverlay.hasClass('active');
var pastScrollBreakpoint = scrollHeight >= sbInstance.vars.scrollBreakpoint;
var scrollMessageShowing = sbInstance.vars.scrollMessageShowing;

@@ -76,5 +75,5 @@ if (!overlayActive && pastScrollBreakpoint && !scrollMessageShowing) {

},
send: function(sbInstance) {
this.register = function() {
sbInstance.dom.textInput.off('keypress.send').on('keypress.send', function(e) {
send: function (sbInstance) {
this.register = function () {
sbInstance.dom.textInput.off('keypress.send').on('keypress.send', function (e) {
if (e.which === 13 && !e.shiftKey) {

@@ -85,3 +84,3 @@ handle();

sbInstance.dom.sendButton.off('click.send').on('click.send', function(e){
sbInstance.dom.sendButton.off('click.send').on('click.send', function () {
handle();

@@ -96,3 +95,3 @@ return false;

if (msg.length) {
sbInstance.commands.parse(msg, function(msg) {
sbInstance.commands.parse(msg, function (msg) {
sbInstance.sockets.sendShout({ message: msg });

@@ -105,4 +104,4 @@ });

},
delete: function(sbInstance) {
this.register = function() {
delete: function (sbInstance) {
this.register = function () {
sbInstance.dom.container

@@ -127,6 +126,6 @@ .off('click.delete', '.shoutbox-shout-option-close')

},
edit: function(sbInstance) {
edit: function (sbInstance) {
var self = this;
this.register = function() {
this.register = function () {
function eventsOff() {

@@ -142,7 +141,7 @@ sbInstance.dom.shoutsContainer

sbInstance.dom.shoutsContainer
.on('click.edit', '.shoutbox-shout-option-edit', function() {
.on('click.edit', '.shoutbox-shout-option-edit', function () {
handle(
$(this).parents('[data-sid]').data('sid')
);
}).on('dblclick.edit', '[data-sid]', function() {
}).on('dblclick.edit', '[data-sid]', function () {
handle(

@@ -153,3 +152,3 @@ $(this).data('sid')

sbInstance.dom.textInput.on('keyup.edit', function(e) {
sbInstance.dom.textInput.on('keyup.edit', function (e) {
if (e.which === 38 && !$(this).val()) {

@@ -165,7 +164,7 @@ handle(

sbInstance.dom.textInput.off('textComplete:show').on('textComplete:show', function() {
sbInstance.dom.textInput.off('textComplete:show').on('textComplete:show', function () {
eventsOff();
});
sbInstance.dom.textInput.off('textComplete:hide').on('textComplete:hide', function() {
sbInstance.dom.textInput.off('textComplete:hide').on('textComplete:hide', function () {
eventsOn();

@@ -184,18 +183,26 @@ });

sbInstance.sockets.getOriginalShout({ sid: sid }, function(err, orig) {
sbInstance.sockets.getOriginalShout({ sid: sid }, function (err, orig) {
if (err) {
return app.alertError(err);
}
orig = orig[0].content;
sbInstance.dom.sendButton.off('click.send').on('click.send', function(e){
sbInstance.dom.sendButton.off('click.send').on('click.send', function () {
edit(orig);
}).text('Edit');
sbInstance.dom.textInput.off('keyup.edit').off('keypress.send').on('keypress.send', function(e) {
sbInstance.dom.textInput.off('keyup.edit').off('keypress.send').on('keypress.send', function (e) {
if (e.which === 13 && !e.shiftKey) {
edit(orig);
}
}).on('keyup.edit', function(e) {
}).on('keyup.edit', function (e) {
if (e.currentTarget.value.length === 0) {
self.finish();
}
}).val(orig).focus().putCursorAtEnd().parents('.input-group').addClass('has-warning');
})
.val(orig)
.focus()
.putCursorAtEnd()
.parents('.input-group')
.addClass('has-warning');
});

@@ -224,19 +231,21 @@ }

this.finish = function() {
this.finish = function () {
sbInstance.dom.textInput.val('').parents('.input-group').removeClass('has-warning');
sbInstance.dom.sendButton.text('Send').removeClass('hide');
sbInstance.actions['send'].register();
sbInstance.actions['edit'].register();
sbInstance.actions.send.register();
sbInstance.actions.edit.register();
sbInstance.vars.editing = 0;
};
}
},
};
for (var a in DefaultActions) {
if (DefaultActions.hasOwnProperty(a))
Shoutbox.actions.register(a, DefaultActions[a]);
}
})(window.Shoutbox);
$(window).on('action:app.load', function () {
for (var a in DefaultActions) {
if (DefaultActions.hasOwnProperty(a)) {
Shoutbox.actions.register(a, DefaultActions[a]);
}
}
});
}(window.Shoutbox));

@@ -1,8 +0,7 @@

/* global ajaxify */
"use strict";
'use strict';
(function(Shoutbox) {
var Gist = function(sbInstance) {
this.register = function() {
ajaxify.loadTemplate('shoutbox/features/gist', function(tpl){
(function (Shoutbox) {
var Gist = function (sbInstance) {
this.register = function () {
app.parseAndTranslate('shoutbox/features/gist', {}, function (tpl) {
$(document.body).append(tpl);

@@ -12,7 +11,7 @@

sbInstance.dom.container.find('.shoutbox-button-gist').off('click').on('click', function(e) {
sbInstance.dom.container.find('.shoutbox-button-gist').off('click').on('click', function () {
gistModal.modal('show');
});
gistModal.find('#shoutbox-button-create-gist-submit').off('click').on('click', function(e) {
gistModal.find('#shoutbox-button-create-gist-submit').off('click').on('click', function () {
createGist(gistModal.find('textarea').val(), gistModal);

@@ -22,39 +21,39 @@ });

};
function createGist(code, gistModal) {
if (app.user.uid === null) {
gistModal.modal('hide');
app.alertError('Only registered users can create Gists!', 3000);
return;
}
var json = {
"description": "Gist created from NodeBB shoutbox",
"public": true,
"files": {
"Snippet.txt": {
"content": code
}
}
description: 'Gist created from NodeBB shoutbox',
public: true,
files: {
'Snippet.txt': {
content: code,
},
},
};
$.post('https://api.github.com/gists', JSON.stringify(json), function(data) {
$.post('https://api.github.com/gists', JSON.stringify(json), function (data) {
var input = sbInstance.dom.textInput;
var link = data.html_url;
if (input.val().length > 0) {
link = ' ' + link;
}
input.val(input.val() + link);
gistModal.modal('hide');
gistModal.find('textarea').val('');
app.alertSuccess('Successfully created Gist!', 3000);
}).fail(function(data) {
}).fail(function () {
gistModal.modal('hide');
app.alertError('Error while creating Gist, try again later!', 3000);

@@ -65,3 +64,5 @@ });

Shoutbox.actions.register('gist', Gist);
})(window.Shoutbox);
$(window).on('action:app.load', function () {
Shoutbox.actions.register('gist', Gist);
});
}(window.Shoutbox));

@@ -1,6 +0,6 @@

"use strict";
'use strict';
(function(Shoutbox) {
var Hide = function(sbInstance) {
this.register = function() {
(function (Shoutbox) {
var Hide = function (sbInstance) {
this.register = function () {
sbInstance.settings

@@ -21,4 +21,5 @@ .off('toggles.hide')

};
Shoutbox.actions.register('hide', Hide);
})(window.Shoutbox);
$(window).on('action:app.load', function () {
Shoutbox.actions.register('hide', Hide);
});
}(window.Shoutbox));

@@ -1,6 +0,6 @@

"use strict";
'use strict';
(function(Shoutbox) {
var Settings = function(sbInstance) {
this.register = function() {
(function (Shoutbox) {
var Settings = function (sbInstance) {
this.register = function () {
sbInstance.dom.container

@@ -12,6 +12,6 @@ .off('click', '.shoutbox-settings-menu a')

function handle() {
var el = $(this),
key = el.data('shoutbox-setting'),
statusEl = el.find('span'),
status = statusEl.hasClass('fa-check');
var el = $(this);
var key = el.data('shoutbox-setting');
var statusEl = el.find('span');
var status = statusEl.hasClass('fa-check');

@@ -31,4 +31,5 @@ if (status) {

};
Shoutbox.actions.register('settings', Settings);
})(window.Shoutbox);
$(window).on('action:app.load', function () {
Shoutbox.actions.register('settings', Settings);
});
}(window.Shoutbox));

@@ -1,6 +0,5 @@

"use strict";
/*global templates, Mentions, emojiExtended*/
'use strict';
(function(Shoutbox) {
var Instance = function(container, options) {
(function (Shoutbox) {
var Instance = function (container, options) {
var self = this;

@@ -20,4 +19,7 @@

function getShouts() {
self.sockets.getShouts(function(err, shouts) {
shouts = shouts.filter(function(el) {
self.sockets.getShouts(function (err, shouts) {
if (err) {
return app.alertError(err);
}
shouts = shouts.filter(function (el) {
return el !== null;

@@ -43,10 +45,22 @@ });

Instance.prototype.addShouts = function(shouts) {
var self = this,
lastUid = this.vars.lastUid,
lastSid = this.vars.lastSid,
timeStampUpdates = {},
uid, sid;
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;
shouts = shouts.map(function(el) {
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);

@@ -68,14 +82,5 @@ sid = parseInt(el.sid, 10);

// Do we need to update the user timestamp?
if (el.isChained) {
if (timeStampUpdates[lastSid]) {
delete timeStampUpdates[lastSid];
}
timeStampUpdates[sid] = el.timeString;
}
// Extra classes
el.typeClasses = el.isOwn ? "shoutbox-shout-self " : "";
el.typeClasses += el.user.isAdmin ? "shoutbox-shout-admin " : "";
el.typeClasses = el.isOwn ? 'shoutbox-shout-self ' : '';
el.typeClasses += el.user.isAdmin ? 'shoutbox-shout-admin ' : '';

@@ -91,39 +96,21 @@ lastUid = uid;

templates.parse('shoutbox/shouts', {
shouts: shouts
}, function(html) {
app.parseAndTranslate('shoutbox/shouts', {
shouts: shouts,
}, function (html) {
self.dom.shoutsContainer.append(html);
self.utils.scrollToBottom(shouts.length > 1);
// Chaos begins here
if (Object.keys(timeStampUpdates).length > 0) {
// Get all the user elements that belong to the sids that need their timestamp updated
var userElements = $('[data-sid]').filter(function() {
return timeStampUpdates[$(this).data('sid')] !== undefined;
}).prevUntil('.shoutbox-avatar', '.shoutbox-user');
var i = 0;
for (var sid in timeStampUpdates) {
if (timeStampUpdates.hasOwnProperty(sid)) {
userElements.eq(i).find('span.timeago')
.attr('title', timeStampUpdates[sid])
.data('timeago', null)
.addClass('timeago-update');
i++;
}
}
}
if (jQuery.timeago) {
$('.timeago-update').removeClass('timeago-update').timeago();
}
});
};
Instance.prototype.updateUserStatus = function(uid, status) {
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) {
var getStatus = function (uid) {
self.sockets.getUserStatus(uid, function (err, data) {
if (err) {
return app.alertError(err);
}
setStatus(uid, data.status);

@@ -133,14 +120,10 @@ });

var setStatus = function(uid, status) {
self.dom.shoutsContainer.find('[data-uid="' + uid + '"].shoutbox-avatar').removeClass().addClass('shoutbox-avatar ' + status);
};
if (!uid) {
uid = [];
self.dom.shoutsContainer.find('[data-uid].shoutbox-avatar').each(function(index, el){
uid.push($(el).data('uid'))
self.dom.shoutsContainer.find('[data-uid].shoutbox-avatar').each(function (index, el) {
uid.push($(el).data('uid'));
});
uid = uid.filter(function(el, index) {
uid = uid.filter(function (el, index) {
return uid.indexOf(el) === index;

@@ -151,16 +134,14 @@ });

if (!status) {
if (typeof(uid) === 'number') {
if (typeof uid === 'number') {
getStatus(uid);
} else if (Array.isArray(uid)) {
for (var i = 0, l = uid.length; i < l; i++) {
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 (var i = 0, l = uid.length; i < l; i++) {
setStatus(uid[i], status);
}
} 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);
}

@@ -170,11 +151,11 @@ }

Instance.prototype.showUserPanel = function() {
Instance.prototype.showUserPanel = function () {
this.dom.onlineUsers.parent().removeClass('hidden');
};
Instance.prototype.hideUserPanel = function() {
Instance.prototype.hideUserPanel = function () {
this.dom.onlineUsers.parent().addClass('hidden');
};
Instance.prototype.startUserPanelUpdater = function() {
Instance.prototype.startUserPanelUpdater = function () {
var self = this;

@@ -185,8 +166,11 @@

function update() {
this.sockets.getUsers({ set: 'users:online', after: 0 }, function(err, data) {
var userCount = data.users.length,
usernames = data.users.map(function(i) {
return (i.username === null ? 'Anonymous' : i.username);
}),
userString = usernames.join('; ');
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('; ');

@@ -202,4 +186,2 @@ self.dom.onlineUsers.find('.panel-body').text(userString);

function setupDom(container) {
var self = this;
this.dom = {};

@@ -229,5 +211,5 @@ this.dom.container = container;

empty: 'The shoutbox is empty, start shouting!',
scrolled: '<a href="#" id="shoutbox-content-overlay-scrolldown">Scroll down</a>'
scrolled: '<a href="#" id="shoutbox-content-overlay-scrolldown">Scroll down</a>',
},
userCheck: 0
userCheck: 0,
};

@@ -237,7 +219,7 @@ }

Shoutbox.base = {
init: function(container, options) {
init: function (container, options) {
return new Instance(container, options);
}
},
};
}(window.Shoutbox));
})(window.Shoutbox);

@@ -1,7 +0,8 @@

"use strict";
'use strict';
(function(Shoutbox) {
var regex = /^\/(\w+)\s?(.+)?/, allCommands = {};
(function (Shoutbox) {
var regex = /^\/(\w+)\s?(.+)?/;
var allCommands = {};
var Commands = function(instance) {
var Commands = function (instance) {
this.sb = instance;

@@ -16,3 +17,3 @@ this.commands = {};

}
this.commands[c] = allCommands[c];

@@ -22,8 +23,8 @@ }

};
Commands.prototype.getCommands = function() {
Commands.prototype.getCommands = function () {
return this.commands;
};
Commands.prototype.parse = function(msg, sendShout) {
Commands.prototype.parse = function (msg, sendShout) {
var match = msg.match(regex);

@@ -39,13 +40,12 @@

Shoutbox.commands = {
init: function(instance) {
init: function (instance) {
return new Commands(instance);
},
getCommands: function() {
getCommands: function () {
return allCommands;
},
register: function(command, commandObj) {
register: function (command, commandObj) {
allCommands[command] = commandObj;
}
},
};
})(window.Shoutbox);
}(window.Shoutbox));

@@ -1,13 +0,11 @@

/* global utils */
"use strict";
'use strict';
(function(Shoutbox) {
(function (Shoutbox) {
var ArgumentHandlers = {
username: function(argument) {
username: function (argument) {
if (argument.indexOf('@') === 0) {
argument = argument.slice(1);
}
return utils.slugify(argument);
}
return argument;
},
};

@@ -19,8 +17,8 @@

usage: '/help',
description: 'Displays the available commands'
description: 'Displays the available commands',
},
handlers: {
action: function(argument, sendShout, sbInstance) {
var message = '<strong>Available commands:</strong><br>',
commands = sbInstance.commands.getCommands();
action: function (argument, sendShout, sbInstance) {
var message = '<strong>Available commands:</strong><br>';
var commands = sbInstance.commands.getCommands();

@@ -34,4 +32,4 @@ for (var c in commands) {

sbInstance.utils.showOverlay(message);
}
}
},
},
},

@@ -41,12 +39,12 @@ thisagain: {

usage: '/thisagain',
description: 'Remind the n00bs of the obvious'
description: 'Remind the n00bs of the obvious',
},
handlers: {
action: function(argument, sendShout) {
action: function (argument, sendShout) {
sendShout('This again... Clear your cache and refresh.');
}
}
},
},
},
wobble: soundCommand('wobble', 'WOBULLY SASUGE'),
cena: soundCommand('cena', 'AND HIS NAME IS')
cena: soundCommand('cena', 'AND HIS NAME IS'),
};

@@ -58,26 +56,26 @@

usage: '/' + sound + ' &lt;username&gt;',
description: description
description: description,
},
register: function(sbInstance) {
register: function (sbInstance) {
sbInstance.sockets.registerMessage(sound, 'plugins.shoutbox.' + sound);
sbInstance.sockets.registerEvent('event:shoutbox.' + sound, function() {
sbInstance.utils.playSound(sound);
sbInstance.sockets.registerEvent('event:shoutbox.' + sound, function () {
sbInstance.utils.playSound('shoutbox-' + sound + '.mp3');
});
},
handlers: {
action: function(argument, sendShout, sbInstance) {
action: function (argument, sendShout, sbInstance) {
sbInstance.sockets[sound]({
victim: ArgumentHandlers.username(argument)
victim: ArgumentHandlers.username(argument),
});
}
},
},
};
}
$(window).on('action:app.load', function () {
for (var c in DefaultCommands) {
if (DefaultCommands.hasOwnProperty(c)) {
Shoutbox.commands.register(c, DefaultCommands[c]);
}
}
}
for (var c in DefaultCommands) {
if (DefaultCommands.hasOwnProperty(c)) {
Shoutbox.commands.register(c, DefaultCommands[c]);
}
}
})(window.Shoutbox);
});
}(window.Shoutbox));

@@ -1,6 +0,5 @@

"use strict";
'use strict';
(function(Shoutbox) {
var Settings = function(instance) {
(function (Shoutbox) {
var Settings = function (instance) {
this.sb = instance;

@@ -11,5 +10,5 @@ this.settings = null;

Settings.prototype.load = function() {
Settings.prototype.load = function () {
var self = this;
this.sb.sockets.getSettings(function(err, result) {
this.sb.sockets.getSettings(function (err, result) {
if (err || !result || !result.settings) {

@@ -44,3 +43,3 @@ return;

Settings.prototype.get = function(key) {
Settings.prototype.get = function (key) {
key = formalString(key);

@@ -50,3 +49,3 @@ return this.settings[key];

Settings.prototype.set = function(key, value) {
Settings.prototype.set = function (key, value) {
var fullKey = formalString(key);

@@ -56,3 +55,3 @@ this.settings[fullKey] = value;

if (this.listeners.hasOwnProperty(key)) {
this.listeners[key].forEach(function(cb) {
this.listeners[key].forEach(function (cb) {
cb(value);

@@ -62,3 +61,3 @@ });

this.sb.sockets.saveSettings({settings: this.settings}, function(err, result) {
this.sb.sockets.saveSettings({ settings: this.settings }, function (err) {
if (err) {

@@ -70,3 +69,3 @@ app.alertError('Error saving settings!');

Settings.prototype.on = function(key, callback) {
Settings.prototype.on = function (key, callback) {
if (!this.listeners.hasOwnProperty(key)) {

@@ -81,3 +80,3 @@ this.listeners[key] = [];

Settings.prototype.off = function(key) {
Settings.prototype.off = function (key) {
delete this.listeners[key];

@@ -96,54 +95,7 @@

function inflate(object, startIndex, separator) {
var keys = Object.keys(object),
obj = {};
for (var i = 0, l = keys.length; i < l; i++) {
var cur = keys[i],
parts = cur.split(separator || ':'),
curObj = obj;
for (var j = startIndex || 0; j < parts.length; j++) {
if (typeof curObj[parts[j]] !== 'object' && j !== parts.length - 1) {
curObj = curObj[parts[j]] = {};
} else if (j === parts.length - 1) {
curObj[parts[j]] = object[cur];
} else {
curObj = curObj[parts[j]];
}
}
}
return obj;
}
function deflate(object, separator) {
var result = {},
sep = separator || ':';
function iterate(obj, path) {
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
if (typeof obj[prop] === 'object') {
path.push(prop);
iterate(obj[prop], path);
} else {
result[path.join(sep) + sep + prop] = obj[prop];
}
}
}
}
iterate(object, ['shoutbox']);
return result;
}
Shoutbox.settings = {
init: function(instance) {
init: function (instance) {
return new Settings(instance);
}
},
};
})(window.Shoutbox);
}(window.Shoutbox));

@@ -1,10 +0,8 @@

"use strict";
/*global socket*/
'use strict';
(function(Shoutbox) {
(function (Shoutbox) {
var Messages = {
getShouts: 'plugins.shoutbox.get',
sendShout: 'plugins.shoutbox.send',
removeShout : 'plugins.shoutbox.remove',
removeShout: 'plugins.shoutbox.remove',
editShout: 'plugins.shoutbox.edit',

@@ -17,3 +15,3 @@ notifyStartTyping: 'plugins.shoutbox.startTyping',

getUsers: 'user.loadMore',
getUserStatus: 'user.checkStatus'
getUserStatus: 'user.checkStatus',
};

@@ -27,7 +25,7 @@

onStartTyping: 'event:shoutbox.startTyping',
onStopTyping: 'event:shoutbox.stopTyping'
onStopTyping: 'event:shoutbox.stopTyping',
};
var Handlers = {
defaultSocketHandler: function(message) {
defaultSocketHandler: function (message) {
var self = this;

@@ -44,6 +42,6 @@ this.message = message;

};
}
},
};
var Sockets = function(sbInstance) {
var Sockets = function (sbInstance) {
this.sb = sbInstance;

@@ -55,3 +53,3 @@

this.handlers = {
onReceive: function(data) {
onReceive: function (data) {
sbInstance.addShouts(data);

@@ -63,14 +61,14 @@

},
onDelete: function(data) {
var shout = $('[data-sid="' + data.sid + '"]'),
uid = shout.data('uid'),
onDelete: function (data) {
var shout = $('[data-sid="' + data.sid + '"]');
var uid = shout.data('uid');
prevUser = shout.prev('[data-uid].shoutbox-user'),
prevUserUid = parseInt(prevUser.data('uid'), 10),
var prevUser = shout.prev('[data-uid].shoutbox-user');
var prevUserUid = parseInt(prevUser.data('uid'), 10);
nextShout = shout.next('[data-uid].shoutbox-shout'),
nextShoutUid = parseInt(nextShout.data('uid'), 10),
var nextShout = shout.next('[data-uid].shoutbox-shout');
var nextShoutUid = parseInt(nextShout.data('uid'), 10);
prevUserIsSelf = prevUser.length > 0 && prevUserUid === parseInt(uid, 10),
nextShoutIsSelf = nextShout.length > 0 && nextShoutUid === parseInt(uid, 10);
var prevUserIsSelf = prevUser.length > 0 && prevUserUid === parseInt(uid, 10);
var nextShoutIsSelf = nextShout.length > 0 && nextShoutUid === parseInt(uid, 10);

@@ -99,15 +97,15 @@ if (shout.length > 0) {

},
onEdit: function(data) {
onEdit: function (data) {
$('[data-sid="' + data[0].sid + '"] .shoutbox-shout-text')
.html(data[0].content).addClass('shoutbox-shout-edited');
},
onUserStatusChange: function(data) {
onUserStatusChange: function (data) {
sbInstance.updateUserStatus(data.uid, data.status);
},
onStartTyping: function(data) {
onStartTyping: function (data) {
$('[data-uid="' + data.uid + '"].shoutbox-avatar').addClass('isTyping');
},
onStopTyping: function(data) {
onStopTyping: function (data) {
$('[data-uid="' + data.uid + '"].shoutbox-avatar').removeClass('isTyping');
}
},
};

@@ -128,3 +126,3 @@

Sockets.prototype.registerMessage = function(handle, message) {
Sockets.prototype.registerMessage = function (handle, message) {
if (!this.hasOwnProperty(handle)) {

@@ -135,3 +133,3 @@ this[handle] = new Handlers.defaultSocketHandler(message);

Sockets.prototype.registerEvent = function(event, handler) {
Sockets.prototype.registerEvent = function (event, handler) {
socket.on(event, handler);

@@ -141,7 +139,6 @@ };

Shoutbox.sockets = {
init: function(instance) {
init: function (instance) {
return new Sockets(instance);
}
},
};
})(window.Shoutbox);
}(window.Shoutbox));

@@ -1,38 +0,40 @@

"use strict";
/* global app */
'use strict';
(function(Shoutbox) {
var sounds = null;
var Utils = function(instance) {
(function (Shoutbox) {
var Utils = function (instance) {
this.sb = instance;
};
Utils.prototype.isAnon = function() {
Utils.prototype.isAnon = function () {
return app.user.uid === 0;
};
Utils.prototype.notify = function(data) {
if (parseInt(this.sb.settings.get('toggles.notification'), 10) === 1) {
app.alternatingTitle(this.sb.vars.messages.alert.replace(/%u/g, data.user.username));
Utils.prototype.notify = function (data) {
const shoutboxOnPage = $('#shoutbox-main').length > 0;
if (parseInt(this.sb.settings.get('toggles.notification'), 10) === 1 && shoutboxOnPage) {
window.document.title = $('<div></div>').html(this.sb.vars.messages.alert.replace(/%u/g, data.user.username)).text();
}
if (parseInt(this.sb.settings.get('toggles.sound'), 10) === 1) {
this.playSound('notification');
if (parseInt(this.sb.settings.get('toggles.sound'), 10) === 1 && shoutboxOnPage) {
this.playSound('shoutbox-notification.mp3');
}
};
Utils.prototype.playSound = function(sound) {
var self = this;
if (sounds === null) {
require(['sounds'], function(s) {
sounds = s;
Utils.prototype.playSound = function (file) {
if (!file) {
return;
}
var audio = new Audio(
config.relative_path + '/plugins/nodebb-plugin-shoutbox/assets/sounds/' + file
);
self.playSound(sound);
});
} else {
sounds.playFile('shoutbox-' + sound + '.mp3');
audio.pause();
audio.currentTime = 0;
try {
audio.play();
} catch (err) {
console.error(err);
}
};
Utils.prototype.showOverlay = function(message) {
Utils.prototype.showOverlay = function (message) {
this.sb.dom.overlayMessage.html(message);

@@ -42,10 +44,10 @@ this.sb.dom.overlay.addClass('active');

Utils.prototype.closeOverlay = function() {
Utils.prototype.closeOverlay = function () {
this.sb.dom.overlay.removeClass('active');
};
Utils.prototype.scrollToBottom = function(force) {
var shoutsContainer = this.sb.dom.shoutsContainer,
lastShoutHeight = shoutsContainer.find('[data-sid]:last').height(),
scrollHeight = getScrollHeight(shoutsContainer) - lastShoutHeight;
Utils.prototype.scrollToBottom = function (force) {
var shoutsContainer = this.sb.dom.shoutsContainer;
var lastShoutHeight = shoutsContainer.find('[data-sid]:last').height();
var scrollHeight = getScrollHeight(shoutsContainer) - lastShoutHeight;

@@ -63,15 +65,13 @@ if (scrollHeight < this.sb.vars.scrollBreakpoint || force) {

return (((container[0].scrollHeight - container.scrollTop()) - container.height()) - padding);
} else {
return -1;
}
return -1;
}
Shoutbox.utils = {
init: function(instance) {
init: function (instance) {
return new Utils(instance);
},
getScrollHeight: getScrollHeight
}
getScrollHeight: getScrollHeight,
};
}(window.Shoutbox));
})(window.Shoutbox);

@@ -1,14 +0,16 @@

(function() {
$(window).on('action:widgets.loaded', function() {
if ($('#shoutbox-main').length > 0) {
Shoutbox.init();
}
});
'use strict';
window.Shoutbox = {
init: function() {
Shoutbox.instances.main = Shoutbox.base.init($('#shoutbox-main'), {});
},
instances: {}
};
})();
/* globals Shoutbox */
$(window).on('action:ajaxify.end', function () {
if ($('#shoutbox-main').length > 0) {
Shoutbox.init();
}
});
window.Shoutbox = {
init: function () {
Shoutbox.instances.main = Shoutbox.base.init($('#shoutbox-main'), {});
},
instances: {},
};

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

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