aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--client/client.js1377
1 files changed, 713 insertions, 664 deletions
diff --git a/client/client.js b/client/client.js
index 3624925..5a9537d 100644
--- a/client/client.js
+++ b/client/client.js
@@ -5,90 +5,134 @@
* soon. As a result of this, the current code has been deprecated
* and will not actively be updated.
*
-*/
+ */
// initialize markdown engine
var markdownOptions = {
- html: false,
- xhtmlOut: false,
- breaks: true,
- langPrefix: '',
- linkify: true,
- linkTarget: '_blank" rel="noreferrer',
- typographer: true,
- quotes: `""''`,
-
- doHighlight: true,
- highlight: function (str, lang) {
- if (!markdownOptions.doHighlight || !window.hljs) { return ''; }
-
- if (lang && hljs.getLanguage(lang)) {
- try {
- return hljs.highlight(lang, str).value;
- } catch (__) {}
- }
-
- try {
- return hljs.highlightAuto(str).value;
- } catch (__) {}
-
- return '';
- }
+ html: false,
+ xhtmlOut: false,
+ breaks: true,
+ langPrefix: "",
+ linkify: true,
+ linkTarget: '_blank" rel="noreferrer',
+ typographer: true,
+ quotes: `""''`,
+
+ doHighlight: true,
+ highlight: function (str, lang) {
+ if (!markdownOptions.doHighlight || !window.hljs) {
+ return "";
+ }
+
+ if (lang && hljs.getLanguage(lang)) {
+ try {
+ return hljs.highlight(lang, str).value;
+ } catch (__) {}
+ }
+
+ try {
+ return hljs.highlightAuto(str).value;
+ } catch (__) {}
+
+ return "";
+ },
};
-var md = new Remarkable('full', markdownOptions);
+var md = new Remarkable("full", markdownOptions);
// image handler
var allowImages = false;
-var imgHostWhitelist = [
- 'i.imgur.com',
- 'imgur.com',
-];
+var imgHostWhitelist = ["i.imgur.com", "imgur.com"];
function getDomain(link) {
- var a = document.createElement('a');
- a.href = link;
- return a.hostname;
+ var a = document.createElement("a");
+ a.href = link;
+ return a.hostname;
}
function isWhiteListed(link) {
- return imgHostWhitelist.indexOf(getDomain(link)) !== -1;
+ return imgHostWhitelist.indexOf(getDomain(link)) !== -1;
}
md.renderer.rules.image = function (tokens, idx, options) {
- var src = Remarkable.utils.escapeHtml(tokens[idx].src);
-
- if (isWhiteListed(src) && allowImages) {
- var imgSrc = ' src="' + Remarkable.utils.escapeHtml(tokens[idx].src) + '"';
- var title = tokens[idx].title ? (' title="' + Remarkable.utils.escapeHtml(Remarkable.utils.replaceEntities(tokens[idx].title)) + '"') : '';
- var alt = ' alt="' + (tokens[idx].alt ? Remarkable.utils.escapeHtml(Remarkable.utils.replaceEntities(Remarkable.utils.unescapeMd(tokens[idx].alt))) : '') + '"';
- var suffix = options.xhtmlOut ? ' /' : '';
- var scrollOnload = isAtBottom() ? ' onload="window.scrollTo(0, document.body.scrollHeight)"' : '';
- return '<a href="' + src + '" target="_blank" rel="noreferrer"><img' + scrollOnload + imgSrc + alt + title + suffix + '></a>';
- }
-
- return '<a href="' + src + '" target="_blank" rel="noreferrer">' + Remarkable.utils.escapeHtml(Remarkable.utils.replaceEntities(src)) + '</a>';
+ var src = Remarkable.utils.escapeHtml(tokens[idx].src);
+
+ if (isWhiteListed(src) && allowImages) {
+ var imgSrc = ' src="' + Remarkable.utils.escapeHtml(tokens[idx].src) + '"';
+ var title = tokens[idx].title
+ ? ' title="' +
+ Remarkable.utils.escapeHtml(Remarkable.utils.replaceEntities(tokens[idx].title)) +
+ '"'
+ : "";
+ var alt =
+ ' alt="' +
+ (tokens[idx].alt
+ ? Remarkable.utils.escapeHtml(
+ Remarkable.utils.replaceEntities(Remarkable.utils.unescapeMd(tokens[idx].alt))
+ )
+ : "") +
+ '"';
+ var suffix = options.xhtmlOut ? " /" : "";
+ var scrollOnload = isAtBottom()
+ ? ' onload="window.scrollTo(0, document.body.scrollHeight)"'
+ : "";
+ return (
+ '<a href="' +
+ src +
+ '" target="_blank" rel="noreferrer"><img' +
+ scrollOnload +
+ imgSrc +
+ alt +
+ title +
+ suffix +
+ "></a>"
+ );
+ }
+
+ return (
+ '<a href="' +
+ src +
+ '" target="_blank" rel="noreferrer">' +
+ Remarkable.utils.escapeHtml(Remarkable.utils.replaceEntities(src)) +
+ "</a>"
+ );
};
md.renderer.rules.link_open = function (tokens, idx, options) {
- var title = tokens[idx].title ? (' title="' + Remarkable.utils.escapeHtml(Remarkable.utils.replaceEntities(tokens[idx].title)) + '"') : '';
- var target = options.linkTarget ? (' target="' + options.linkTarget + '"') : '';
- return '<a rel="noreferrer" onclick="return verifyLink(this)" href="' + Remarkable.utils.escapeHtml(tokens[idx].href) + '"' + title + target + '>';
+ var title = tokens[idx].title
+ ? ' title="' +
+ Remarkable.utils.escapeHtml(Remarkable.utils.replaceEntities(tokens[idx].title)) +
+ '"'
+ : "";
+ var target = options.linkTarget ? ' target="' + options.linkTarget + '"' : "";
+ return (
+ '<a rel="noreferrer" onclick="return verifyLink(this)" href="' +
+ Remarkable.utils.escapeHtml(tokens[idx].href) +
+ '"' +
+ title +
+ target +
+ ">"
+ );
};
-md.renderer.rules.text = function(tokens, idx) {
- tokens[idx].content = Remarkable.utils.escapeHtml(tokens[idx].content);
-
- if (tokens[idx].content.indexOf('?') !== -1) {
- tokens[idx].content = tokens[idx].content.replace(/(^|\s)(\?)\S+?(?=[,.!?:)]?\s|$)/gm, function(match) {
- var channelLink = Remarkable.utils.escapeHtml(Remarkable.utils.replaceEntities(match.trim()));
- var whiteSpace = '';
- if (match[0] !== '?') {
- whiteSpace = match[0];
- }
- return whiteSpace + '<a href="' + channelLink + '" target="_blank">' + channelLink + '</a>';
- });
- }
+md.renderer.rules.text = function (tokens, idx) {
+ tokens[idx].content = Remarkable.utils.escapeHtml(tokens[idx].content);
+
+ if (tokens[idx].content.indexOf("?") !== -1) {
+ tokens[idx].content = tokens[idx].content.replace(
+ /(^|\s)(\?)\S+?(?=[,.!?:)]?\s|$)/gm,
+ function (match) {
+ var channelLink = Remarkable.utils.escapeHtml(
+ Remarkable.utils.replaceEntities(match.trim())
+ );
+ var whiteSpace = "";
+ if (match[0] !== "?") {
+ whiteSpace = match[0];
+ }
+ return whiteSpace + '<a href="' + channelLink + '" target="_blank">' + channelLink + "</a>";
+ }
+ );
+ }
return tokens[idx].content;
};
@@ -96,790 +140,795 @@ md.renderer.rules.text = function(tokens, idx) {
md.use(remarkableKatex);
function verifyLink(link) {
- var linkHref = Remarkable.utils.escapeHtml(Remarkable.utils.replaceEntities(link.href));
- if (linkHref !== link.innerHTML) {
- return confirm('Warning, please verify this is where you want to go: ' + linkHref);
- }
+ var linkHref = Remarkable.utils.escapeHtml(Remarkable.utils.replaceEntities(link.href));
+ if (linkHref !== link.innerHTML) {
+ return confirm("Warning, please verify this is where you want to go: " + linkHref);
+ }
- return true;
+ return true;
}
var verifyNickname = function (nick) {
- return /^[a-zA-Z0-9_]{1,24}$/.test(nick);
-}
+ return /^[a-zA-Z0-9_]{1,24}$/.test(nick);
+};
var frontpage = [
- " _ _ _ _ ",
- " | |_ ___ ___| |_ ___| |_ ___| |_ ",
- " | |_ || _| '_| | _| |_ || _|",
- " |_|_|__/|___|_,_|.|___|_|_|__/|_| ",
- "",
- "",
- "Welcome to hack.chat, a minimal, distraction-free chat application.",
- "Channels are created, joined and shared with the url, create your own channel by changing the text after the question mark.",
- "If you wanted your channel name to be 'your-channel': https://hack.chat/?your-channel",
- "There are no channel lists, so a secret channel name can be used for private discussions.",
- "",
- "Here are some pre-made channels you can join:",
- "?lounge ?meta",
- "?math ?physics ?chemistry",
- "?technology ?programming",
- "?games ?banana",
- "And here's a random one generated just for you: ?" + Math.random().toString(36).substr(2, 8),
- "",
- "Formatting:",
- "Whitespace is preserved, so source code can be pasted verbatim.",
- "Surround LaTeX with a dollar sign for inline style $\\zeta(2) = \\pi^2/6$, and two dollars for display. $$\\int_0^1 \\int_0^1 \\frac{1}{1-xy} dx dy = \\frac{\\pi^2}{6}$$",
- "For syntax highlight, wrap the code like: ```<language> <the code>``` where <language> is any known programming language.",
- "",
- "Current Github: https://github.com/hack-chat",
- "Legacy GitHub: https://github.com/AndrewBelt/hack.chat",
- "",
- "Bots, Android clients, desktop clients, browser extensions, docker images, programming libraries, server modules and more:",
- "https://github.com/hack-chat/3rd-party-software-list",
- "",
- "Server and web client released under the WTFPL and MIT open source license.",
- "No message history is retained on the hack.chat server."
+ " _ _ _ _ ",
+ " | |_ ___ ___| |_ ___| |_ ___| |_ ",
+ " | |_ || _| '_| | _| |_ || _|",
+ " |_|_|__/|___|_,_|.|___|_|_|__/|_| ",
+ "",
+ "",
+ "Welcome to hack.chat, a minimal, distraction-free chat application.",
+ "Channels are created, joined and shared with the url, create your own channel by changing the text after the question mark.",
+ "If you wanted your channel name to be 'your-channel': https://hack.chat/?your-channel",
+ "There are no channel lists, so a secret channel name can be used for private discussions.",
+ "",
+ "Here are some pre-made channels you can join:",
+ "?lounge ?meta",
+ "?math ?physics ?chemistry",
+ "?technology ?programming",
+ "?games ?banana",
+ "And here's a random one generated just for you: ?" + Math.random().toString(36).substr(2, 8),
+ "",
+ "Formatting:",
+ "Whitespace is preserved, so source code can be pasted verbatim.",
+ "Surround LaTeX with a dollar sign for inline style $\\zeta(2) = \\pi^2/6$, and two dollars for display. $$\\int_0^1 \\int_0^1 \\frac{1}{1-xy} dx dy = \\frac{\\pi^2}{6}$$",
+ "For syntax highlight, wrap the code like: ```<language> <the code>``` where <language> is any known programming language.",
+ "",
+ "Current Github: https://github.com/hack-chat",
+ "Legacy GitHub: https://github.com/AndrewBelt/hack.chat",
+ "",
+ "Bots, Android clients, desktop clients, browser extensions, docker images, programming libraries, server modules and more:",
+ "https://github.com/hack-chat/3rd-party-software-list",
+ "",
+ "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");
function $(query) {
- return document.querySelector(query);
+ return document.querySelector(query);
}
function localStorageGet(key) {
- try {
- return window.localStorage[key]
- } catch (e) { }
+ try {
+ return window.localStorage[key];
+ } catch (e) {}
}
function localStorageSet(key, val) {
- try {
- window.localStorage[key] = val
- } catch (e) { }
+ try {
+ window.localStorage[key] = val;
+ } catch (e) {}
}
var ws;
-var myNick = localStorageGet('my-nick') || '';
-var myChannel = window.location.search.replace(/^\?/, '');
+var myNick = localStorageGet("my-nick") || "";
+var myChannel = window.location.search.replace(/^\?/, "");
var lastSent = [""];
var lastSentPos = 0;
/** Notification switch and local storage behavior **/
-var notifySwitch = document.getElementById("notify-switch")
-var notifySetting = localStorageGet("notify-api")
+var notifySwitch = document.getElementById("notify-switch");
+var notifySetting = localStorageGet("notify-api");
var notifyPermissionExplained = 0; // 1 = granted msg shown, -1 = denied message shown
// Inital request for notifications permission
function RequestNotifyPermission() {
- try {
- var notifyPromise = Notification.requestPermission();
- if (notifyPromise) {
- notifyPromise.then(function (result) {
- console.log("Hack.Chat notification permission: " + result);
- if (result === "granted") {
- if (notifyPermissionExplained === 0) {
- pushMessage({
- cmd: "chat",
- nick: "*",
- text: "Notifications permission granted.",
- time: null
- });
- notifyPermissionExplained = 1;
- }
- return false;
- } else {
- if (notifyPermissionExplained === 0) {
- pushMessage({
- cmd: "chat",
- nick: "*",
- text: "Notifications permission denied, you won't be notified if someone @mentions you.",
- time: null
- });
- notifyPermissionExplained = -1;
- }
- return true;
- }
- });
- }
- } catch (error) {
- pushMessage({
- cmd: "chat",
- nick: "*",
- text: "Unable to create a notification.",
- time: null
- });
- console.error("An error occured trying to request notification permissions. This browser might not support desktop notifications.\nDetails:")
- console.error(error)
- return false;
- }
+ try {
+ var notifyPromise = Notification.requestPermission();
+ if (notifyPromise) {
+ notifyPromise.then(function (result) {
+ console.log("Hack.Chat notification permission: " + result);
+ if (result === "granted") {
+ if (notifyPermissionExplained === 0) {
+ pushMessage({
+ cmd: "chat",
+ nick: "*",
+ text: "Notifications permission granted.",
+ time: null,
+ });
+ notifyPermissionExplained = 1;
+ }
+ return false;
+ } else {
+ if (notifyPermissionExplained === 0) {
+ pushMessage({
+ cmd: "chat",
+ nick: "*",
+ text:
+ "Notifications permission denied, you won't be notified if someone @mentions you.",
+ time: null,
+ });
+ notifyPermissionExplained = -1;
+ }
+ return true;
+ }
+ });
+ }
+ } catch (error) {
+ pushMessage({
+ cmd: "chat",
+ nick: "*",
+ text: "Unable to create a notification.",
+ time: null,
+ });
+ console.error(
+ "An error occured trying to request notification permissions. This browser might not support desktop notifications.\nDetails:"
+ );
+ console.error(error);
+ return false;
+ }
}
// Update localStorage with value of checkbox
-notifySwitch.addEventListener('change', (event) => {
- if (event.target.checked) {
- RequestNotifyPermission();
- }
- localStorageSet("notify-api", notifySwitch.checked)
-})
+notifySwitch.addEventListener("change", (event) => {
+ if (event.target.checked) {
+ RequestNotifyPermission();
+ }
+ localStorageSet("notify-api", notifySwitch.checked);
+});
// Check if localStorage value is set, defaults to OFF
if (notifySetting === null) {
- localStorageSet("notify-api", "false")
- notifySwitch.checked = false
+ localStorageSet("notify-api", "false");
+ notifySwitch.checked = false;
}
// Configure notifySwitch checkbox element
if (notifySetting === "true" || notifySetting === true) {
- notifySwitch.checked = true
+ notifySwitch.checked = true;
} else if (notifySetting === "false" || notifySetting === false) {
- notifySwitch.checked = false
+ notifySwitch.checked = false;
}
/** Sound switch and local storage behavior **/
-var soundSwitch = document.getElementById("sound-switch")
-var notifySetting = localStorageGet("notify-sound")
+var soundSwitch = document.getElementById("sound-switch");
+var notifySetting = localStorageGet("notify-sound");
// Update localStorage with value of checkbox
-soundSwitch.addEventListener('change', (event) => {
- localStorageSet("notify-sound", soundSwitch.checked)
-})
+soundSwitch.addEventListener("change", (event) => {
+ localStorageSet("notify-sound", soundSwitch.checked);
+});
// Check if localStorage value is set, defaults to OFF
if (notifySetting === null) {
- localStorageSet("notify-sound", "false")
- soundSwitch.checked = false
+ localStorageSet("notify-sound", "false");
+ soundSwitch.checked = false;
}
// Configure soundSwitch checkbox element
if (notifySetting === "true" || notifySetting === true) {
- soundSwitch.checked = true
+ soundSwitch.checked = true;
} else if (notifySetting === "false" || notifySetting === false) {
- soundSwitch.checked = false
+ soundSwitch.checked = false;
}
// Create a new notification after checking if permission has been granted
function spawnNotification(title, body) {
- // Let's check if the browser supports notifications
- if (!("Notification" in window)) {
- console.error("This browser does not support desktop notification");
- } else if (Notification.permission === "granted") { // Check if notification permissions are already given
- // If it's okay let's create a notification
- var options = {
- body: body,
- icon: "/favicon-96x96.png"
- };
- var n = new Notification(title, options);
- }
- // Otherwise, we need to ask the user for permission
- else if (Notification.permission !== "denied") {
- if (RequestNotifyPermission()) {
- var options = {
- body: body,
- icon: "/favicon-96x96.png"
- };
- var n = new Notification(title, options);
- }
- } else if (Notification.permission == "denied") {
- // At last, if the user has denied notifications, and you
- // want to be respectful, there is no need to bother them any more.
- }
+ // Let's check if the browser supports notifications
+ if (!("Notification" in window)) {
+ console.error("This browser does not support desktop notification");
+ } else if (Notification.permission === "granted") {
+ // Check if notification permissions are already given
+ // If it's okay let's create a notification
+ var options = {
+ body: body,
+ icon: "/favicon-96x96.png",
+ };
+ var n = new Notification(title, options);
+ }
+ // Otherwise, we need to ask the user for permission
+ else if (Notification.permission !== "denied") {
+ if (RequestNotifyPermission()) {
+ var options = {
+ body: body,
+ icon: "/favicon-96x96.png",
+ };
+ var n = new Notification(title, options);
+ }
+ } else if (Notification.permission == "denied") {
+ // At last, if the user has denied notifications, and you
+ // want to be respectful, there is no need to bother them any more.
+ }
}
function notify(args) {
- // Spawn notification if enabled
- if (notifySwitch.checked) {
- spawnNotification("?" + myChannel + " — " + args.nick, args.text)
- }
-
- // Play sound if enabled
- if (soundSwitch.checked) {
- var soundPromise = document.getElementById("notify-sound").play();
- if (soundPromise) {
- soundPromise.catch(function (error) {
- console.error("Problem playing sound:\n" + error);
- });
- }
- }
+ // Spawn notification if enabled
+ if (notifySwitch.checked) {
+ spawnNotification("?" + myChannel + " — " + args.nick, args.text);
+ }
+
+ // Play sound if enabled
+ if (soundSwitch.checked) {
+ var soundPromise = document.getElementById("notify-sound").play();
+ if (soundPromise) {
+ soundPromise.catch(function (error) {
+ console.error("Problem playing sound:\n" + error);
+ });
+ }
+ }
}
function join(channel) {
- if (document.domain == 'hack.chat') {
- // For https://hack.chat/
- ws = new WebSocket('wss://hack.chat/chat-ws');
- } else {
- // for local installs
- var protocol = location.protocol === 'https:' ? 'wss:' : 'ws:'
- // if you changed the port during the server config, change 'wsPath'
- // to the new port (example: ':8080')
- // if you are reverse proxying, change 'wsPath' to the new location
- // (example: '/chat-ws')
- var wsPath = ':6060';
- ws = new WebSocket(protocol + '//' + document.domain + wsPath);
- }
-
- var wasConnected = false;
-
- ws.onopen = function () {
- if (!wasConnected) {
- if (location.hash) {
- myNick = location.hash.substr(1);
- } else {
- myNick = prompt('Nickname:', myNick);
- }
- }
-
- if (myNick) {
- localStorageSet('my-nick', myNick);
- send({ cmd: 'join', channel: channel, nick: myNick });
- }
-
- wasConnected = true;
- }
-
- ws.onclose = function () {
- if (wasConnected) {
- pushMessage({ nick: '!', text: "Server disconnected. Attempting to reconnect. . ." });
- }
-
- 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);
- }
+ if (document.domain == "hack.chat") {
+ // For https://hack.chat/
+ ws = new WebSocket("wss://hack.chat/chat-ws");
+ } else {
+ // for local installs
+ var protocol = location.protocol === "https:" ? "wss:" : "ws:";
+ // if you changed the port during the server config, change 'wsPath'
+ // to the new port (example: ':8080')
+ // if you are reverse proxying, change 'wsPath' to the new location
+ // (example: '/chat-ws')
+ var wsPath = "/socket";
+ ws = new WebSocket(protocol + "//" + document.domain + wsPath);
+ }
+
+ var wasConnected = false;
+
+ ws.onopen = function () {
+ if (!wasConnected) {
+ if (location.hash) {
+ myNick = location.hash.substr(1);
+ } else {
+ myNick = prompt("Nickname:", myNick);
+ }
+ }
+
+ if (myNick) {
+ localStorageSet("my-nick", myNick);
+ send({cmd: "join", channel: channel, nick: myNick});
+ }
+
+ wasConnected = true;
+ };
+
+ ws.onclose = function () {
+ if (wasConnected) {
+ pushMessage({nick: "!", text: "Server disconnected. Attempting to reconnect. . ."});
+ }
+
+ 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);
+ };
}
var COMMANDS = {
- chat: function (args) {
- if (ignoredUsers.indexOf(args.nick) >= 0) {
- return;
- }
- pushMessage(args);
- },
+ chat: function (args) {
+ if (ignoredUsers.indexOf(args.nick) >= 0) {
+ return;
+ }
+ 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;
+ onlineSet: function (args) {
+ var nicks = args.nicks;
- usersClear();
+ usersClear();
- nicks.forEach(function (nick) {
- userAdd(nick);
- });
+ nicks.forEach(function (nick) {
+ userAdd(nick);
+ });
- pushMessage({ nick: '*', text: "Users online: " + nicks.join(", ") })
- },
+ pushMessage({nick: "*", text: "Users online: " + nicks.join(", ")});
+ },
- onlineAdd: function (args) {
- var nick = args.nick;
+ onlineAdd: function (args) {
+ var nick = args.nick;
- userAdd(nick);
+ userAdd(nick);
- if ($('#joined-left').checked) {
- pushMessage({ nick: '*', text: nick + " joined" });
- }
- },
+ if ($("#joined-left").checked) {
+ pushMessage({nick: "*", text: nick + " joined"});
+ }
+ },
- onlineRemove: function (args) {
- var nick = args.nick;
+ onlineRemove: function (args) {
+ var nick = args.nick;
- userRemove(nick);
+ userRemove(nick);
- if ($('#joined-left').checked) {
- pushMessage({ nick: '*', text: nick + " left" });
- }
- }
-}
+ if ($("#joined-left").checked) {
+ pushMessage({nick: "*", text: nick + " left"});
+ }
+ },
+};
function pushMessage(args) {
- // Message container
- var messageEl = document.createElement('div');
-
- if (
- typeof (myNick) === 'string' && (
- args.text.match(new RegExp('@' + myNick.split('#')[0] + '\\b', "gi")) ||
- ((args.type === "whisper" || args.type === "invite") && args.from)
- )
- ) {
- notify(args);
- }
-
- messageEl.classList.add('message');
-
- if (verifyNickname(myNick) && 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');
- }
-
- // Nickname
- 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);
- }
-
- if (args.nick) {
- 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);
- }
-
- // Text
- var textEl = document.createElement('p');
- textEl.classList.add('text');
- textEl.innerHTML = md.render(args.text);
-
- messageEl.appendChild(textEl);
-
- // Scroll to bottom
- var atBottom = isAtBottom();
- $('#messages').appendChild(messageEl);
- if (atBottom) {
- window.scrollTo(0, document.body.scrollHeight);
- }
-
- unread += 1;
- updateTitle();
+ // Message container
+ var messageEl = document.createElement("div");
+
+ if (
+ typeof myNick === "string" &&
+ (args.text.match(new RegExp("@" + myNick.split("#")[0] + "\\b", "gi")) ||
+ ((args.type === "whisper" || args.type === "invite") && args.from))
+ ) {
+ notify(args);
+ }
+
+ messageEl.classList.add("message");
+
+ if (verifyNickname(myNick) && 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");
+ }
+
+ // Nickname
+ 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);
+ }
+
+ if (args.nick) {
+ 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);
+ }
+
+ // Text
+ var textEl = document.createElement("p");
+ textEl.classList.add("text");
+ textEl.innerHTML = md.render(args.text);
+
+ messageEl.appendChild(textEl);
+
+ // Scroll to bottom
+ var atBottom = isAtBottom();
+ $("#messages").appendChild(messageEl);
+ if (atBottom) {
+ window.scrollTo(0, document.body.scrollHeight);
+ }
+
+ 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);
+ 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;
+ before += text;
+ input.value = before + after;
+ input.selectionStart = input.selectionEnd = before.length;
- updateInputSize();
+ updateInputSize();
}
function send(data) {
- if (ws && ws.readyState == ws.OPEN) {
- ws.send(JSON.stringify(data));
- }
+ if (ws && ws.readyState == ws.OPEN) {
+ ws.send(JSON.stringify(data));
+ }
}
var windowActive = true;
var unread = 0;
window.onfocus = function () {
- windowActive = true;
+ windowActive = true;
- updateTitle();
-}
+ updateTitle();
+};
window.onblur = function () {
- windowActive = false;
-}
+ windowActive = false;
+};
window.onscroll = function () {
- if (isAtBottom()) {
- updateTitle();
- }
-}
+ if (isAtBottom()) {
+ 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;
- }
-
- var title;
- if (myChannel) {
- title = "?" + myChannel;
- } else {
- title = "hack.chat";
- }
-
- if (unread > 0) {
- title = '(' + unread + ') ' + title;
- }
-
- document.title = title;
-}
-
-$('#footer').onclick = function () {
- $('#chatinput').focus();
-}
-
-$('#chatinput').onkeydown = function (e) {
- if (e.keyCode == 13 /* ENTER */ && !e.shiftKey) {
- 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();
- }
- } else if (e.keyCode == 38 /* UP */) {
- // Restore previous sent messages
- if (e.target.selectionStart === 0 && lastSentPos < lastSent.length - 1) {
- e.preventDefault();
-
- if (lastSentPos == 0) {
- lastSent[0] = e.target.value;
- }
-
- lastSentPos += 1;
- e.target.value = lastSent[lastSentPos];
- e.target.selectionStart = e.target.selectionEnd = e.target.value.length;
-
- updateInputSize();
- }
- } 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();
- }
- } 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 */) {
- // Tab complete nicknames starting with @
-
- if (e.ctrlKey) {
- // Skip autocompletion and tab insertion if user is pressing ctrl
- // ctrl-tab is used by browsers to cycle through tabs
- return;
- }
- e.preventDefault();
-
- var pos = e.target.selectionStart || 0;
- var text = e.target.value;
- var index = text.lastIndexOf('@', pos);
-
- var autocompletedNick = false;
-
- if (index >= 0) {
- var stub = text.substring(index + 1, pos).toLowerCase();
- // Search for nick beginning with stub
- var nicks = onlineUsers.filter(function (nick) {
- return nick.toLowerCase().indexOf(stub) == 0
- });
-
- if (nicks.length > 0) {
- autocompletedNick = true;
- if (nicks.length == 1) {
- insertAtCursor(nicks[0].substr(stub.length) + " ");
- }
- }
- }
-
- // Since we did not insert a nick, we insert a tab character
- if (!autocompletedNick) {
- insertAtCursor('\t');
- }
- }
+ if (windowActive && isAtBottom()) {
+ unread = 0;
+ }
+
+ var title;
+ if (myChannel) {
+ title = "?" + myChannel;
+ } else {
+ title = "hack.chat";
+ }
+
+ if (unread > 0) {
+ title = "(" + unread + ") " + title;
+ }
+
+ document.title = title;
}
+$("#footer").onclick = function () {
+ $("#chatinput").focus();
+};
+
+$("#chatinput").onkeydown = function (e) {
+ if (e.keyCode == 13 /* ENTER */ && !e.shiftKey) {
+ 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();
+ }
+ } else if (e.keyCode == 38 /* UP */) {
+ // Restore previous sent messages
+ if (e.target.selectionStart === 0 && lastSentPos < lastSent.length - 1) {
+ e.preventDefault();
+
+ if (lastSentPos == 0) {
+ lastSent[0] = e.target.value;
+ }
+
+ lastSentPos += 1;
+ e.target.value = lastSent[lastSentPos];
+ e.target.selectionStart = e.target.selectionEnd = e.target.value.length;
+
+ updateInputSize();
+ }
+ } 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();
+ }
+ } 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 */) {
+ // Tab complete nicknames starting with @
+
+ if (e.ctrlKey) {
+ // Skip autocompletion and tab insertion if user is pressing ctrl
+ // ctrl-tab is used by browsers to cycle through tabs
+ return;
+ }
+ e.preventDefault();
+
+ var pos = e.target.selectionStart || 0;
+ var text = e.target.value;
+ var index = text.lastIndexOf("@", pos);
+
+ var autocompletedNick = false;
+
+ if (index >= 0) {
+ var stub = text.substring(index + 1, pos).toLowerCase();
+ // Search for nick beginning with stub
+ var nicks = onlineUsers.filter(function (nick) {
+ return nick.toLowerCase().indexOf(stub) == 0;
+ });
+
+ if (nicks.length > 0) {
+ autocompletedNick = true;
+ if (nicks.length == 1) {
+ insertAtCursor(nicks[0].substr(stub.length) + " ");
+ }
+ }
+ }
+
+ // Since we did not insert a nick, we insert a tab character
+ if (!autocompletedNick) {
+ insertAtCursor("\t");
+ }
+ }
+};
+
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);
- }
+ if (atBottom) {
+ window.scrollTo(0, document.body.scrollHeight);
+ }
}
-$('#chatinput').oninput = function () {
- updateInputSize();
-}
+$("#chatinput").oninput = function () {
+ updateInputSize();
+};
updateInputSize();
/* sidebar */
-$('#sidebar').onmouseenter = $('#sidebar').ontouchstart = function (e) {
- $('#sidebar-content').classList.remove('hidden');
- $('#sidebar').classList.add('expand');
- e.stopPropagation();
-}
-
-$('#sidebar').onmouseleave = document.ontouchstart = function (event) {
- var e = event.toElement || event.relatedTarget;
- try {
- if (e.parentNode == this || e == this) {
- return;
- }
- } catch (e) { return; }
+$("#sidebar").onmouseenter = $("#sidebar").ontouchstart = function (e) {
+ $("#sidebar-content").classList.remove("hidden");
+ $("#sidebar").classList.add("expand");
+ e.stopPropagation();
+};
- if (!$('#pin-sidebar').checked) {
- $('#sidebar-content').classList.add('hidden');
- $('#sidebar').classList.remove('expand');
- }
-}
+$("#sidebar").onmouseleave = document.ontouchstart = function (event) {
+ var e = event.toElement || event.relatedTarget;
+ try {
+ if (e.parentNode == this || e == this) {
+ return;
+ }
+ } catch (e) {
+ return;
+ }
+
+ if (!$("#pin-sidebar").checked) {
+ $("#sidebar-content").classList.add("hidden");
+ $("#sidebar").classList.remove("expand");
+ }
+};
-$('#clear-messages').onclick = function () {
- // Delete children elements
- var messages = $('#messages');
- messages.innerHTML = '';
-}
+$("#clear-messages").onclick = function () {
+ // Delete children elements
+ var messages = $("#messages");
+ messages.innerHTML = "";
+};
// Restore settings from localStorage
-if (localStorageGet('pin-sidebar') == 'true') {
- $('#pin-sidebar').checked = true;
- $('#sidebar-content').classList.remove('hidden');
+if (localStorageGet("pin-sidebar") == "true") {
+ $("#pin-sidebar").checked = true;
+ $("#sidebar-content").classList.remove("hidden");
}
-if (localStorageGet('joined-left') == 'false') {
- $('#joined-left').checked = false;
+if (localStorageGet("joined-left") == "false") {
+ $("#joined-left").checked = false;
}
-if (localStorageGet('parse-latex') == 'false') {
- $('#parse-latex').checked = false;
- md.inline.ruler.disable([ 'katex' ]);
- md.block.ruler.disable([ 'katex' ]);
+if (localStorageGet("parse-latex") == "false") {
+ $("#parse-latex").checked = false;
+ md.inline.ruler.disable(["katex"]);
+ md.block.ruler.disable(["katex"]);
}
-$('#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) {
- var enabled = !!e.target.checked;
- localStorageSet('parse-latex', enabled);
- if (enabled) {
- md.inline.ruler.enable([ 'katex' ]);
- md.block.ruler.enable([ 'katex' ]);
- } else {
- md.inline.ruler.disable([ 'katex' ]);
- md.block.ruler.disable([ 'katex' ]);
- }
-}
+$("#parse-latex").onchange = function (e) {
+ var enabled = !!e.target.checked;
+ localStorageSet("parse-latex", enabled);
+ if (enabled) {
+ md.inline.ruler.enable(["katex"]);
+ md.block.ruler.enable(["katex"]);
+ } else {
+ md.inline.ruler.disable(["katex"]);
+ md.block.ruler.disable(["katex"]);
+ }
+};
-if (localStorageGet('syntax-highlight') == 'false') {
- $('#syntax-highlight').checked = false;
- markdownOptions.doHighlight = false;
+if (localStorageGet("syntax-highlight") == "false") {
+ $("#syntax-highlight").checked = false;
+ markdownOptions.doHighlight = false;
}
-$('#syntax-highlight').onchange = function (e) {
- var enabled = !!e.target.checked;
- localStorageSet('syntax-highlight', enabled);
- markdownOptions.doHighlight = enabled;
-}
+$("#syntax-highlight").onchange = function (e) {
+ var enabled = !!e.target.checked;
+ localStorageSet("syntax-highlight", enabled);
+ markdownOptions.doHighlight = enabled;
+};
-if (localStorageGet('allow-imgur') == 'false') {
- $('#allow-imgur').checked = false;
- allowImages = false;
+if (localStorageGet("allow-imgur") == "false") {
+ $("#allow-imgur").checked = false;
+ allowImages = false;
}
-$('#allow-imgur').onchange = function (e) {
- var enabled = !!e.target.checked;
- localStorageSet('allow-imgur', enabled);
- allowImages = enabled;
-}
+$("#allow-imgur").onchange = function (e) {
+ var enabled = !!e.target.checked;
+ localStorageSet("allow-imgur", enabled);
+ allowImages = enabled;
+};
// User list
var onlineUsers = [];
var ignoredUsers = [];
function userAdd(nick) {
- var user = document.createElement('a');
- user.textContent = nick;
+ var user = document.createElement("a");
+ user.textContent = nick;
- user.onclick = function (e) {
- userInvite(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];
- if (user.textContent == nick) {
- users.removeChild(user);
- }
- }
+ for (var i = 0; i < children.length; i++) {
+ var user = children[i];
+ if (user.textContent == nick) {
+ users.removeChild(user);
+ }
+ }
- var index = onlineUsers.indexOf(nick);
- if (index >= 0) {
- onlineUsers.splice(index, 1);
- }
+ var index = onlineUsers.indexOf(nick);
+ if (index >= 0) {
+ onlineUsers.splice(index, 1);
+ }
}
function usersClear() {
- var users = $('#users');
+ var users = $("#users");
- while (users.firstChild) {
- users.removeChild(users.firstChild);
- }
+ while (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 */
var schemes = [
- 'android',
- 'android-white',
- 'atelier-dune',
- 'atelier-forest',
- 'atelier-heath',
- 'atelier-lakeside',
- 'atelier-seaside',
- 'bright',
- 'chalk',
- 'default',
- 'eighties',
- 'fresh-green',
- 'greenscreen',
- 'mariana',
- 'mocha',
- 'monokai',
- 'nese',
- 'ocean',
- 'pop',
- 'railscasts',
- 'solarized',
- 'tomorrow'
+ "android",
+ "android-white",
+ "atelier-dune",
+ "atelier-forest",
+ "atelier-heath",
+ "atelier-lakeside",
+ "atelier-seaside",
+ "bright",
+ "chalk",
+ "default",
+ "eighties",
+ "fresh-green",
+ "greenscreen",
+ "mariana",
+ "mocha",
+ "monokai",
+ "nese",
+ "ocean",
+ "pop",
+ "railscasts",
+ "solarized",
+ "tomorrow",
];
var highlights = [
- 'agate',
- 'androidstudio',
- 'atom-one-dark',
- 'darcula',
- 'github',
- 'rainbow',
- 'tomorrow',
- 'xcode',
- 'zenburn'
-]
-
-var currentScheme = 'atelier-dune';
-var currentHighlight = 'darcula';
+ "agate",
+ "androidstudio",
+ "atom-one-dark",
+ "darcula",
+ "github",
+ "rainbow",
+ "tomorrow",
+ "xcode",
+ "zenburn",
+];
+
+var currentScheme = "atelier-dune";
+var currentHighlight = "darcula";
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);
}
function setHighlight(scheme) {
- currentHighlight = scheme;
- $('#highlight-link').href = "vendor/hljs/styles/" + scheme + ".min.css";
- localStorageSet('highlight', scheme);
+ currentHighlight = scheme;
+ $("#highlight-link").href = "vendor/hljs/styles/" + scheme + ".min.css";
+ localStorageSet("highlight", 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);
+ var option = document.createElement("option");
+ option.textContent = scheme;
+ option.value = scheme;
+ $("#scheme-selector").appendChild(option);
});
highlights.forEach(function (scheme) {
- var option = document.createElement('option');
- option.textContent = scheme;
- option.value = scheme;
- $('#highlight-selector').appendChild(option);
+ var option = document.createElement("option");
+ option.textContent = scheme;
+ option.value = scheme;
+ $("#highlight-selector").appendChild(option);
});
-$('#scheme-selector').onchange = function (e) {
- setScheme(e.target.value);
-}
+$("#scheme-selector").onchange = function (e) {
+ setScheme(e.target.value);
+};
-$('#highlight-selector').onchange = function (e) {
- setHighlight(e.target.value);
-}
+$("#highlight-selector").onchange = function (e) {
+ setHighlight(e.target.value);
+};
// Load sidebar configaration values from local storage if available
-if (localStorageGet('scheme')) {
- setScheme(localStorageGet('scheme'));
+if (localStorageGet("scheme")) {
+ setScheme(localStorageGet("scheme"));
}
-if (localStorageGet('highlight')) {
- setHighlight(localStorageGet('highlight'));
+if (localStorageGet("highlight")) {
+ setHighlight(localStorageGet("highlight"));
}
-$('#scheme-selector').value = currentScheme;
-$('#highlight-selector').value = currentHighlight;
+$("#scheme-selector").value = currentScheme;
+$("#highlight-selector").value = currentHighlight;
/* main */
-if (myChannel == '') {
- pushMessage({ text: frontpage });
- $('#footer').classList.add('hidden');
- $('#sidebar').classList.add('hidden');
+if (myChannel == "") {
+ pushMessage({text: frontpage});
+ $("#footer").classList.add("hidden");
+ $("#sidebar").classList.add("hidden");
} else {
- join(myChannel);
+ join(myChannel);
}