Add whois and conversation as action to user contextmenu
Add Op specific actions to contextMenu Show context menu when left clicking user Switch to using data attributes as selectors remove ban as possible action Move `isOpInChannel()` to utils.js Capitalize strings use CSS.escape for `ownNick` use string interpolation properly point to findCurrentNetworkChan Move context menu item actions to command pattern add icons for context menu actions Make list in context menu always list. remove empty lines in style.css use info circle instead of question circle change context menu labels. change contextMenuActions.execute to more explicit method.
This commit is contained in:
parent
9b75b5727a
commit
33d865501d
@ -224,6 +224,9 @@ kbd {
|
|||||||
.context-menu-chan::before { content: "\f292"; /* http://fontawesome.io/icon/hashtag/ */ }
|
.context-menu-chan::before { content: "\f292"; /* http://fontawesome.io/icon/hashtag/ */ }
|
||||||
.context-menu-close::before { content: "\f00d"; /* http://fontawesome.io/icon/times/ */ }
|
.context-menu-close::before { content: "\f00d"; /* http://fontawesome.io/icon/times/ */ }
|
||||||
.context-menu-list::before { content: "\f03a"; /* http://fontawesome.io/icon/list/ */ }
|
.context-menu-list::before { content: "\f03a"; /* http://fontawesome.io/icon/list/ */ }
|
||||||
|
.context-menu-action-whois::before { content: "\f05a"; /* http://fontawesome.io/icon/info-circle/ */ }
|
||||||
|
.context-menu-action-query::before { content: "\f0e6"; /* http://fontawesome.io/icon/comments-o/ */ }
|
||||||
|
.context-menu-action-kick::before { content: "\f05e"; /* http://fontawesome.io/icon/ban/ */ }
|
||||||
|
|
||||||
.context-menu-network::before,
|
.context-menu-network::before,
|
||||||
#sidebar .chan.lobby::before,
|
#sidebar .chan.lobby::before,
|
||||||
|
@ -79,9 +79,34 @@ $(function() {
|
|||||||
if (target.hasClass("user")) {
|
if (target.hasClass("user")) {
|
||||||
output = templates.contextmenu_item({
|
output = templates.contextmenu_item({
|
||||||
class: "user",
|
class: "user",
|
||||||
|
action: "whois",
|
||||||
text: target.text(),
|
text: target.text(),
|
||||||
data: target.data("name"),
|
data: target.data("name"),
|
||||||
});
|
});
|
||||||
|
output += templates.contextmenu_divider();
|
||||||
|
output += templates.contextmenu_item({
|
||||||
|
class: "action-whois",
|
||||||
|
action: "whois",
|
||||||
|
text: "User information",
|
||||||
|
data: target.data("name"),
|
||||||
|
});
|
||||||
|
output += templates.contextmenu_item({
|
||||||
|
class: "action-query",
|
||||||
|
action: "query",
|
||||||
|
text: "Direct messages",
|
||||||
|
data: target.data("name"),
|
||||||
|
});
|
||||||
|
|
||||||
|
const channel = target.closest(".chan");
|
||||||
|
if (utils.isOpInChannel(channel) && channel.data("type") === "channel") {
|
||||||
|
output += templates.contextmenu_divider();
|
||||||
|
output += templates.contextmenu_item({
|
||||||
|
class: "action-kick",
|
||||||
|
action: "kick",
|
||||||
|
text: "Kick",
|
||||||
|
data: target.data("name"),
|
||||||
|
});
|
||||||
|
}
|
||||||
} else if (target.hasClass("chan")) {
|
} else if (target.hasClass("chan")) {
|
||||||
let itemClass;
|
let itemClass;
|
||||||
|
|
||||||
@ -95,6 +120,7 @@ $(function() {
|
|||||||
|
|
||||||
output = templates.contextmenu_item({
|
output = templates.contextmenu_item({
|
||||||
class: itemClass,
|
class: itemClass,
|
||||||
|
action: "focusChan",
|
||||||
text: target.data("title"),
|
text: target.data("title"),
|
||||||
data: target.data("target"),
|
data: target.data("target"),
|
||||||
});
|
});
|
||||||
@ -102,12 +128,14 @@ $(function() {
|
|||||||
if (target.hasClass("lobby")) {
|
if (target.hasClass("lobby")) {
|
||||||
output += templates.contextmenu_item({
|
output += templates.contextmenu_item({
|
||||||
class: "list",
|
class: "list",
|
||||||
|
action: "list",
|
||||||
text: "List all channels",
|
text: "List all channels",
|
||||||
data: target.data("target"),
|
data: target.data("id"),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
output += templates.contextmenu_item({
|
output += templates.contextmenu_item({
|
||||||
class: "close",
|
class: "close",
|
||||||
|
action: "close",
|
||||||
text: target.hasClass("lobby") ? "Disconnect" : target.hasClass("channel") ? "Leave" : "Close",
|
text: target.hasClass("lobby") ? "Disconnect" : target.hasClass("channel") ? "Leave" : "Close",
|
||||||
data: target.data("target"),
|
data: target.data("target"),
|
||||||
});
|
});
|
||||||
@ -121,7 +149,11 @@ $(function() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
viewport.on("contextmenu", ".user, .network .chan", function(e) {
|
viewport.on("contextmenu", ".network .chan", function(e) {
|
||||||
|
return showContextMenu(this, e);
|
||||||
|
});
|
||||||
|
|
||||||
|
viewport.on("click contextmenu", ".user", function(e) {
|
||||||
return showContextMenu(this, e);
|
return showContextMenu(this, e);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -285,20 +317,6 @@ $(function() {
|
|||||||
$(this).closest(".msg.condensed").toggleClass("closed");
|
$(this).closest(".msg.condensed").toggleClass("closed");
|
||||||
});
|
});
|
||||||
|
|
||||||
chat.on("click", ".user", function() {
|
|
||||||
var name = $(this).data("name");
|
|
||||||
var chan = utils.findCurrentNetworkChan(name);
|
|
||||||
|
|
||||||
if (chan.length) {
|
|
||||||
chan.click();
|
|
||||||
}
|
|
||||||
|
|
||||||
socket.emit("input", {
|
|
||||||
target: chat.data("id"),
|
|
||||||
text: "/whois " + name,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
sidebar.on("click", ".chan, button", function(e, data) {
|
sidebar.on("click", ".chan, button", function(e, data) {
|
||||||
// Pushes states to history web API when clicking elements with a data-target attribute.
|
// Pushes states to history web API when clicking elements with a data-target attribute.
|
||||||
// States are very trivial and only contain a single `clickTarget` property which
|
// States are very trivial and only contain a single `clickTarget` property which
|
||||||
@ -447,24 +465,60 @@ $(function() {
|
|||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
contextMenu.on("click", ".context-menu-item", function() {
|
const contextMenuActions = {
|
||||||
switch ($(this).data("action")) {
|
close: function(itemData) {
|
||||||
case "close":
|
$(`.networks .chan[data-target="${itemData}"] .close`).click();
|
||||||
$(".networks .chan[data-target='" + $(this).data("data") + "'] .close").click();
|
},
|
||||||
break;
|
focusChan: function(itemData) {
|
||||||
case "chan":
|
$(`.networks .chan[data-target="${itemData}"]`).click();
|
||||||
$(".networks .chan[data-target='" + $(this).data("data") + "']").click();
|
},
|
||||||
break;
|
list: function(itemData) {
|
||||||
case "user":
|
|
||||||
$(".channel.active .users .user[data-name='" + $(this).data("data") + "']").click();
|
|
||||||
break;
|
|
||||||
case "list":
|
|
||||||
socket.emit("input", {
|
socket.emit("input", {
|
||||||
target: chat.data("id"),
|
target: itemData,
|
||||||
text: "/list",
|
text: "/list",
|
||||||
});
|
});
|
||||||
break;
|
},
|
||||||
}
|
whois: function(itemData) {
|
||||||
|
const chan = utils.findCurrentNetworkChan(itemData);
|
||||||
|
|
||||||
|
if (chan.length) {
|
||||||
|
chan.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit("input", {
|
||||||
|
target: $("#chat").data("id"),
|
||||||
|
text: "/whois " + itemData,
|
||||||
|
});
|
||||||
|
|
||||||
|
$(`.channel.active .users .user[data-name="${itemData}"]`).click();
|
||||||
|
},
|
||||||
|
query: function(itemData) {
|
||||||
|
const chan = utils.findCurrentNetworkChan(itemData);
|
||||||
|
|
||||||
|
if (chan.length) {
|
||||||
|
chan.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit("input", {
|
||||||
|
target: $("#chat").data("id"),
|
||||||
|
text: "/query " + itemData,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
kick: function(itemData) {
|
||||||
|
socket.emit("input", {
|
||||||
|
target: $("#chat").data("id"),
|
||||||
|
text: "/kick " + itemData,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
contextMenuActions.execute = (name, ...args) => contextMenuActions[name] && contextMenuActions[name](...args);
|
||||||
|
|
||||||
|
contextMenu.on("click", ".context-menu-item", function() {
|
||||||
|
const $this = $(this);
|
||||||
|
const itemData = $this.data("data");
|
||||||
|
const contextAction = $this.data("action");
|
||||||
|
contextMenuActions.execute(contextAction, itemData);
|
||||||
});
|
});
|
||||||
|
|
||||||
chat.on("input", ".search", function() {
|
chat.on("input", ".search", function() {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const $ = require("jquery");
|
const $ = require("jquery");
|
||||||
|
const escape = require("css.escape");
|
||||||
const input = $("#input");
|
const input = $("#input");
|
||||||
|
|
||||||
var serverHash = -1;
|
var serverHash = -1;
|
||||||
@ -19,6 +20,7 @@ module.exports = {
|
|||||||
toggleNickEditor,
|
toggleNickEditor,
|
||||||
toggleNotificationMarkers,
|
toggleNotificationMarkers,
|
||||||
requestIdleCallback,
|
requestIdleCallback,
|
||||||
|
isOpInChannel,
|
||||||
};
|
};
|
||||||
|
|
||||||
function findCurrentNetworkChan(name) {
|
function findCurrentNetworkChan(name) {
|
||||||
@ -37,6 +39,15 @@ function resetHeight(element) {
|
|||||||
element.style.height = element.style.minHeight;
|
element.style.height = element.style.minHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Given a channel element will determine if the lounge user is Op in that channel
|
||||||
|
function isOpInChannel(channel) {
|
||||||
|
const channelID = channel.data("id");
|
||||||
|
const network = $("#sidebar .network").has(`.chan[data-id="${channelID}"]`);
|
||||||
|
const ownNick = network.data("nick");
|
||||||
|
const isOP = channel.find(`.users .user-mode.op .user[data-name="${escape(ownNick)}"]`).length;
|
||||||
|
return isOP;
|
||||||
|
}
|
||||||
|
|
||||||
// Triggering click event opens the virtual keyboard on mobile
|
// Triggering click event opens the virtual keyboard on mobile
|
||||||
// This can only be called from another interactive event (e.g. button click)
|
// This can only be called from another interactive event (e.g. button click)
|
||||||
function forceFocus() {
|
function forceFocus() {
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
<li class="context-menu-item context-menu-{{class}}" data-action="{{class}}"{{#if data}} data-data="{{data}}"{{/if}}>
|
<li class="context-menu-item context-menu-{{class}}" data-action="{{action}}"{{#if data}} data-data="{{data}}"{{/if}}>
|
||||||
{{text}}
|
{{text}}
|
||||||
</li>
|
</li>
|
||||||
|
@ -48,5 +48,6 @@ exports.input = function(network, chan, cmd, args) {
|
|||||||
this.emit("join", {
|
this.emit("join", {
|
||||||
network: network.id,
|
network: network.id,
|
||||||
chan: newChan.getFilteredClone(true),
|
chan: newChan.getFilteredClone(true),
|
||||||
|
shouldOpen: true,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user