Merge pull request #1722 from creesch/contextMenu

Add actions to user context menu
This commit is contained in:
Jérémie Astori 2017-12-11 23:14:54 -05:00 committed by GitHub
commit aeb8f66f30
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 101 additions and 32 deletions

View file

@ -224,6 +224,9 @@ kbd {
.context-menu-chan::before { content: "\f292"; /* http://fontawesome.io/icon/hashtag/ */ }
.context-menu-close::before { content: "\f00d"; /* http://fontawesome.io/icon/times/ */ }
.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,
#sidebar .chan.lobby::before,

View file

@ -79,9 +79,34 @@ $(function() {
if (target.hasClass("user")) {
output = templates.contextmenu_item({
class: "user",
action: "whois",
text: target.text(),
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")) {
let itemClass;
@ -95,6 +120,7 @@ $(function() {
output = templates.contextmenu_item({
class: itemClass,
action: "focusChan",
text: target.data("title"),
data: target.data("target"),
});
@ -102,12 +128,14 @@ $(function() {
if (target.hasClass("lobby")) {
output += templates.contextmenu_item({
class: "list",
action: "list",
text: "List all channels",
data: target.data("target"),
data: target.data("id"),
});
}
output += templates.contextmenu_item({
class: "close",
action: "close",
text: target.hasClass("lobby") ? "Disconnect" : target.hasClass("channel") ? "Leave" : "Close",
data: target.data("target"),
});
@ -121,7 +149,11 @@ $(function() {
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);
});
@ -285,20 +317,6 @@ $(function() {
$(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) {
// 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
@ -447,24 +465,60 @@ $(function() {
return false;
});
contextMenu.on("click", ".context-menu-item", function() {
switch ($(this).data("action")) {
case "close":
$(".networks .chan[data-target='" + $(this).data("data") + "'] .close").click();
break;
case "chan":
$(".networks .chan[data-target='" + $(this).data("data") + "']").click();
break;
case "user":
$(".channel.active .users .user[data-name='" + $(this).data("data") + "']").click();
break;
case "list":
const contextMenuActions = {
close: function(itemData) {
$(`.networks .chan[data-target="${itemData}"] .close`).click();
},
focusChan: function(itemData) {
$(`.networks .chan[data-target="${itemData}"]`).click();
},
list: function(itemData) {
socket.emit("input", {
target: chat.data("id"),
target: itemData,
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() {

View file

@ -1,6 +1,7 @@
"use strict";
const $ = require("jquery");
const escape = require("css.escape");
const input = $("#input");
var serverHash = -1;
@ -19,6 +20,7 @@ module.exports = {
toggleNickEditor,
toggleNotificationMarkers,
requestIdleCallback,
isOpInChannel,
};
function findCurrentNetworkChan(name) {
@ -37,6 +39,15 @@ function resetHeight(element) {
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
// This can only be called from another interactive event (e.g. button click)
function forceFocus() {

View file

@ -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}}
</li>

View file

@ -48,5 +48,6 @@ exports.input = function(network, chan, cmd, args) {
this.emit("join", {
network: network.id,
chan: newChan.getFilteredClone(true),
shouldOpen: true,
});
};