Started work on userlist profile tooltips and context menus.
This commit is contained in:
parent
9df7f52e9e
commit
9a8def18d7
|
|
@ -104,8 +104,8 @@ module.exports = class tokebot{
|
||||||
this.chatHandler.relayTokeWhisper(commandObj.socket, `Please wait ${this.cooldownCounter} seconds before starting a new group toke.`);
|
this.chatHandler.relayTokeWhisper(commandObj.socket, `Please wait ${this.cooldownCounter} seconds before starting a new group toke.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Toke command found, don't send as chat
|
//Toke command found, and there isn't any extra text, don't send as chat (re-create fore.st tokebot behaviour)
|
||||||
return false;
|
return (commandObj.command != `!${commandObj.argumentArray[0]}`)
|
||||||
}else{
|
}else{
|
||||||
//No toke found, send it down the line, because shaming the user is funny
|
//No toke found, send it down the line, because shaming the user is funny
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
42
src/controllers/panel/profileController.js
Normal file
42
src/controllers/panel/profileController.js
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*Canopy - The next generation of stoner streaming software
|
||||||
|
Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as
|
||||||
|
published by the Free Software Foundation, either version 3 of the
|
||||||
|
License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
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/>.*/
|
||||||
|
|
||||||
|
//NPM Imports
|
||||||
|
const {validationResult, matchedData} = require('express-validator');
|
||||||
|
|
||||||
|
//local imports
|
||||||
|
const {userModel} = require('../../schemas/user/userSchema');
|
||||||
|
const {exceptionHandler, errorHandler} = require('../../utils/loggerUtils');
|
||||||
|
|
||||||
|
//root index functions
|
||||||
|
module.exports.get = async function(req, res){
|
||||||
|
try{
|
||||||
|
const validResult = validationResult(req);
|
||||||
|
|
||||||
|
if(validResult.isEmpty()){
|
||||||
|
const data = matchedData(req);
|
||||||
|
const profile = await userModel.findProfile({user: data.user});
|
||||||
|
|
||||||
|
return res.render('partial/panels/profile', {profile});
|
||||||
|
}else{
|
||||||
|
res.status(400);
|
||||||
|
return res.send({errors: validResult.array()})
|
||||||
|
}
|
||||||
|
|
||||||
|
}catch(err){
|
||||||
|
return exceptionHandler(res, err);
|
||||||
|
}
|
||||||
|
}
|
||||||
42
src/controllers/tooltip/profileController.js
Normal file
42
src/controllers/tooltip/profileController.js
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*Canopy - The next generation of stoner streaming software
|
||||||
|
Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as
|
||||||
|
published by the Free Software Foundation, either version 3 of the
|
||||||
|
License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
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/>.*/
|
||||||
|
|
||||||
|
//NPM Imports
|
||||||
|
const {validationResult, matchedData} = require('express-validator');
|
||||||
|
|
||||||
|
//local imports
|
||||||
|
const {userModel} = require('../../schemas/user/userSchema');
|
||||||
|
const {exceptionHandler, errorHandler} = require('../../utils/loggerUtils');
|
||||||
|
|
||||||
|
//root index functions
|
||||||
|
module.exports.get = async function(req, res){
|
||||||
|
try{
|
||||||
|
const validResult = validationResult(req);
|
||||||
|
|
||||||
|
if(validResult.isEmpty()){
|
||||||
|
const data = matchedData(req);
|
||||||
|
const profile = await userModel.findProfile({user: data.user});
|
||||||
|
|
||||||
|
return res.render('partial/tooltip/profile', {profile});
|
||||||
|
}else{
|
||||||
|
res.status(400);
|
||||||
|
return res.send({errors: validResult.array()})
|
||||||
|
}
|
||||||
|
|
||||||
|
}catch(err){
|
||||||
|
return exceptionHandler(res, err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -22,6 +22,9 @@ const { Router } = require('express');
|
||||||
const placeholderController = require("../controllers/panel/placeholderController");
|
const placeholderController = require("../controllers/panel/placeholderController");
|
||||||
const emoteController = require("../controllers/panel/emoteController");
|
const emoteController = require("../controllers/panel/emoteController");
|
||||||
const popoutContainerController = require("../controllers/panel/popoutContainerController");
|
const popoutContainerController = require("../controllers/panel/popoutContainerController");
|
||||||
|
const profileController = require("../controllers/panel/profileController");
|
||||||
|
//Validators
|
||||||
|
const accountValidator = require("../validators/accountValidator");
|
||||||
|
|
||||||
//globals
|
//globals
|
||||||
const router = Router();
|
const router = Router();
|
||||||
|
|
@ -30,5 +33,6 @@ const router = Router();
|
||||||
router.get('/placeholder', placeholderController.get);
|
router.get('/placeholder', placeholderController.get);
|
||||||
router.get('/emote', emoteController.get);
|
router.get('/emote', emoteController.get);
|
||||||
router.get('/popoutContainer', popoutContainerController.get);
|
router.get('/popoutContainer', popoutContainerController.get);
|
||||||
|
router.get('/profile', accountValidator.user(), profileController.get);
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|
|
||||||
|
|
@ -19,14 +19,19 @@ const { Router } = require('express');
|
||||||
|
|
||||||
|
|
||||||
//local imports
|
//local imports
|
||||||
const altListController = require("../controllers/tooltip/altListController");
|
//DB Models
|
||||||
const permissionSchema = require("../schemas/permissionSchema");
|
const permissionModel = require("../schemas/permissionSchema");
|
||||||
|
//Validators
|
||||||
const accountValidator = require("../validators/accountValidator");
|
const accountValidator = require("../validators/accountValidator");
|
||||||
|
//controllers
|
||||||
|
const altListController = require("../controllers/tooltip/altListController");
|
||||||
|
const profileController = require("../controllers/tooltip/profileController");
|
||||||
|
|
||||||
//globals
|
//globals
|
||||||
const router = Router();
|
const router = Router();
|
||||||
|
|
||||||
//routing functions
|
//routing functions
|
||||||
router.get('/altList', accountValidator.user(), permissionSchema.reqPermCheck("adminPanel"), altListController.get);
|
router.get('/altList', accountValidator.user(), permissionModel.reqPermCheck("adminPanel"), altListController.get);
|
||||||
|
router.get('/profile', accountValidator.user(), profileController.get);
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|
|
||||||
32
src/views/partial/panels/profile.ejs
Normal file
32
src/views/partial/panels/profile.ejs
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
<%# Canopy - The next generation of stoner streaming software
|
||||||
|
Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as
|
||||||
|
published by the Free Software Foundation, either version 3 of the
|
||||||
|
License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
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/>. %>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/css/panel/profile.css">
|
||||||
|
<div id="profile-panel">
|
||||||
|
<% if(profile == null){ %>
|
||||||
|
<p>Profile not found!</p>
|
||||||
|
<% }else{ %>
|
||||||
|
<a class="panel profile-link" target="_blank" href="/profile/<%- profile.user %>">View Full Profile<i class="bi-box-arrow-in-up-right"></i></a>
|
||||||
|
<h2 class="panel profile-name"><%- profile.user %></h2>
|
||||||
|
<img class="panel profile-img" src="<%- profile.img %>">
|
||||||
|
<p class="panel profile-info">Toke Count: <%- profile.tokeCount %></p>
|
||||||
|
<% if(profile.pronouns != '' && profile.pronouns != null){ %>
|
||||||
|
<p class="panel profile-info">Pronouns: <%- profile.pronouns %></p>
|
||||||
|
<% } %>
|
||||||
|
<p class="panel profile-info">Signature: <%- profile.signature %></p>
|
||||||
|
<p class="panel profile-bio-label">Bio:</p>
|
||||||
|
<p class="panel profile-bio"><%- profile.bio %></p>
|
||||||
|
<% } %>
|
||||||
|
</div>
|
||||||
|
|
@ -19,6 +19,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. %>
|
||||||
<div class="seperator"></div>
|
<div class="seperator"></div>
|
||||||
<p class="tooltip">User: <%- alts[alt].user %></p>
|
<p class="tooltip">User: <%- alts[alt].user %></p>
|
||||||
<p class="tooltip">ID: <%- alts[alt].id %></p>
|
<p class="tooltip">ID: <%- alts[alt].id %></p>
|
||||||
|
<% if(alts[alt].pronouns != '' && alts[alt].pronouns != null){ %>
|
||||||
|
<p class="tooltip">Pronouns: <%- alts[alt].pronouns %></p>
|
||||||
|
<% } %>
|
||||||
<p class="tooltip">Signature: <%- alts[alt].signature %></p>
|
<p class="tooltip">Signature: <%- alts[alt].signature %></p>
|
||||||
<p class="tooltip">Toke Count: <%- alts[alt].tokeCount %></p>
|
<p class="tooltip">Toke Count: <%- alts[alt].tokeCount %></p>
|
||||||
<p class="tooltip">Joined: <%- alts[alt].date.toLocaleString() %></p>
|
<p class="tooltip">Joined: <%- alts[alt].date.toLocaleString() %></p>
|
||||||
|
|
|
||||||
27
src/views/partial/tooltip/profile.ejs
Normal file
27
src/views/partial/tooltip/profile.ejs
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
<%# Canopy - The next generation of stoner streaming software
|
||||||
|
Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as
|
||||||
|
published by the Free Software Foundation, either version 3 of the
|
||||||
|
License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
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/>. %>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/css/tooltip/profile.css">
|
||||||
|
<% if(profile == null){ %>
|
||||||
|
<p>Profile not found!</p>
|
||||||
|
<% }else{ %>
|
||||||
|
<h2 class="tooltip profile-name"><%- profile.user %></h2>
|
||||||
|
<img class="tooltip profile-img" src="<%- profile.img %>">
|
||||||
|
<p class="tooltip">Toke Count: <%- profile.tokeCount %></p>
|
||||||
|
<% if(profile.pronouns != '' && profile.pronouns != null){ %>
|
||||||
|
<p class="tooltip">Pronouns: <%- profile.pronouns %></p>
|
||||||
|
<% } %>
|
||||||
|
<p class="tooltip">Signature: <%- profile.signature %></p>
|
||||||
|
<% } %>
|
||||||
|
|
@ -187,6 +187,7 @@ p.panel-head-element{
|
||||||
span.user-entry{
|
span.user-entry{
|
||||||
display: flex;
|
display: flex;
|
||||||
margin-bottom: 0.1em;
|
margin-bottom: 0.1em;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-entry{
|
.user-entry{
|
||||||
|
|
@ -238,6 +239,7 @@ span.user-entry{
|
||||||
left: 0;
|
left: 0;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
scrollbar-width: thin;
|
scrollbar-width: thin;
|
||||||
|
width: 75%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#cpanel-pinned-div{
|
#cpanel-pinned-div{
|
||||||
|
|
|
||||||
|
|
@ -161,8 +161,25 @@ div.tooltip{
|
||||||
min-width: 1em;
|
min-width: 1em;
|
||||||
min-height: 1em;
|
min-height: 1em;
|
||||||
padding: 0.5em;
|
padding: 0.5em;
|
||||||
|
z-index: 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
p.tooltip, h3.tooltip{
|
p.tooltip, h3.tooltip{
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* context menu */
|
||||||
|
.context-menu{
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.context-menu h2{
|
||||||
|
margin: 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.context-menu button{
|
||||||
|
margin: 0.05em 0;
|
||||||
|
}
|
||||||
47
www/css/panel/profile.css
Normal file
47
www/css/panel/profile.css
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*Canopy - The next generation of stoner streaming software
|
||||||
|
Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as
|
||||||
|
published by the Free Software Foundation, either version 3 of the
|
||||||
|
License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
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/>.*/
|
||||||
|
#profile-panel{
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel.profile-link{
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel.profile-name{
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel.profile-img{
|
||||||
|
margin: 0 2em;
|
||||||
|
max-height: 20em;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.panel{
|
||||||
|
margin: 0.2em 2em;
|
||||||
|
text-wrap: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel.profile-bio-label{
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel.profile-bio{
|
||||||
|
margin-top: 0;
|
||||||
|
text-wrap: wrap;
|
||||||
|
}
|
||||||
38
www/css/tooltip/profile.css
Normal file
38
www/css/tooltip/profile.css
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*Canopy - The next generation of stoner streaming software
|
||||||
|
Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as
|
||||||
|
published by the Free Software Foundation, either version 3 of the
|
||||||
|
License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
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/>.*/
|
||||||
|
div.tooltip{
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip .profile-img{
|
||||||
|
max-width: 6em;
|
||||||
|
max-height: 6em;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip .profile-name{
|
||||||
|
text-align: center;
|
||||||
|
margin: 0;
|
||||||
|
text-wrap: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip p{
|
||||||
|
text-align: left;
|
||||||
|
width: 100%;
|
||||||
|
text-wrap: nowrap;
|
||||||
|
}
|
||||||
|
|
@ -307,20 +307,7 @@ class adminUserList{
|
||||||
//Splice username out of class name
|
//Splice username out of class name
|
||||||
const name = userName.id.replace('admin-user-list-name-','');
|
const name = userName.id.replace('admin-user-list-name-','');
|
||||||
|
|
||||||
//When the mouse starts to hover
|
userName.addEventListener('mouseenter',(event)=>{utils.ux.displayTooltip(event, `altList?user=${name}`, true);});
|
||||||
userName.addEventListener('mouseenter',(event)=>{
|
|
||||||
//Create the tooltip
|
|
||||||
const tooltip = new canopyUXUtils.tooltip(`altList?user=${name}`, true);
|
|
||||||
|
|
||||||
//Do intial mouse move
|
|
||||||
tooltip.moveToMouse(event);
|
|
||||||
|
|
||||||
//Move the tooltip with the mouse
|
|
||||||
userName.addEventListener('mousemove', tooltip.moveToMouse.bind(tooltip));
|
|
||||||
|
|
||||||
//remove the tooltip on mouseleave
|
|
||||||
userName.addEventListener('mouseleave', tooltip.remove.bind(tooltip));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for(let rankSelector of this.rankSelectors){
|
for(let rankSelector of this.rankSelectors){
|
||||||
|
|
|
||||||
|
|
@ -140,6 +140,10 @@ class chatBox{
|
||||||
this.displayAutocomplete();
|
this.displayAutocomplete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tokeWith(user){
|
||||||
|
this.commandPreprocessor.preprocess(user == this.client.user.user ? "!toke up fuckers" : `!toke up ${user}`);
|
||||||
|
}
|
||||||
|
|
||||||
send(event){
|
send(event){
|
||||||
if((!event || !event.key || event.key == "Enter") && this.chatPrompt.value){
|
if((!event || !event.key || event.key == "Enter") && this.chatPrompt.value){
|
||||||
this.commandPreprocessor.preprocess(this.chatPrompt.value);
|
this.commandPreprocessor.preprocess(this.chatPrompt.value);
|
||||||
|
|
|
||||||
|
|
@ -101,7 +101,6 @@ class userList{
|
||||||
var highLevel = document.createElement('p');
|
var highLevel = document.createElement('p');
|
||||||
highLevel.classList.add("user-list-high-level","high-level");
|
highLevel.classList.add("user-list-high-level","high-level");
|
||||||
highLevel.innerHTML = `${user.highLevel}`;
|
highLevel.innerHTML = `${user.highLevel}`;
|
||||||
userSpan.appendChild(highLevel);
|
|
||||||
|
|
||||||
//Create nameplate
|
//Create nameplate
|
||||||
var userEntry = document.createElement('p');
|
var userEntry = document.createElement('p');
|
||||||
|
|
@ -115,10 +114,30 @@ class userList{
|
||||||
//Add classes to classList
|
//Add classes to classList
|
||||||
userEntry.classList.add("chat-panel-users","user-entry",flair);
|
userEntry.classList.add("chat-panel-users","user-entry",flair);
|
||||||
|
|
||||||
|
//Add high-level username to nameplate
|
||||||
|
userSpan.appendChild(highLevel);
|
||||||
userSpan.appendChild(userEntry);
|
userSpan.appendChild(userEntry);
|
||||||
|
|
||||||
|
//Setup profile tooltip
|
||||||
|
userSpan.addEventListener('mouseenter',(event)=>{utils.ux.displayTooltip(event, `profile?user=${user.user}`, true, null, true);});
|
||||||
|
|
||||||
|
//Setup profile context menu
|
||||||
|
userSpan.addEventListener('click', renderContextMenu.bind(this));
|
||||||
|
userSpan.addEventListener('contextmenu', renderContextMenu.bind(this));
|
||||||
|
|
||||||
this.userList.appendChild(userSpan);
|
this.userList.appendChild(userSpan);
|
||||||
|
|
||||||
|
function renderContextMenu(event){
|
||||||
|
//Setup menu map
|
||||||
|
let menuMap = new Map([
|
||||||
|
["Profile", ()=>{this.client.cPanel.setActivePanel(new panelObj(client, `${user.user}`, `/panel/profile?user=${user.user}`))}],
|
||||||
|
["Mention", ()=>{client.chatBox.catChat(`${user.user} `)}],
|
||||||
|
["Toke With", ()=>{client.chatBox.tokeWith(user.user)}],
|
||||||
|
]);
|
||||||
|
|
||||||
|
//Display the menu
|
||||||
|
utils.ux.displayContextMenu(event, user.user, menuMap);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleUI(show = !this.userDiv.checkVisibility()){
|
toggleUI(show = !this.userDiv.checkVisibility()){
|
||||||
|
|
|
||||||
|
|
@ -34,13 +34,51 @@ class canopyUXUtils{
|
||||||
new canopyUXUtils.popup(`<h3>Server Error:</h3><p><br>${err.msg}</p>`);
|
new canopyUXUtils.popup(`<h3>Server Error:</h3><p><br>${err.msg}</p>`);
|
||||||
});
|
});
|
||||||
}catch(err){
|
}catch(err){
|
||||||
console.error("Display Error Error:");
|
console.error("Display Error Body:");
|
||||||
console.error(body);
|
console.error(body);
|
||||||
console.error("Display Error Error:");
|
console.error("Display Error Error:");
|
||||||
console.error(err);
|
console.error(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
displayTooltip(event, content, ajaxTooltip, cb, soft = false){
|
||||||
|
//Create the tooltip
|
||||||
|
const tooltip = new canopyUXUtils.tooltip(content, ajaxTooltip, ()=>{
|
||||||
|
//Call mouse move again after ajax load to re-calculate position within context of the new content
|
||||||
|
tooltip.moveToMouse(event);
|
||||||
|
//If we have a callback function
|
||||||
|
if(typeof cb == "function"){
|
||||||
|
//Call async callback
|
||||||
|
cb();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//Move the tooltip with the mouse
|
||||||
|
event.target.addEventListener('mousemove', tooltip.moveToMouse.bind(tooltip));
|
||||||
|
|
||||||
|
//Do intial mouse move
|
||||||
|
tooltip.moveToMouse(event);
|
||||||
|
|
||||||
|
//remove the tooltip on mouseleave
|
||||||
|
event.target.addEventListener('mouseleave', tooltip.remove.bind(tooltip));
|
||||||
|
|
||||||
|
if(soft){
|
||||||
|
//remove the tooltip on context menu open
|
||||||
|
event.target.addEventListener('click', tooltip.remove.bind(tooltip));
|
||||||
|
event.target.addEventListener('contextmenu', tooltip.remove.bind(tooltip));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
displayContextMenu(event, title, menuMap){
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
//Create context menu
|
||||||
|
const contextMenu = new canopyUXUtils.contextMenu(title, menuMap);
|
||||||
|
|
||||||
|
//Move context menu to mouse
|
||||||
|
contextMenu.moveToMouse(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//We should really move this over to uxutils along with newrow & newtable functions
|
//We should really move this over to uxutils along with newrow & newtable functions
|
||||||
newTableCell(content, firstCol = false){
|
newTableCell(content, firstCol = false){
|
||||||
|
|
@ -174,6 +212,50 @@ class canopyUXUtils{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static contextMenu = class extends this.tooltip{
|
||||||
|
constructor(title, menuMap){
|
||||||
|
//Call inherited tooltip constructor
|
||||||
|
super('Loading Menu...');
|
||||||
|
//Set tooltip class
|
||||||
|
this.tooltip.classList.add('context-menu');
|
||||||
|
|
||||||
|
//Set title and menu map
|
||||||
|
this.title = title;
|
||||||
|
this.menuMap = menuMap;
|
||||||
|
|
||||||
|
this.constructMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
constructMenu(){
|
||||||
|
//Clear out tooltip
|
||||||
|
this.tooltip.innerHTML = '';
|
||||||
|
|
||||||
|
//Create menu title
|
||||||
|
const menuTitle = document.createElement('h2');
|
||||||
|
menuTitle.innerHTML = this.title;
|
||||||
|
|
||||||
|
//Append the title to the tooltip
|
||||||
|
this.tooltip.append(menuTitle);
|
||||||
|
|
||||||
|
for(let choice of this.menuMap){
|
||||||
|
//Create button
|
||||||
|
const button = document.createElement('button');
|
||||||
|
button.innerHTML = choice[0];
|
||||||
|
|
||||||
|
//Add event listeners
|
||||||
|
button.addEventListener('click', choice[1]);
|
||||||
|
|
||||||
|
//Append the button to the menu div
|
||||||
|
this.tooltip.appendChild(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Create event listener to remove tooltip whenever anything is clicked, inside or out of the menu
|
||||||
|
//Little hacky but we have to do it a bit later to prevent the opening event from closing the menu
|
||||||
|
setTimeout(()=>{document.body.addEventListener('click', this.remove.bind(this));}, 1);
|
||||||
|
setTimeout(()=>{document.body.addEventListener('contextmenu', this.remove.bind(this));}, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static popup = class{
|
static popup = class{
|
||||||
constructor(content, ajaxPopup = false, cb){
|
constructor(content, ajaxPopup = false, cb){
|
||||||
//Define non-popup node values
|
//Define non-popup node values
|
||||||
|
|
@ -326,7 +408,6 @@ class canopyUXUtils{
|
||||||
}
|
}
|
||||||
|
|
||||||
drag(event){
|
drag(event){
|
||||||
|
|
||||||
if(this.dragLock){
|
if(this.dragLock){
|
||||||
if(this.leftHandle){
|
if(this.leftHandle){
|
||||||
//get difference between mouse and right edge of element
|
//get difference between mouse and right edge of element
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue