mirror of
https://github.com/darkwire/darkwire.io.git
synced 2025-07-18 18:54:52 +00:00
commit
712c581083
263
src/js/app.js
Normal file
263
src/js/app.js
Normal file
@ -0,0 +1,263 @@
|
|||||||
|
import _ from 'underscore';
|
||||||
|
import Darkwire from './darkwire';
|
||||||
|
import WindowHandler from './window';
|
||||||
|
import Chat from './chat';
|
||||||
|
import moment from 'moment';
|
||||||
|
import sanitizeHtml from 'sanitize-html';
|
||||||
|
import he from 'he';
|
||||||
|
|
||||||
|
export default class App {
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this._roomId = window.location.pathname.length ? window.location.pathname : null;
|
||||||
|
this._darkwire = new Darkwire();
|
||||||
|
this._socket = io(this._roomId);
|
||||||
|
this._chat = new Chat(this._darkwire, this._socket);
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
|
||||||
|
if (!this._roomId) { return; }
|
||||||
|
|
||||||
|
$('input.share-text').val(document.location.protocol + '//' + document.location.host + this._roomId);
|
||||||
|
|
||||||
|
$('input.share-text').click(() => {
|
||||||
|
$(this).focus();
|
||||||
|
$(this).select();
|
||||||
|
this.setSelectionRange(0, 9999);
|
||||||
|
});
|
||||||
|
|
||||||
|
const windowHandler = new WindowHandler(this._darkwire, this._socket, this._chat);
|
||||||
|
|
||||||
|
FastClick.attach(document.body);
|
||||||
|
|
||||||
|
// Select message input when closing modal
|
||||||
|
$('.modal').on('hidden.bs.modal', (e) => {
|
||||||
|
this._chat.inputMessage.focus();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Whenever the server emits 'login', log the login message
|
||||||
|
this._socket.on('user joined', (data) => {
|
||||||
|
this._darkwire.connected = true;
|
||||||
|
this.addParticipantsMessage(data);
|
||||||
|
let importKeysPromises = this._darkwire.addUser(data);
|
||||||
|
Promise.all(importKeysPromises).then(() => {
|
||||||
|
// All users' keys have been imported
|
||||||
|
if (data.numUsers === 1) {
|
||||||
|
$('#first-modal').modal('show');
|
||||||
|
}
|
||||||
|
|
||||||
|
this._chat.log(data.username + ' joined');
|
||||||
|
this.renderParticipantsList();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
this._socket.on('user update', (data) => {
|
||||||
|
this._darkwire.updateUser(data).then((oldUsername) => {
|
||||||
|
this._chat.log(oldUsername + ' <span>changed name to</span> ' + data.username,
|
||||||
|
{
|
||||||
|
classNames: 'changed-name'
|
||||||
|
});
|
||||||
|
this.renderParticipantsList();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Whenever the server emits 'new message', update the chat body
|
||||||
|
this._socket.on('new message', (data) => {
|
||||||
|
this._darkwire.decodeMessage(data).then((decodedMessage) => {
|
||||||
|
if (!windowHandler.isActive) {
|
||||||
|
windowHandler.notifyFavicon();
|
||||||
|
this._darkwire.audio.play();
|
||||||
|
}
|
||||||
|
|
||||||
|
let data = {
|
||||||
|
username: decodedMessage.username,
|
||||||
|
message: decodedMessage.message.text,
|
||||||
|
messageType: decodedMessage.messageType,
|
||||||
|
additionalData: decodedMessage.message.additionalData
|
||||||
|
};
|
||||||
|
this._chat.addChatMessage(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
// Whenever the server emits 'user left', log it in the chat body
|
||||||
|
this._socket.on('user left', (data) => {
|
||||||
|
this._chat.log(data.username + ' left');
|
||||||
|
this.addParticipantsMessage(data);
|
||||||
|
this._chat.removeChatTyping(data);
|
||||||
|
|
||||||
|
this._darkwire.removeUser(data);
|
||||||
|
|
||||||
|
this.renderParticipantsList();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Whenever the server emits 'typing', show the typing message
|
||||||
|
this._socket.on('typing', (data) => {
|
||||||
|
this._chat.addChatTyping(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Whenever the server emits 'stop typing', kill the typing message
|
||||||
|
this._socket.on('stop typing', (data) => {
|
||||||
|
this._chat.removeChatTyping(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.initChat();
|
||||||
|
|
||||||
|
// Nav links
|
||||||
|
$('a#settings-nav').click(() => {
|
||||||
|
$('#settings-modal').modal('show');
|
||||||
|
});
|
||||||
|
|
||||||
|
$('a#about-nav').click(() => {
|
||||||
|
$('#about-modal').modal('show');
|
||||||
|
});
|
||||||
|
|
||||||
|
$('[data-toggle="tooltip"]').tooltip();
|
||||||
|
|
||||||
|
$('.navbar .participants').click(() => {
|
||||||
|
this.renderParticipantsList();
|
||||||
|
$('#participants-modal').modal('show');
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#send-message-btn').click(() => {
|
||||||
|
handleMessageSending();
|
||||||
|
this._socket.emit('stop typing');
|
||||||
|
this._chat.typing = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
$('.navbar-collapse ul li a').click(() => {
|
||||||
|
$('.navbar-toggle:visible').click();
|
||||||
|
});
|
||||||
|
|
||||||
|
let audioSwitch = $('input.sound-enabled').bootstrapSwitch();
|
||||||
|
|
||||||
|
audioSwitch.on('switchChange.bootstrapSwitch', (event, state) => {
|
||||||
|
this._darkwire.audio.soundEnabled = state;
|
||||||
|
});
|
||||||
|
|
||||||
|
window.handleMessageSending = () => {
|
||||||
|
let message = this._chat.inputMessage;
|
||||||
|
let cleanedMessage = this.cleanInput(message.val());
|
||||||
|
let slashCommand = this._chat.parseCommand(cleanedMessage);
|
||||||
|
|
||||||
|
if (slashCommand) {
|
||||||
|
return this._chat.executeCommand(slashCommand, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prevent markup from being injected into the message
|
||||||
|
this._darkwire.encodeMessage(cleanedMessage, 'text').then((socketData) => {
|
||||||
|
message.val('');
|
||||||
|
$('#send-message-btn').removeClass('active');
|
||||||
|
// Add escaped message since message did not come from the server
|
||||||
|
this._chat.addChatMessage({
|
||||||
|
username: username,
|
||||||
|
message: escape(cleanedMessage)
|
||||||
|
});
|
||||||
|
this._socket.emit('new message', socketData);
|
||||||
|
}).catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
window.triggerFileTransfer = (context) => {
|
||||||
|
const fileId = context.getAttribute('data-file');
|
||||||
|
if (fileId) {
|
||||||
|
return windowHandler.fileHandler.encodeFile(fileId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._chat.log('Requested file transfer is no longer valid. Please try again.', {error: true});
|
||||||
|
};
|
||||||
|
|
||||||
|
window.triggerFileDestroy = (context) => {
|
||||||
|
const fileId = context.getAttribute('data-file');
|
||||||
|
if (fileId) {
|
||||||
|
return windowHandler.fileHandler.destroyFile(fileId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._chat.log('Requested file transfer is no longer valid. Please try again.', {error: true});
|
||||||
|
};
|
||||||
|
|
||||||
|
window.triggerFileDownload = (context) => {
|
||||||
|
const fileId = context.getAttribute('data-file');
|
||||||
|
const file = this._darkwire.getFile(fileId);
|
||||||
|
windowHandler.fileHandler.createBlob(file.message, file.messageType).then((blob) => {
|
||||||
|
let url = windowHandler.fileHandler.createUrlFromBlob(blob);
|
||||||
|
|
||||||
|
if (file) {
|
||||||
|
if (file.messageType.match('image.*')) {
|
||||||
|
let image = new Image();
|
||||||
|
image.src = url;
|
||||||
|
this._chat.replaceMessage('#file-transfer-request-' + fileId, image);
|
||||||
|
} else {
|
||||||
|
let downloadLink = document.createElement('a');
|
||||||
|
downloadLink.href = url;
|
||||||
|
downloadLink.target = '_blank';
|
||||||
|
downloadLink.innerHTML = 'Download ' + file.additionalData.fileName;
|
||||||
|
this._chat.replaceMessage('#file-transfer-request-' + fileId, downloadLink);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this._darkwire.encodeMessage('Accepted <strong>' + file.additionalData.fileName + '</strong>', 'text').then((socketData) => {
|
||||||
|
this._socket.emit('new message', socketData);
|
||||||
|
}).catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prevents input from having injected markup
|
||||||
|
cleanInput(input) {
|
||||||
|
input = input.replace(/\r?\n/g, '<br />');
|
||||||
|
let sanitized = he.encode(input);
|
||||||
|
sanitized = Autolinker.link(sanitized);
|
||||||
|
return sanitized;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets the client's username
|
||||||
|
initChat() {
|
||||||
|
|
||||||
|
// Warn if not incognito
|
||||||
|
// FileSystem API is disabled in incognito mode, so we can use that to check
|
||||||
|
let fs = window.requestFileSystem || window.webkitRequestFileSystem;
|
||||||
|
if (fs) {
|
||||||
|
fs(window.TEMPORARY, 100, () => {
|
||||||
|
this._chat.log('Your browser is not in incognito mode!', {warning: true});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this._chat.log(moment().format('MMMM Do YYYY, h:mm:ss a'), {info: true});
|
||||||
|
this._darkwire.updateUsername(username).then((socketData) => {
|
||||||
|
this._chat.chatPage.show();
|
||||||
|
this._chat.inputMessage.focus();
|
||||||
|
this._socket.emit('add user', socketData);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
addParticipantsMessage(data) {
|
||||||
|
let message = '';
|
||||||
|
let headerMsg = '';
|
||||||
|
|
||||||
|
$('#participants').text(data.numUsers);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderParticipantsList() {
|
||||||
|
$('#participants-modal ul.users').empty();
|
||||||
|
_.each(this._darkwire.users, (user) => {
|
||||||
|
let li;
|
||||||
|
if (user.username === window.username) {
|
||||||
|
// User is me
|
||||||
|
li = $('<li class="yourself">' + user.username + ' <span class="you">(you)</span></li>').css('color', this._chat.getUsernameColor(user.username));
|
||||||
|
} else {
|
||||||
|
li = $('<li>' + user.username + '</li>').css('color', this._chat.getUsernameColor(user.username));
|
||||||
|
}
|
||||||
|
$('#participants-modal ul.users')
|
||||||
|
.append(li);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
262
src/js/main.js
262
src/js/main.js
@ -1,261 +1,5 @@
|
|||||||
import _ from 'underscore';
|
import App from './app';
|
||||||
import Darkwire from './darkwire';
|
|
||||||
import WindowHandler from './window';
|
|
||||||
import CryptoUtil from './crypto';
|
|
||||||
import Chat from './chat';
|
|
||||||
import moment from 'moment';
|
|
||||||
import sanitizeHtml from 'sanitize-html';
|
|
||||||
import he from 'he';
|
|
||||||
|
|
||||||
let fs = window.RequestFileSystem || window.webkitRequestFileSystem;
|
|
||||||
|
|
||||||
$(function() {
|
|
||||||
const darkwire = new Darkwire();
|
|
||||||
const cryptoUtil = new CryptoUtil();
|
|
||||||
|
|
||||||
let $participants = $('#participants');
|
|
||||||
|
|
||||||
let roomId = window.location.pathname.length ? window.location.pathname : null;
|
|
||||||
|
|
||||||
if (!roomId) { return; }
|
|
||||||
|
|
||||||
$('input.share-text').val(document.location.protocol + '//' + document.location.host + roomId);
|
|
||||||
|
|
||||||
$('input.share-text').click(function() {
|
|
||||||
$(this).focus();
|
|
||||||
$(this).select();
|
|
||||||
this.setSelectionRange(0, 9999);
|
|
||||||
});
|
|
||||||
|
|
||||||
let socket = io(roomId);
|
|
||||||
const chat = new Chat(darkwire, socket);
|
|
||||||
const windowHandler = new WindowHandler(darkwire, socket, chat);
|
|
||||||
|
|
||||||
FastClick.attach(document.body);
|
|
||||||
|
|
||||||
function addParticipantsMessage(data) {
|
|
||||||
let message = '';
|
|
||||||
let headerMsg = '';
|
|
||||||
|
|
||||||
$participants.text(data.numUsers);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sets the client's username
|
|
||||||
function initChat() {
|
|
||||||
// warn not incognitor
|
|
||||||
if (fs) {
|
|
||||||
fs(window.TEMPORARY,
|
|
||||||
100,
|
|
||||||
() => {
|
|
||||||
chat.log('Your browser is not in incognito mode!', {warning: true});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
chat.log(moment().format('MMMM Do YYYY, h:mm:ss a'), {info: true});
|
|
||||||
darkwire.updateUsername(username).then((socketData) => {
|
|
||||||
chat.chatPage.show();
|
|
||||||
chat.inputMessage.focus();
|
|
||||||
socket.emit('add user', socketData);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prevents input from having injected markup
|
|
||||||
function cleanInput(input) {
|
|
||||||
input = input.replace(/\r?\n/g, '<br />');
|
|
||||||
let sanitized = he.encode(input);
|
|
||||||
sanitized = Autolinker.link(sanitized);
|
|
||||||
return sanitized;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Select message input when closing modal
|
|
||||||
$('.modal').on('hidden.bs.modal', function(e) {
|
|
||||||
chat.inputMessage.focus();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Whenever the server emits 'login', log the login message
|
|
||||||
socket.on('user joined', function(data) {
|
|
||||||
darkwire.connected = true;
|
|
||||||
addParticipantsMessage(data);
|
|
||||||
let importKeysPromises = darkwire.addUser(data);
|
|
||||||
Promise.all(importKeysPromises).then(() => {
|
|
||||||
// All users' keys have been imported
|
|
||||||
if (data.numUsers === 1) {
|
|
||||||
$('#first-modal').modal('show');
|
|
||||||
}
|
|
||||||
|
|
||||||
chat.log(data.username + ' joined');
|
|
||||||
renderParticipantsList();
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.on('user update', (data) => {
|
|
||||||
darkwire.updateUser(data).then((oldUsername) => {
|
|
||||||
chat.log(oldUsername + ' <span>changed name to</span> ' + data.username,
|
|
||||||
{
|
|
||||||
classNames: 'changed-name'
|
|
||||||
});
|
|
||||||
renderParticipantsList();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Whenever the server emits 'new message', update the chat body
|
|
||||||
socket.on('new message', function(data) {
|
|
||||||
darkwire.decodeMessage(data).then((decodedMessage) => {
|
|
||||||
if (!windowHandler.isActive) {
|
|
||||||
windowHandler.notifyFavicon();
|
|
||||||
darkwire.audio.play();
|
|
||||||
}
|
|
||||||
|
|
||||||
let data = {
|
|
||||||
username: decodedMessage.username,
|
|
||||||
message: decodedMessage.message.text,
|
|
||||||
messageType: decodedMessage.messageType,
|
|
||||||
additionalData: decodedMessage.message.additionalData
|
|
||||||
};
|
|
||||||
chat.addChatMessage(data);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
// Whenever the server emits 'user left', log it in the chat body
|
|
||||||
socket.on('user left', function(data) {
|
|
||||||
chat.log(data.username + ' left');
|
|
||||||
addParticipantsMessage(data);
|
|
||||||
chat.removeChatTyping(data);
|
|
||||||
|
|
||||||
darkwire.removeUser(data);
|
|
||||||
|
|
||||||
renderParticipantsList();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Whenever the server emits 'typing', show the typing message
|
|
||||||
socket.on('typing', function(data) {
|
|
||||||
chat.addChatTyping(data);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Whenever the server emits 'stop typing', kill the typing message
|
|
||||||
socket.on('stop typing', function(data) {
|
|
||||||
chat.removeChatTyping(data);
|
|
||||||
});
|
|
||||||
|
|
||||||
initChat();
|
|
||||||
|
|
||||||
// Nav links
|
|
||||||
$('a#settings-nav').click(function() {
|
|
||||||
$('#settings-modal').modal('show');
|
|
||||||
});
|
|
||||||
|
|
||||||
$('a#about-nav').click(function() {
|
|
||||||
$('#about-modal').modal('show');
|
|
||||||
});
|
|
||||||
|
|
||||||
$('[data-toggle="tooltip"]').tooltip();
|
|
||||||
|
|
||||||
$('.navbar .participants').click(function() {
|
|
||||||
renderParticipantsList();
|
|
||||||
$('#participants-modal').modal('show');
|
|
||||||
});
|
|
||||||
|
|
||||||
function renderParticipantsList() {
|
|
||||||
$('#participants-modal ul.users').empty();
|
|
||||||
_.each(darkwire.users, function(user) {
|
|
||||||
let li;
|
|
||||||
if (user.username === window.username) {
|
|
||||||
// User is me
|
|
||||||
li = $('<li class="yourself">' + user.username + ' <span class="you">(you)</span></li>').css('color', chat.getUsernameColor(user.username));
|
|
||||||
} else {
|
|
||||||
li = $('<li>' + user.username + '</li>').css('color', chat.getUsernameColor(user.username));
|
|
||||||
}
|
|
||||||
$('#participants-modal ul.users')
|
|
||||||
.append(li);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
$('#send-message-btn').click(function() {
|
|
||||||
handleMessageSending();
|
|
||||||
socket.emit('stop typing');
|
|
||||||
chat.typing = false;
|
|
||||||
});
|
|
||||||
|
|
||||||
$('.navbar-collapse ul li a').click(function() {
|
|
||||||
$('.navbar-toggle:visible').click();
|
|
||||||
});
|
|
||||||
|
|
||||||
let audioSwitch = $('input.sound-enabled').bootstrapSwitch();
|
|
||||||
|
|
||||||
audioSwitch.on('switchChange.bootstrapSwitch', function(event, state) {
|
|
||||||
darkwire.audio.soundEnabled = state;
|
|
||||||
});
|
|
||||||
|
|
||||||
window.handleMessageSending = function() {
|
|
||||||
let message = chat.inputMessage;
|
|
||||||
let cleanedMessage = cleanInput(message.val());
|
|
||||||
let slashCommand = chat.parseCommand(cleanedMessage);
|
|
||||||
|
|
||||||
if (slashCommand) {
|
|
||||||
return chat.executeCommand(slashCommand, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prevent markup from being injected into the message
|
|
||||||
darkwire.encodeMessage(cleanedMessage, 'text').then((socketData) => {
|
|
||||||
message.val('');
|
|
||||||
$('#send-message-btn').removeClass('active');
|
|
||||||
// Add escaped message since message did not come from the server
|
|
||||||
chat.addChatMessage({
|
|
||||||
username: username,
|
|
||||||
message: escape(cleanedMessage)
|
|
||||||
});
|
|
||||||
socket.emit('new message', socketData);
|
|
||||||
}).catch((err) => {
|
|
||||||
console.log(err);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
window.triggerFileTransfer = function(context) {
|
|
||||||
const fileId = context.getAttribute('data-file');
|
|
||||||
if (fileId) {
|
|
||||||
return windowHandler.fileHandler.encodeFile(fileId);
|
|
||||||
}
|
|
||||||
|
|
||||||
return chat.log('Requested file transfer is no longer valid. Please try again.', {error: true});
|
|
||||||
};
|
|
||||||
|
|
||||||
window.triggerFileDestroy = function(context) {
|
|
||||||
const fileId = context.getAttribute('data-file');
|
|
||||||
if (fileId) {
|
|
||||||
return windowHandler.fileHandler.destroyFile(fileId);
|
|
||||||
}
|
|
||||||
|
|
||||||
return chat.log('Requested file transfer is no longer valid. Please try again.', {error: true});
|
|
||||||
};
|
|
||||||
|
|
||||||
window.triggerFileDownload = function(context) {
|
|
||||||
const fileId = context.getAttribute('data-file');
|
|
||||||
const file = darkwire.getFile(fileId);
|
|
||||||
windowHandler.fileHandler.createBlob(file.message, file.messageType).then((blob) => {
|
|
||||||
let url = windowHandler.fileHandler.createUrlFromBlob(blob);
|
|
||||||
|
|
||||||
if (file) {
|
|
||||||
if (file.messageType.match('image.*')) {
|
|
||||||
let image = new Image();
|
|
||||||
image.src = url;
|
|
||||||
chat.replaceMessage('#file-transfer-request-' + fileId, image);
|
|
||||||
} else {
|
|
||||||
let downloadLink = document.createElement('a');
|
|
||||||
downloadLink.href = url;
|
|
||||||
downloadLink.target = '_blank';
|
|
||||||
downloadLink.innerHTML = 'Download ' + file.additionalData.fileName;
|
|
||||||
chat.replaceMessage('#file-transfer-request-' + fileId, downloadLink);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
darkwire.encodeMessage('Accepted <strong>' + file.additionalData.fileName + '</strong>', 'text').then((socketData) => {
|
|
||||||
socket.emit('new message', socketData);
|
|
||||||
}).catch((err) => {
|
|
||||||
console.log(err);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
|
$(() => {
|
||||||
|
let app = new App();
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user