nodebb-plugin-shoutbox
Advanced tools
Comparing version 0.3.4 to 1.0.0
@@ -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; |
128
library.js
@@ -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 + ' <username>', | ||
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
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
490762
45
1667
2
0
3
1