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-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,

View File

@ -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() {

View File

@ -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() {

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}} {{text}}
</li> </li>

View File

@ -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,
}); });
}; };