diff --git a/client/css/style.css b/client/css/style.css index 72ae08b1..c12158c8 100644 --- a/client/css/style.css +++ b/client/css/style.css @@ -265,6 +265,8 @@ kbd { .context-menu-user::before { content: "\f007"; /* http://fontawesome.io/icon/user/ */ } .context-menu-close::before { content: "\f00d"; /* http://fontawesome.io/icon/times/ */ } .context-menu-list::before { content: "\f03a"; /* http://fontawesome.io/icon/list/ */ } +.context-menu-disconnect::before { content: "\f0c1"; /* https://fontawesome.com/icons/unlink?style=solid */ } +.context-menu-connect::before { content: "\f127"; /* https://fontawesome.com/icons/link?style=solid */ } .context-menu-action-whois::before { content: "\f05a"; /* http://fontawesome.io/icon/info-circle/ */ } .context-menu-action-kick::before { content: "\f05e"; /* http://fontawesome.io/icon/ban/ */ } .context-menu-action-op::before { content: "\f1fa"; /* http://fontawesome.io/icon/at/ */ } diff --git a/client/js/contextMenuFactory.js b/client/js/contextMenuFactory.js index bfbfde52..8d793604 100644 --- a/client/js/contextMenuFactory.js +++ b/client/js/contextMenuFactory.js @@ -108,6 +108,82 @@ function addQueryItem() { }); } +function addCloseItem() { + function getCloseDisplay(target) { + if (target.hasClass("lobby")) { + return "Remove"; + } else if (target.hasClass("channel")) { + return "Leave"; + } + + return "Close"; + } + + addContextMenuItem({ + check: (target) => target.hasClass("chan"), + className: "close", + displayName: getCloseDisplay, + data: (target) => target.attr("data-target"), + callback: (itemData) => utils.closeChan($(`.networks .chan[data-target="${itemData}"]`)), + }); +} + +function addConnectItem() { + let clickedNetwork; + + function isDisconnected(target) { + return target.parent().hasClass("not-connected"); + } + + function connect() { + socket.emit("input", { + target: $("#chat").data("id"), + text: "/connect", + }); + } + + function check(target) { + clickedNetwork = target; + return target.hasClass("lobby") && isDisconnected(target); + } + + addContextMenuItem({ + check: check, + className: "connect", + displayName: "Connect", + data: () => clickedNetwork.data("id"), + callback: connect, + }); +} + +function addDisconnectItem() { + let clickedNetwork; + + function isConnected(target) { + return !target.parent().hasClass("not-connected"); + } + + function disconnect() { + socket.emit("input", { + target: $("#chat").data("id"), + text: "/disconnect", + }); + } + + function check(target) { + clickedNetwork = target; + return target.hasClass("lobby") && isConnected(target); + } + + addContextMenuItem({ + check: check, + className: "disconnect", + displayName: "Disconnect", + data: () => clickedNetwork.data("id"), + callback: disconnect, + }); +} + function addKickItem() { function kick(itemData) { socket.emit("input", { @@ -324,4 +400,7 @@ function addDefaultItems() { addChannelListItem(); addBanListItem(); addIgnoreListItem(); + addConnectItem(); + addDisconnectItem(); + addCloseItem(); } diff --git a/client/js/lounge.js b/client/js/lounge.js index 82abe9d5..7283728f 100644 --- a/client/js/lounge.js +++ b/client/js/lounge.js @@ -300,49 +300,8 @@ $(function() { $("#help").on("click", "#view-changelog, #back-to-help", openWindow); $("#changelog").on("click", "#back-to-help", openWindow); - function closeChan(chan) { - let cmd = "/close"; - - if (chan.hasClass("lobby")) { - cmd = "/quit"; - const server = chan.find(".name").html(); - - if (!confirm("Disconnect from " + server + "?")) { // eslint-disable-line no-alert - return false; - } - } - - socket.emit("input", { - target: chan.data("id"), - text: cmd, - }); - chan.css({ - transition: "none", - opacity: 0.4, - }); - return false; - } - sidebar.on("click", ".close", function() { - closeChan($(this).closest(".chan")); - }); - - const getCloseDisplay = (target) => { - if (target.hasClass("lobby")) { - return "Disconnect"; - } else if (target.hasClass("channel")) { - return "Leave"; - } - - return "Close"; - }; - - contextMenuFactory.addContextMenuItem({ - check: (target) => target.hasClass("chan"), - className: "close", - displayName: getCloseDisplay, - data: (target) => target.attr("data-target"), - callback: (itemData) => closeChan($(`.networks .chan[data-target="${itemData}"]`)), + utils.closeChan($(this).closest(".chan")); }); $(document).on("visibilitychange focus click", () => { diff --git a/client/js/utils.js b/client/js/utils.js index aa162d71..3b808530 100644 --- a/client/js/utils.js +++ b/client/js/utils.js @@ -18,6 +18,7 @@ module.exports = { scrollIntoViewNicely, hasRoleInChannel, move, + closeChan, resetHeight, toggleNotificationMarkers, togglePasswordField, @@ -138,6 +139,30 @@ function move(array, old_index, new_index) { return array; } +function closeChan(chan) { + const socket = require("./socket"); + let cmd = "/close"; + + if (chan.hasClass("lobby")) { + cmd = "/quit"; + const server = chan.find(".name").html(); + + if (!confirm("Disconnect from " + server + "?")) { // eslint-disable-line no-alert + return false; + } + } + + socket.emit("input", { + target: chan.data("id"), + text: cmd, + }); + chan.css({ + transition: "none", + opacity: 0.4, + }); + return false; +} + function requestIdleCallback(callback, timeout) { if (window.requestIdleCallback) { // During an idle period the user agent will run idle callbacks in FIFO order