diff --git a/src/js/app.js b/src/js/app.js new file mode 100644 index 0000000..ddecb8d --- /dev/null +++ b/src/js/app.js @@ -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 + ' changed name to ' + 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 ' + file.additionalData.fileName + '', '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, '
'); + 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 = $('
  • ' + user.username + ' (you)
  • ').css('color', this._chat.getUsernameColor(user.username)); + } else { + li = $('
  • ' + user.username + '
  • ').css('color', this._chat.getUsernameColor(user.username)); + } + $('#participants-modal ul.users') + .append(li); + }); + } + +} diff --git a/src/js/main.js b/src/js/main.js index 02259a3..68313da 100644 --- a/src/js/main.js +++ b/src/js/main.js @@ -1,261 +1,5 @@ -import _ from 'underscore'; -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, '
    '); - 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 + ' changed name to ' + 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 = $('
  • ' + user.username + ' (you)
  • ').css('color', chat.getUsernameColor(user.username)); - } else { - li = $('
  • ' + user.username + '
  • ').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 ' + file.additionalData.fileName + '', 'text').then((socketData) => { - socket.emit('new message', socketData); - }).catch((err) => { - console.log(err); - }); - - }); - }; +import App from './app'; +$(() => { + let app = new App(); });