diff --git a/client/css/style.css b/client/css/style.css index 65bba699..695a0b75 100644 --- a/client/css/style.css +++ b/client/css/style.css @@ -160,7 +160,8 @@ button { #chat .whois .from:before, #chat .nick .from:before, #chat .action .from:before, -.context-menu-item:before { +.context-menu-item:before, +#nick button:before { font: normal normal normal 14px/1 FontAwesome; font-size: inherit; /* Can't have font-size inherit on line above, so need to override */ -webkit-font-smoothing: antialiased; @@ -260,6 +261,18 @@ button { margin-right: 9px; } +#set-nick:before { + content: "\f040"; /* http://fontawesome.io/icon/pencil/ */ +} + +#submit-nick:before { + content: "\f00c"; /* http://fontawesome.io/icon/check/ */ +} + +#cancel-nick:before { + content: "\f00d"; /* http://fontawesome.io/icon/times/ */ +} + /* End icons */ #wrap { @@ -1284,32 +1297,64 @@ button { align-items: flex-end; } +[contenteditable]:focus { + outline: none; +} + +/* Nick editor */ + #form #nick { background: #f6f6f6; color: #666; font: inherit; font-size: 11px; margin: 4px; - line-height: 26px; + line-height: 22px; height: 24px; - padding: 0 9px; - border-radius: 1px; + padding-left: 9px; + padding-right: 5px; + border-radius: 2px; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; -webkit-flex: 0 0 auto; flex: 0 0 auto; + border: 1px solid transparent; + transition: border-color .2s; } -#form #nick:empty { - visibility: hidden; +#form #nick-value { + padding-right: 5px; } -#form #nick:after { - content: ":"; +#form #nick.editable { + border-color: black; } +#nick button#set-nick, +#nick button#submit-nick, +#nick button#cancel-nick { + color: #aaa; + width: 18px; +} + +#nick.editable button#set-nick, +#nick.editable #set-nick-tooltip, +#nick button#submit-nick, +#nick:not(.editable) #save-nick-tooltip, +#nick button#cancel-nick, +#nick:not(.editable) #cancel-nick-tooltip { + display: none; +} + +#nick.editable button#submit-nick, +#nick.editable button#cancel-nick { + display: inline-block; +} + +/* End nick editor */ + #form #input { background: transparent; border: none; diff --git a/client/index.html b/client/index.html index 1276b99b..25be00ab 100644 --- a/client/index.html +++ b/client/index.html @@ -59,7 +59,12 @@
- + + + diff --git a/client/js/lounge.js b/client/js/lounge.js index 58cf0c17..914d9c2c 100644 --- a/client/js/lounge.js +++ b/client/js/lounge.js @@ -713,6 +713,65 @@ $(function() { .first(); } + $("button#set-nick").on("click", function() { + toggleNickEditor(true); + + // Selects existing nick in the editable text field + var element = document.querySelector("#nick-value"); + element.focus(); + var range = document.createRange(); + range.selectNodeContents(element); + var selection = window.getSelection(); + selection.removeAllRanges(); + selection.addRange(range); + }); + + $("button#cancel-nick").on("click", cancelNick); + $("button#submit-nick").on("click", submitNick); + + function toggleNickEditor(toggle) { + $("#nick").toggleClass("editable", toggle); + $("#nick-value").attr("contenteditable", toggle); + } + + function submitNick() { + var newNick = $("#nick-value").text().trim(); + + if (newNick.length === 0) { + cancelNick(); + return; + } + + toggleNickEditor(false); + + socket.emit("input", { + target: chat.data("id"), + text: "/nick " + newNick + }); + } + + function cancelNick() { + setNick(sidebar.find(".chan.active").closest(".network").data("nick")); + } + + $("#nick-value").keypress(function(e) { + switch (e.keyCode ? e.keyCode : e.which) { + case 13: // Enter + // Ensures a new line is not added when pressing Enter + e.preventDefault(); + break; + } + }).keyup(function(e) { + switch (e.keyCode ? e.keyCode : e.which) { + case 13: // Enter + submitNick(); + break; + case 27: // Escape + cancelNick(); + break; + } + }); + chat.on("click", ".inline-channel", function() { var name = $(this).data("chan"); var chan = findCurrentNetworkChan(name); @@ -1198,7 +1257,11 @@ $(function() { } function setNick(nick) { - $("#nick").text(nick); + // Closes the nick editor when canceling, changing channel, or when a nick + // is set in a different tab / browser / device. + toggleNickEditor(false); + + $("#nick-value").text(nick); } function move(array, old_index, new_index) { diff --git a/src/client.js b/src/client.js index 222b7628..f8be844a 100644 --- a/src/client.js +++ b/src/client.js @@ -42,6 +42,7 @@ var inputs = [ "invite", "kick", "mode", + "nick", "notice", "query", "quit", diff --git a/src/plugins/inputs/nick.js b/src/plugins/inputs/nick.js new file mode 100644 index 00000000..a267b1e4 --- /dev/null +++ b/src/plugins/inputs/nick.js @@ -0,0 +1,37 @@ +var Msg = require("../../models/msg"); + +exports.commands = ["nick"]; +exports.allowDisconnected = true; + +exports.input = function(network, chan, cmd, args) { + if (args.length === 0) { + chan.pushMessage(this, new Msg({ + type: Msg.Type.ERROR, + text: "Usage: /nick " + })); + return; + } + + if (args.length !== 1) { + chan.pushMessage(this, new Msg({ + type: Msg.Type.ERROR, + text: "Nicknames may not contain spaces." + })); + return; + } + + var newNick = args[0]; + + // If connected to IRC, send to server and wait for ACK + // otherwise update the nick and UI straight away + if (network.irc && network.irc.connection) { + network.irc.raw("NICK", newNick); + } else { + network.setNick(newNick); + + this.emit("nick", { + network: network.id, + nick: newNick + }); + } +}; diff --git a/src/plugins/irc-events/error.js b/src/plugins/irc-events/error.js index b7709738..3a92ebb7 100644 --- a/src/plugins/irc-events/error.js +++ b/src/plugins/irc-events/error.js @@ -28,6 +28,11 @@ module.exports = function(irc, network) { var random = (data.nick || irc.user.nick) + Math.floor(10 + (Math.random() * 89)); irc.changeNick(random); } + + client.emit("nick", { + network: network.id, + nick: irc.user.nick + }); }); irc.on("nick invalid", function(data) { @@ -42,5 +47,10 @@ module.exports = function(irc, network) { var random = "i" + Math.random().toString(36).substr(2, 10); // 'i' so it never begins with a number irc.changeNick(random); } + + client.emit("nick", { + network: network.id, + nick: irc.user.nick + }); }); };