Finished up with css-only flair implementation.
This commit is contained in:
parent
5b5f495853
commit
9dbbc4e924
|
|
@ -1,10 +1,17 @@
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"name": "glitter",
|
"name": "gold",
|
||||||
|
"displayName": "Gold",
|
||||||
"rank": "gold"
|
"rank": "gold"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "negativeGlitter",
|
"name": "black-gold",
|
||||||
"ranke": "gold"
|
"displayName": "Black Gold",
|
||||||
|
"rank": "gold"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "lightning",
|
||||||
|
"displayName": "Lightning",
|
||||||
|
"rank": "gold"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
@ -14,6 +14,10 @@ GNU Affero General Public License for more details.
|
||||||
You should have received a copy of the GNU Affero General Public License
|
You should have received a copy of the GNU Affero General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||||
|
|
||||||
|
//local imports
|
||||||
|
const flairModel = require('../../schemas/flairSchema');
|
||||||
|
const permissionModel = require('../../schemas/permissionSchema');
|
||||||
|
|
||||||
module.exports = class{
|
module.exports = class{
|
||||||
constructor(server, name){
|
constructor(server, name){
|
||||||
this.server = server;
|
this.server = server;
|
||||||
|
|
@ -21,7 +25,7 @@ module.exports = class{
|
||||||
this.userList = new Map();
|
this.userList = new Map();
|
||||||
}
|
}
|
||||||
|
|
||||||
handleConnection(userDB, socket){
|
async handleConnection(userDB, socket){
|
||||||
//get current user object from the userlist
|
//get current user object from the userlist
|
||||||
var userObj = this.userList.get(userDB.user);
|
var userObj = this.userList.get(userDB.user);
|
||||||
|
|
||||||
|
|
@ -45,6 +49,9 @@ module.exports = class{
|
||||||
//if everything looks good, admit the connection to the channel
|
//if everything looks good, admit the connection to the channel
|
||||||
socket.join(socket.chan);
|
socket.join(socket.chan);
|
||||||
|
|
||||||
|
//Make sure the client receives important client-info before userlist
|
||||||
|
await this.sendClientMetadata(userDB, socket);
|
||||||
|
|
||||||
//Send out the userlist
|
//Send out the userlist
|
||||||
this.broadcastUserList(socket.chan);
|
this.broadcastUserList(socket.chan);
|
||||||
}
|
}
|
||||||
|
|
@ -71,13 +78,59 @@ module.exports = class{
|
||||||
this.broadcastUserList(socket.chan);
|
this.broadcastUserList(socket.chan);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async sendClientMetadata(userObj, socket){
|
||||||
|
const flairListDB = await flairModel.find({});
|
||||||
|
var flairList = [];
|
||||||
|
|
||||||
|
const user = {
|
||||||
|
id: userObj.id,
|
||||||
|
user: userObj.user,
|
||||||
|
rank: userObj.rank,
|
||||||
|
flair: userObj.flair
|
||||||
|
}
|
||||||
|
|
||||||
|
flairListDB.forEach((flair)=>{
|
||||||
|
if(permissionModel.rankToNum(flair.rank) <= permissionModel.rankToNum(userObj.rank)){
|
||||||
|
flairList.push({
|
||||||
|
name: flair.name,
|
||||||
|
displayName: flair.displayName
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.emit("clientMetadata", {user, flairList});
|
||||||
|
}
|
||||||
|
|
||||||
broadcastUserList(){
|
broadcastUserList(){
|
||||||
var userList = [];
|
var userList = [];
|
||||||
|
|
||||||
this.userList.forEach((userObj, user) => {
|
this.userList.forEach((userObj, user) => {
|
||||||
userList.push(user);
|
userList.push({
|
||||||
|
user: user,
|
||||||
|
flair: userObj.flair
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
this.server.io.in(this.name).emit("user-list", userList);
|
this.server.io.in(this.name).emit("userList", userList);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateFlair(user, flair){
|
||||||
|
const userObj = this.userList.get(user);
|
||||||
|
|
||||||
|
userObj.flair = flair;
|
||||||
|
|
||||||
|
this.userList.set(user, userObj);
|
||||||
|
|
||||||
|
//Quick hack to make this compatible with sendClientMetadata. make sure we do this AFTER setting the object in the userList map...
|
||||||
|
userObj.name = user;
|
||||||
|
|
||||||
|
//Crawl through user's sockets (lol)
|
||||||
|
userObj.sockets.forEach((sockid) => {
|
||||||
|
//Send metadata to each one
|
||||||
|
const socket = this.server.io.sockets.sockets.get(sockid);
|
||||||
|
this.sendClientMetadata(userObj, socket);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.broadcastUserList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -116,4 +116,19 @@ module.exports = class{
|
||||||
const channel = this.activeChannels.get(socket.chan);
|
const channel = this.activeChannels.get(socket.chan);
|
||||||
return channel.userList.get(socket.user.user);
|
return channel.userList.get(socket.user.user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getConnectedChannels(socket){
|
||||||
|
var chanList = [];
|
||||||
|
|
||||||
|
this.activeChannels.forEach((channel) => {
|
||||||
|
const foundUser = channel.userList.get(socket.user.user);
|
||||||
|
|
||||||
|
//If we found a user and this channel hasn't been added to the list
|
||||||
|
if(foundUser){
|
||||||
|
chanList.push(channel);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return chanList;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -20,7 +20,6 @@ const validator = require('validator');//No express here, so regular validator i
|
||||||
//local imports
|
//local imports
|
||||||
const loggerUtils = require('../../utils/loggerUtils');
|
const loggerUtils = require('../../utils/loggerUtils');
|
||||||
const userModel = require('../../schemas/userSchema');
|
const userModel = require('../../schemas/userSchema');
|
||||||
const channelManager = require('./channelManager');
|
|
||||||
|
|
||||||
module.exports = class{
|
module.exports = class{
|
||||||
constructor(server){
|
constructor(server){
|
||||||
|
|
@ -54,13 +53,20 @@ module.exports = class{
|
||||||
}
|
}
|
||||||
|
|
||||||
async setFlair(socket, data){
|
async setFlair(socket, data){
|
||||||
const userDB = await userModel.findOne({user: socket.user.user});
|
var userDB = await userModel.findOne({user: socket.user.user});
|
||||||
|
const chanList = this.server.getConnectedChannels(socket)
|
||||||
|
|
||||||
if(userDB){
|
if(userDB){
|
||||||
try{
|
try{
|
||||||
//We can take this data raw since our schema checks it against existing flairs, and mongoose sanatizes queries
|
//We can take this data raw since our schema checks it against existing flairs, and mongoose sanatizes queries
|
||||||
userDB.flair = data.flair;
|
userDB.flair = data.flair;
|
||||||
await userDB.save();
|
userDB = await userDB.save();
|
||||||
|
|
||||||
|
chanList.forEach((channel) => {
|
||||||
|
channel.updateFlair(userDB.user, userDB.flair);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
}catch(err){
|
}catch(err){
|
||||||
return loggerUtils.socketExceptionHandler(socket, err);
|
return loggerUtils.socketExceptionHandler(socket, err);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,10 @@ const flairSchema = new mongoose.Schema({
|
||||||
type: mongoose.SchemaTypes.String,
|
type: mongoose.SchemaTypes.String,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
|
displayName:{
|
||||||
|
type: mongoose.SchemaTypes.String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
rank: {
|
rank: {
|
||||||
type: mongoose.SchemaTypes.String,
|
type: mongoose.SchemaTypes.String,
|
||||||
enum: permissionModel.rankEnum,
|
enum: permissionModel.rankEnum,
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,10 @@ userSchema.pre('save', async function (next){
|
||||||
//Throw a shit fit. Do not pass go. Do not collect $200.
|
//Throw a shit fit. Do not pass go. Do not collect $200.
|
||||||
throw new Error("Invalid flair!");
|
throw new Error("Invalid flair!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(permissionModel.rankToNum(this.rank) < permissionModel.rankToNum(foundFlair.rank)){
|
||||||
|
throw new Error(`User '${this.user}' does not have a high enough rank for flair '${foundFlair.displayName}'!`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,4 +15,5 @@ You should have received a copy of the GNU Affero General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.-->
|
along with this program. If not, see <https://www.gnu.org/licenses/>.-->
|
||||||
<link rel="stylesheet" href="/lib/bootstrap-icons/font/bootstrap-icons.css">
|
<link rel="stylesheet" href="/lib/bootstrap-icons/font/bootstrap-icons.css">
|
||||||
<link rel="stylesheet" type="text/css" href="/css/global.css">
|
<link rel="stylesheet" type="text/css" href="/css/global.css">
|
||||||
|
<link rel="stylesheet" type="text/css" href="/css/flair.css">
|
||||||
<link rel="stylesheet" type="text/css" href="/css/theme/movie-night.css">
|
<link rel="stylesheet" type="text/css" href="/css/theme/movie-night.css">
|
||||||
|
|
@ -202,6 +202,7 @@ input#chat-panel-prompt{
|
||||||
.user-entry{
|
.user-entry{
|
||||||
margin: 0.2em;
|
margin: 0.2em;
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
|
width: fit-content;
|
||||||
}
|
}
|
||||||
|
|
||||||
#media-panel-aspect-lock-icon{
|
#media-panel-aspect-lock-icon{
|
||||||
|
|
|
||||||
16
www/css/flair.css
Normal file
16
www/css/flair.css
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
.flair-gold, .flair-black-gold, .flair-lightning{
|
||||||
|
background-image: url('/img/flair/gold.gif');
|
||||||
|
border-radius: 0.3em;
|
||||||
|
box-shadow: 0.1em 0.1em 3px #fff4b6 inset, -0.1em 0.1em 3px #fff4b6 inset, 0.1em -0.1em 3px #fff4b6 inset, -0.1em -0.1em 3px #fff4b6 inset;
|
||||||
|
color: rgb(121, 106, 23);
|
||||||
|
text-shadow: 1px 1px 1px #fff4b6, -1px 1px 1px #fff4b6, 1px -1px 1px #fff4b6, -1px -1px 1px #fff4b6;
|
||||||
|
padding: 0.1em 0.4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flair-black-gold{
|
||||||
|
filter: invert(1) grayscale(0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
.flair-lightning{
|
||||||
|
filter: invert(1) grayscale(0.5);
|
||||||
|
}
|
||||||
BIN
www/img/flair/gold.gif
Normal file
BIN
www/img/flair/gold.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 694 KiB |
|
|
@ -43,9 +43,19 @@ class channel{
|
||||||
document.title = `${this.channelName} - Connected`
|
document.title = `${this.channelName} - Connected`
|
||||||
});
|
});
|
||||||
|
|
||||||
this.socket.on("error", (data) => {
|
this.socket.on("clientMetadata", this.handleClientInfo.bind(this));
|
||||||
console.log(data);
|
|
||||||
});
|
this.socket.on("error", console.log);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleClientInfo(data){
|
||||||
|
this.user = {
|
||||||
|
id: data.user.id,
|
||||||
|
name: data.user.name,
|
||||||
|
rank: data.user.rank
|
||||||
|
}
|
||||||
|
|
||||||
|
this.chatBox.handleClientInfo(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,8 @@ class chatBox{
|
||||||
|
|
||||||
//Element Nodes
|
//Element Nodes
|
||||||
this.chatPanel = document.querySelector("#chat-panel-div");
|
this.chatPanel = document.querySelector("#chat-panel-div");
|
||||||
this.highLevel = document.querySelector("#chat-panel-high-level-select");
|
this.highSelect = document.querySelector("#chat-panel-high-level-select");
|
||||||
|
this.flairSelect = document.querySelector("#chat-panel-flair-select");
|
||||||
this.chatBuffer = document.querySelector("#chat-panel-buffer-div");
|
this.chatBuffer = document.querySelector("#chat-panel-buffer-div");
|
||||||
this.chatPrompt = document.querySelector("#chat-panel-prompt");
|
this.chatPrompt = document.querySelector("#chat-panel-prompt");
|
||||||
this.settingsIcon = document.querySelector("#chat-panel-settings-icon");
|
this.settingsIcon = document.querySelector("#chat-panel-settings-icon");
|
||||||
|
|
@ -57,6 +58,7 @@ class chatBox{
|
||||||
this.aspectLockIcon.addEventListener("click", this.lockAspect.bind(this));
|
this.aspectLockIcon.addEventListener("click", this.lockAspect.bind(this));
|
||||||
this.showChatIcon.addEventListener("click", ()=>{this.toggleUI()});
|
this.showChatIcon.addEventListener("click", ()=>{this.toggleUI()});
|
||||||
this.hideChatIcon.addEventListener("click", ()=>{this.toggleUI()});
|
this.hideChatIcon.addEventListener("click", ()=>{this.toggleUI()});
|
||||||
|
this.flairSelect.addEventListener("change", this.setFlair.bind(this));
|
||||||
|
|
||||||
//Clickdragger/Resize
|
//Clickdragger/Resize
|
||||||
this.clickDragger.handle.addEventListener("mousedown", this.unlockAspect.bind(this));
|
this.clickDragger.handle.addEventListener("mousedown", this.unlockAspect.bind(this));
|
||||||
|
|
@ -69,6 +71,92 @@ class chatBox{
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
displayChat(chat){
|
||||||
|
//Create chat-entry span
|
||||||
|
var chatEntry = document.createElement('span');
|
||||||
|
chatEntry.classList.add("chat-panel-buffer","chat-entry",`chat-entry-${chat.user}`);
|
||||||
|
|
||||||
|
//Create high-level label
|
||||||
|
var highLevel = document.createElement('p');
|
||||||
|
highLevel.classList.add("chat-panel-buffer","chat-entry-high-level");
|
||||||
|
highLevel.innerHTML = `${chat.high}`;
|
||||||
|
chatEntry.appendChild(highLevel);
|
||||||
|
|
||||||
|
//Create username label
|
||||||
|
var userLabel = document.createElement('p');
|
||||||
|
userLabel.classList.add("chat-panel-buffer","chat-entry-username");
|
||||||
|
|
||||||
|
if(chat.flair != ""){
|
||||||
|
var flair = `flair-${chat.flair}`;
|
||||||
|
}else{
|
||||||
|
var flair = this.client.userList.colorMap.get(chat.user);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Create color span
|
||||||
|
var colorSpan = document.createElement('span');
|
||||||
|
colorSpan.classList.add("chat-entry-flair-span", flair);
|
||||||
|
colorSpan.innerHTML = `${chat.user}`;
|
||||||
|
userLabel.innerHTML = `${colorSpan.outerHTML}: `;
|
||||||
|
|
||||||
|
chatEntry.appendChild(userLabel);
|
||||||
|
|
||||||
|
//Create chat body
|
||||||
|
var chatBody = document.createElement('p');
|
||||||
|
chatBody.classList.add("chat-panel-buffer","chat-entry-body");
|
||||||
|
chatBody.innerHTML = chat.msg;
|
||||||
|
chatEntry.appendChild(chatBody);
|
||||||
|
|
||||||
|
this.chatBuffer.appendChild(chatEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
async send(event){
|
||||||
|
if((!event || !event.key || event.key == "Enter") && this.chatPrompt.value){
|
||||||
|
this.client.socket.emit("chatMessage",{msg: this.chatPrompt.value, high: this.highSelect.value});
|
||||||
|
this.chatPrompt.value = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleClientInfo(data){
|
||||||
|
this.updateFlairSelect(data.flairList, data.user.flair);
|
||||||
|
}
|
||||||
|
|
||||||
|
setFlair(event){
|
||||||
|
const flair = event.target.value;
|
||||||
|
|
||||||
|
this.client.socket.emit("setFlair", {flair});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
updateFlairSelect(flairList, flair){
|
||||||
|
//clear current flair select
|
||||||
|
this.flairSelect.innerHTML = "";
|
||||||
|
|
||||||
|
//Inject flair object for standard flair like the hack we are
|
||||||
|
flairList.push({
|
||||||
|
name: "",
|
||||||
|
displayName: "Classic"
|
||||||
|
});
|
||||||
|
|
||||||
|
//For each flair in flairlist
|
||||||
|
flairList.forEach((flair) => {
|
||||||
|
//Create an option
|
||||||
|
var flairOption = document.createElement('option');
|
||||||
|
//Set the name and innerHTML
|
||||||
|
flairOption.value = flair.name;
|
||||||
|
flairOption.innerHTML = flair.displayName;
|
||||||
|
|
||||||
|
//Append it to the select
|
||||||
|
this.flairSelect.appendChild(flairOption);
|
||||||
|
});
|
||||||
|
|
||||||
|
//Set the selected flair in the UI
|
||||||
|
this.flairSelect.value = flair;
|
||||||
|
//Re-style the UI, do this in two seperate steps in-case we're running for the first time and have nothing to replace.
|
||||||
|
this.flairSelect.className = this.flairSelect.className.replace(/flair-\S*/, "");
|
||||||
|
this.flairSelect.classList.add(`flair-${flair}`);
|
||||||
|
}
|
||||||
|
|
||||||
lockAspect(event){
|
lockAspect(event){
|
||||||
//prevent the user from breaking shit :P
|
//prevent the user from breaking shit :P
|
||||||
if(this.chatPanel.style.display != "none"){
|
if(this.chatPanel.style.display != "none"){
|
||||||
|
|
@ -112,44 +200,4 @@ class chatBox{
|
||||||
this.client.player.hideVideoIcon.style.display = "none";
|
this.client.player.hideVideoIcon.style.display = "none";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
displayChat(chat){
|
|
||||||
//Create chat-entry span
|
|
||||||
var chatEntry = document.createElement('span');
|
|
||||||
chatEntry.classList.add("chat-panel-buffer","chat-entry",`chat-entry-${chat.user}`);
|
|
||||||
|
|
||||||
//Create high-level label
|
|
||||||
var highLevel = document.createElement('p');
|
|
||||||
highLevel.classList.add("chat-panel-buffer","chat-entry-high-level");
|
|
||||||
highLevel.innerHTML = `${chat.high}`;
|
|
||||||
chatEntry.appendChild(highLevel);
|
|
||||||
|
|
||||||
//Create username label
|
|
||||||
var userLabel = document.createElement('p');
|
|
||||||
userLabel.classList.add("chat-panel-buffer","chat-entry-username");
|
|
||||||
|
|
||||||
//Create color span
|
|
||||||
var colorSpan = document.createElement('span');
|
|
||||||
colorSpan.classList.add(this.client.userList.colorMap.get(chat.user));
|
|
||||||
colorSpan.innerHTML = `${chat.user}`;
|
|
||||||
userLabel.innerHTML = `${colorSpan.outerHTML}: `;
|
|
||||||
|
|
||||||
chatEntry.appendChild(userLabel);
|
|
||||||
|
|
||||||
//Create chat body
|
|
||||||
var chatBody = document.createElement('p');
|
|
||||||
chatBody.classList.add("chat-panel-buffer","chat-entry-body");
|
|
||||||
chatBody.innerHTML = chat.msg;
|
|
||||||
chatEntry.appendChild(chatBody);
|
|
||||||
|
|
||||||
this.chatBuffer.appendChild(chatEntry);
|
|
||||||
}
|
|
||||||
|
|
||||||
async send(event){
|
|
||||||
if((!event || !event.key || event.key == "Enter") && this.chatPrompt.value){
|
|
||||||
this.client.socket.emit("chatMessage",{msg: this.chatPrompt.value, high: this.highLevel.value});
|
|
||||||
this.chatPrompt.value = "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -53,7 +53,7 @@ class userList{
|
||||||
}
|
}
|
||||||
|
|
||||||
defineListeners(){
|
defineListeners(){
|
||||||
this.client.socket.on('user-list', (data) => {
|
this.client.socket.on('userList', (data) => {
|
||||||
this.updateList(data);
|
this.updateList(data);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -72,12 +72,12 @@ class userList{
|
||||||
var color = this.userColors[Math.floor(Math.random()*this.userColors.length)]
|
var color = this.userColors[Math.floor(Math.random()*this.userColors.length)]
|
||||||
|
|
||||||
//if this user was in the previous colormap
|
//if this user was in the previous colormap
|
||||||
if(this.colorMap.get(user) != null){
|
if(this.colorMap.get(user.user) != null){
|
||||||
//Override with previous color
|
//Override with previous color
|
||||||
color = this.colorMap.get(user);
|
color = this.colorMap.get(user.user);
|
||||||
}
|
}
|
||||||
|
|
||||||
newMap.set(user, color);
|
newMap.set(user.user, color);
|
||||||
this.renderUser(user, color);
|
this.renderUser(user, color);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -87,8 +87,14 @@ class userList{
|
||||||
renderUser(user, color){
|
renderUser(user, color){
|
||||||
var userEntry = document.createElement('p');
|
var userEntry = document.createElement('p');
|
||||||
|
|
||||||
userEntry.innerText = user;
|
userEntry.innerText = user.user;
|
||||||
userEntry.id = `user-entry-${user}`;
|
userEntry.id = `user-entry-${user.user}`;
|
||||||
|
|
||||||
|
//Override color with flair
|
||||||
|
if(user.flair != ""){
|
||||||
|
color = `flair-${user.flair}`;
|
||||||
|
}
|
||||||
|
|
||||||
userEntry.classList.add("chat-panel-users","user-entry",color);
|
userEntry.classList.add("chat-panel-users","user-entry",color);
|
||||||
|
|
||||||
this.userList.appendChild(userEntry);
|
this.userList.appendChild(userEntry);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue