diff options
Diffstat (limited to 'client')
-rw-r--r-- | client/client.js | 555 |
1 files changed, 291 insertions, 264 deletions
diff --git a/client/client.js b/client/client.js index 254480d..85e3ecb 100644 --- a/client/client.js +++ b/client/client.js @@ -26,452 +26,481 @@ var frontpage = [ "", "Server and web client released under the WTFPL and MIT open source license.", "No message history is retained on the hack.chat server." -].join("\n") +].join("\n"); -function $(query) {return document.querySelector(query)} +function $(query) { + return document.querySelector(query); +} function localStorageGet(key) { try { return window.localStorage[key] - } - catch(e) {} + } catch(e) {} } function localStorageSet(key, val) { try { window.localStorage[key] = val - } - catch(e) {} + } catch(e) {} } - -var ws -var myNick = localStorageGet('my-nick') -var myChannel = window.location.search.replace(/^\?/, '') -var lastSent = [""] -var lastSentPos = 0 - +var ws; +var myNick = localStorageGet('my-nick'); +var myChannel = window.location.search.replace(/^\?/, ''); +var lastSent = [""]; +var lastSentPos = 0; // Ping server every 50 seconds to retain WebSocket connection -window.setInterval(function() { - send({cmd: 'ping'}) -}, 50000) - +window.setInterval(function () { + send({ cmd: 'ping' }); +}, 50000); function join(channel) { if (document.domain == 'hack.chat') { // For https://hack.chat/ - ws = new WebSocket('wss://hack.chat/chat-ws') + ws = new WebSocket('wss://hack.chat/chat-ws'); } else { // for local installs - ws = new WebSocket('ws://' + document.domain + ':6060') + ws = new WebSocket('ws://' + document.domain + ':6060'); } - var wasConnected = false + var wasConnected = false; - ws.onopen = function() { + ws.onopen = function () { if (!wasConnected) { if (location.hash) { - myNick = location.hash.substr(1) - } - else { - myNick = prompt('Nickname:', myNick) + myNick = location.hash.substr(1); + } else { + myNick = prompt('Nickname:', myNick); } } + if (myNick) { - localStorageSet('my-nick', myNick) - send({cmd: 'join', channel: channel, nick: myNick}) + localStorageSet('my-nick', myNick); + send({ cmd: 'join', channel: channel, nick: myNick }); } - wasConnected = true + + wasConnected = true; } - ws.onclose = function() { + ws.onclose = function () { if (wasConnected) { - pushMessage({nick: '!', text: "Server disconnected. Attempting to reconnect..."}) + pushMessage({ nick: '!', text: "Server disconnected. Attempting to reconnect. . ." }); } - window.setTimeout(function() { - join(channel) - }, 2000) + + window.setTimeout(function () { + join(channel); + }, 2000); } - ws.onmessage = function(message) { - var args = JSON.parse(message.data) - var cmd = args.cmd - var command = COMMANDS[cmd] - command.call(null, args) + ws.onmessage = function (message) { + var args = JSON.parse(message.data); + var cmd = args.cmd; + var command = COMMANDS[cmd]; + command.call(null, args); } } - var COMMANDS = { - chat: function(args) { + chat: function (args) { if (ignoredUsers.indexOf(args.nick) >= 0) { - return + return; } - pushMessage(args) + + pushMessage(args); }, - info: function(args) { - args.nick = '*' - pushMessage(args) + + info: function (args) { + args.nick = '*'; + + pushMessage(args); }, - warn: function(args) { - args.nick = '!' - pushMessage(args) + + warn: function (args) { + args.nick = '!'; + + pushMessage(args); }, - onlineSet: function(args) { - var nicks = args.nicks - usersClear() - nicks.forEach(function(nick) { - userAdd(nick) - }) - pushMessage({nick: '*', text: "Users online: " + nicks.join(", ")}) + + onlineSet: function (args) { + var nicks = args.nicks; + + usersClear(); + + nicks.forEach(function (nick) { + userAdd(nick); + }); + + pushMessage({ nick: '*', text: "Users online: " + nicks.join(", ") }) }, - onlineAdd: function(args) { - var nick = args.nick - userAdd(nick) + + onlineAdd: function (args) { + var nick = args.nick; + + userAdd(nick); + if ($('#joined-left').checked) { - pushMessage({nick: '*', text: nick + " joined"}) + pushMessage({ nick: '*', text: nick + " joined" }); } }, - onlineRemove: function(args) { - var nick = args.nick - userRemove(nick) + + onlineRemove: function (args) { + var nick = args.nick; + + userRemove(nick); + if ($('#joined-left').checked) { - pushMessage({nick: '*', text: nick + " left"}) + pushMessage({ nick: '*', text: nick + " left" }); } - }, + } } - function pushMessage(args) { // Message container - var messageEl = document.createElement('div') - messageEl.classList.add('message') + var messageEl = document.createElement('div'); + messageEl.classList.add('message'); if (args.nick == myNick) { - messageEl.classList.add('me') - } - else if (args.nick == '!') { - messageEl.classList.add('warn') - } - else if (args.nick == '*') { - messageEl.classList.add('info') - } - else if (args.admin) { - messageEl.classList.add('admin') - } - else if (args.mod) { - messageEl.classList.add('mod') + messageEl.classList.add('me'); + } else if (args.nick == '!') { + messageEl.classList.add('warn'); + } else if (args.nick == '*') { + messageEl.classList.add('info'); + } else if (args.admin) { + messageEl.classList.add('admin'); + } else if (args.mod) { + messageEl.classList.add('mod'); } // Nickname - var nickSpanEl = document.createElement('span') - nickSpanEl.classList.add('nick') - messageEl.appendChild(nickSpanEl) + var nickSpanEl = document.createElement('span'); + nickSpanEl.classList.add('nick'); + messageEl.appendChild(nickSpanEl); if (args.trip) { - var tripEl = document.createElement('span') - tripEl.textContent = args.trip + " " - tripEl.classList.add('trip') - nickSpanEl.appendChild(tripEl) + var tripEl = document.createElement('span'); + tripEl.textContent = args.trip + " "; + tripEl.classList.add('trip'); + nickSpanEl.appendChild(tripEl); } if (args.nick) { - var nickLinkEl = document.createElement('a') - nickLinkEl.textContent = args.nick - nickLinkEl.onclick = function() { - insertAtCursor("@" + args.nick + " ") - $('#chatinput').focus() + var nickLinkEl = document.createElement('a'); + nickLinkEl.textContent = args.nick; + + nickLinkEl.onclick = function () { + insertAtCursor("@" + args.nick + " "); + $('#chatinput').focus(); } - var date = new Date(args.time || Date.now()) - nickLinkEl.title = date.toLocaleString() - nickSpanEl.appendChild(nickLinkEl) + + var date = new Date(args.time || Date.now()); + nickLinkEl.title = date.toLocaleString(); + nickSpanEl.appendChild(nickLinkEl); } // Text - var textEl = document.createElement('pre') - textEl.classList.add('text') + var textEl = document.createElement('pre'); + textEl.classList.add('text'); - textEl.textContent = args.text || '' - textEl.innerHTML = textEl.innerHTML.replace(/(\?|https?:\/\/)\S+?(?=[,.!?:)]?\s|$)/g, parseLinks) + textEl.textContent = args.text || ''; + textEl.innerHTML = textEl.innerHTML.replace(/(\?|https?:\/\/)\S+?(?=[,.!?:)]?\s|$)/g, parseLinks); if ($('#parse-latex').checked) { // Temporary hotfix for \rule spamming, see https://github.com/Khan/KaTeX/issues/109 - textEl.innerHTML = textEl.innerHTML.replace(/\\rule|\\\\\s*\[.*?\]/g, '') + textEl.innerHTML = textEl.innerHTML.replace(/\\rule|\\\\\s*\[.*?\]/g, ''); try { renderMathInElement(textEl, {delimiters: [ - {left: "$$", right: "$$", display: true}, - {left: "$", right: "$", display: false}, + { left: "$$", right: "$$", display: true }, + { left: "$", right: "$", display: false }, ]}) - } - catch (e) { - console.warn(e) + } catch (e) { + console.warn(e); } } - messageEl.appendChild(textEl) + messageEl.appendChild(textEl); // Scroll to bottom - var atBottom = isAtBottom() - $('#messages').appendChild(messageEl) + var atBottom = isAtBottom(); + $('#messages').appendChild(messageEl); if (atBottom) { - window.scrollTo(0, document.body.scrollHeight) + window.scrollTo(0, document.body.scrollHeight); } - unread += 1 - updateTitle() + unread += 1; + updateTitle(); } - function insertAtCursor(text) { - var input = $('#chatinput') - var start = input.selectionStart || 0 - var before = input.value.substr(0, start) - var after = input.value.substr(start) - before += text - input.value = before + after - input.selectionStart = input.selectionEnd = before.length - updateInputSize() -} + var input = $('#chatinput'); + var start = input.selectionStart || 0; + var before = input.value.substr(0, start); + var after = input.value.substr(start); + before += text; + input.value = before + after; + input.selectionStart = input.selectionEnd = before.length; + + updateInputSize(); +} function send(data) { if (ws && ws.readyState == ws.OPEN) { - ws.send(JSON.stringify(data)) + ws.send(JSON.stringify(data)); } } - function parseLinks(g0) { - var a = document.createElement('a') - a.innerHTML = g0 - var url = a.textContent - a.href = url - a.target = '_blank' - return a.outerHTML + var a = document.createElement('a'); + + a.innerHTML = g0; + + var url = a.textContent; + + a.href = url; + a.target = '_blank'; + + return a.outerHTML; } +var windowActive = true; +var unread = 0; -var windowActive = true -var unread = 0 +window.onfocus = function () { + windowActive = true; -window.onfocus = function() { - windowActive = true - updateTitle() + updateTitle(); } -window.onblur = function() { - windowActive = false +window.onblur = function () { + windowActive = false; } -window.onscroll = function() { +window.onscroll = function () { if (isAtBottom()) { - updateTitle() + updateTitle(); } } function isAtBottom() { - return (window.innerHeight + window.scrollY) >= (document.body.scrollHeight - 1) + return (window.innerHeight + window.scrollY) >= (document.body.scrollHeight - 1); } function updateTitle() { if (windowActive && isAtBottom()) { - unread = 0 + unread = 0; } - var title + var title; if (myChannel) { - title = "?" + myChannel - } - else { - title = "hack.chat" + title = "?" + myChannel; + } else { + title = "hack.chat"; } + if (unread > 0) { - title = '(' + unread + ') ' + title + title = '(' + unread + ') ' + title; } - document.title = title -} -/* footer */ + document.title = title; +} -$('#footer').onclick = function() { - $('#chatinput').focus() +$('#footer').onclick = function () { + $('#chatinput').focus(); } -$('#chatinput').onkeydown = function(e) { +$('#chatinput').onkeydown = function (e) { if (e.keyCode == 13 /* ENTER */ && !e.shiftKey) { - e.preventDefault() + e.preventDefault(); + // Submit message if (e.target.value != '') { - var text = e.target.value - e.target.value = '' - send({cmd: 'chat', text: text}) - lastSent[0] = text - lastSent.unshift("") - lastSentPos = 0 - updateInputSize() + var text = e.target.value; + e.target.value = ''; + + send({ cmd: 'chat', text: text }); + + lastSent[0] = text; + lastSent.unshift(""); + lastSentPos = 0; + + updateInputSize(); } - } - else if (e.keyCode == 38 /* UP */) { + } else if (e.keyCode == 38 /* UP */) { // Restore previous sent messages if (e.target.selectionStart === 0 && lastSentPos < lastSent.length - 1) { - e.preventDefault() + e.preventDefault(); + if (lastSentPos == 0) { - lastSent[0] = e.target.value + lastSent[0] = e.target.value; } - lastSentPos += 1 - e.target.value = lastSent[lastSentPos] - e.target.selectionStart = e.target.selectionEnd = e.target.value.length - updateInputSize() + + lastSentPos += 1; + e.target.value = lastSent[lastSentPos]; + e.target.selectionStart = e.target.selectionEnd = e.target.value.length; + + updateInputSize(); } - } - else if (e.keyCode == 40 /* DOWN */) { + } else if (e.keyCode == 40 /* DOWN */) { if (e.target.selectionStart === e.target.value.length && lastSentPos > 0) { - e.preventDefault() - lastSentPos -= 1 - e.target.value = lastSent[lastSentPos] - e.target.selectionStart = e.target.selectionEnd = 0 - updateInputSize() + e.preventDefault(); + + lastSentPos -= 1; + e.target.value = lastSent[lastSentPos]; + e.target.selectionStart = e.target.selectionEnd = 0; + + updateInputSize(); } - } - else if (e.keyCode == 27 /* ESC */) { - e.preventDefault() + } else if (e.keyCode == 27 /* ESC */) { + e.preventDefault(); + // Clear input field - e.target.value = "" - lastSentPos = 0 - lastSent[lastSentPos] = "" - updateInputSize() - } - else if (e.keyCode == 9 /* TAB */) { + e.target.value = ""; + lastSentPos = 0; + lastSent[lastSentPos] = ""; + + updateInputSize(); + } else if (e.keyCode == 9 /* TAB */) { // Tab complete nicknames starting with @ - e.preventDefault() - var pos = e.target.selectionStart || 0 - var text = e.target.value - var index = text.lastIndexOf('@', pos) + e.preventDefault(); + + var pos = e.target.selectionStart || 0; + var text = e.target.value; + var index = text.lastIndexOf('@', pos); + if (index >= 0) { - var stub = text.substring(index + 1, pos).toLowerCase() + var stub = text.substring(index + 1, pos).toLowerCase(); // Search for nick beginning with stub - var nicks = onlineUsers.filter(function(nick) { + var nicks = onlineUsers.filter(function (nick) { return nick.toLowerCase().indexOf(stub) == 0 - }) + }); + if (nicks.length == 1) { - insertAtCursor(nicks[0].substr(stub.length) + " ") + insertAtCursor(nicks[0].substr(stub.length) + " "); } } } } - function updateInputSize() { - var atBottom = isAtBottom() + var atBottom = isAtBottom(); - var input = $('#chatinput') - input.style.height = 0 - input.style.height = input.scrollHeight + 'px' - document.body.style.marginBottom = $('#footer').offsetHeight + 'px' + var input = $('#chatinput'); + input.style.height = 0; + input.style.height = input.scrollHeight + 'px'; + document.body.style.marginBottom = $('#footer').offsetHeight + 'px'; if (atBottom) { - window.scrollTo(0, document.body.scrollHeight) + window.scrollTo(0, document.body.scrollHeight); } } -$('#chatinput').oninput = function() { - updateInputSize() +$('#chatinput').oninput = function () { + updateInputSize(); } -updateInputSize() +updateInputSize(); /* sidebar */ -$('#sidebar').onmouseenter = $('#sidebar').ontouchstart = function(e) { - $('#sidebar-content').classList.remove('hidden') - e.stopPropagation() +$('#sidebar').onmouseenter = $('#sidebar').ontouchstart = function (e) { + $('#sidebar-content').classList.remove('hidden'); + e.stopPropagation(); } -$('#sidebar').onmouseleave = document.ontouchstart = function() { +$('#sidebar').onmouseleave = document.ontouchstart = function () { if (!$('#pin-sidebar').checked) { - $('#sidebar-content').classList.add('hidden') + $('#sidebar-content').classList.add('hidden'); } } -$('#clear-messages').onclick = function() { +$('#clear-messages').onclick = function () { // Delete children elements - var messages = $('#messages') + var messages = $('#messages'); while (messages.firstChild) { - messages.removeChild(messages.firstChild) + messages.removeChild(messages.firstChild); } } // Restore settings from localStorage if (localStorageGet('pin-sidebar') == 'true') { - $('#pin-sidebar').checked = true - $('#sidebar-content').classList.remove('hidden') + $('#pin-sidebar').checked = true; + $('#sidebar-content').classList.remove('hidden'); } + if (localStorageGet('joined-left') == 'false') { - $('#joined-left').checked = false + $('#joined-left').checked = false; } + if (localStorageGet('parse-latex') == 'false') { - $('#parse-latex').checked = false + $('#parse-latex').checked = false; } -$('#pin-sidebar').onchange = function(e) { - localStorageSet('pin-sidebar', !!e.target.checked) +$('#pin-sidebar').onchange = function (e) { + localStorageSet('pin-sidebar', !!e.target.checked); } -$('#joined-left').onchange = function(e) { - localStorageSet('joined-left', !!e.target.checked) + +$('#joined-left').onchange = function (e) { + localStorageSet('joined-left', !!e.target.checked); } -$('#parse-latex').onchange = function(e) { - localStorageSet('parse-latex', !!e.target.checked) + +$('#parse-latex').onchange = function (e) { + localStorageSet('parse-latex', !!e.target.checked); } // User list - -var onlineUsers = [] -var ignoredUsers = [] +var onlineUsers = []; +var ignoredUsers = []; function userAdd(nick) { - var user = document.createElement('a') - user.textContent = nick - user.onclick = function(e) { + var user = document.createElement('a'); + user.textContent = nick; + + user.onclick = function (e) { userInvite(nick) } - var userLi = document.createElement('li') - userLi.appendChild(user) - $('#users').appendChild(userLi) - onlineUsers.push(nick) + + var userLi = document.createElement('li'); + userLi.appendChild(user); + $('#users').appendChild(userLi); + onlineUsers.push(nick); } function userRemove(nick) { - var users = $('#users') - var children = users.children + var users = $('#users'); + var children = users.children; + for (var i = 0; i < children.length; i++) { - var user = children[i] + var user = children[i]; if (user.textContent == nick) { - users.removeChild(user) + users.removeChild(user); } } - var index = onlineUsers.indexOf(nick) + + var index = onlineUsers.indexOf(nick); if (index >= 0) { - onlineUsers.splice(index, 1) + onlineUsers.splice(index, 1); } } function usersClear() { - var users = $('#users') + var users = $('#users'); + while (users.firstChild) { - users.removeChild(users.firstChild) + users.removeChild(users.firstChild); } - onlineUsers.length = 0 + + onlineUsers.length = 0; } function userInvite(nick) { - send({cmd: 'invite', nick: nick}) + send({ cmd: 'invite', nick: nick }); } function userIgnore(nick) { - ignoredUsers.push(nick) + ignoredUsers.push(nick); } /* color scheme switcher */ @@ -495,44 +524,42 @@ var schemes = [ 'pop', 'railscasts', 'solarized', - 'tomorrow', -] + 'tomorrow' +]; -var currentScheme = 'atelier-dune' +var currentScheme = 'atelier-dune'; function setScheme(scheme) { - currentScheme = scheme - $('#scheme-link').href = "/schemes/" + scheme + ".css" - localStorageSet('scheme', scheme) + currentScheme = scheme; + $('#scheme-link').href = "schemes/" + scheme + ".css"; + localStorageSet('scheme', scheme); } // Add scheme options to dropdown selector -schemes.forEach(function(scheme) { - var option = document.createElement('option') - option.textContent = scheme - option.value = scheme - $('#scheme-selector').appendChild(option) -}) +schemes.forEach(function (scheme) { + var option = document.createElement('option'); + option.textContent = scheme; + option.value = scheme; + $('#scheme-selector').appendChild(option); +}); -$('#scheme-selector').onchange = function(e) { - setScheme(e.target.value) +$('#scheme-selector').onchange = function (e) { + setScheme(e.target.value); } // Load sidebar configaration values from local storage if available if (localStorageGet('scheme')) { - setScheme(localStorageGet('scheme')) + setScheme(localStorageGet('scheme')); } -$('#scheme-selector').value = currentScheme - +$('#scheme-selector').value = currentScheme; /* main */ if (myChannel == '') { - pushMessage({text: frontpage}) - $('#footer').classList.add('hidden') - $('#sidebar').classList.add('hidden') -} -else { - join(myChannel) + pushMessage({ text: frontpage }); + $('#footer').classList.add('hidden'); + $('#sidebar').classList.add('hidden'); +} else { + join(myChannel); } |