diff --git a/src/webapp.jsx b/src/webapp.jsx index 211085d6..eeb0a7b8 100644 --- a/src/webapp.jsx +++ b/src/webapp.jsx @@ -19,9 +19,9 @@ if (typeof require == 'function') { } // Name of this application, used in the User-Agent. -const APP_NAME = "TinodeWeb/" + (package_version || "0.15"); +const APP_NAME = 'TinodeWeb/' + (package_version || '0.15'); -const KNOWN_HOSTS = {hosted: "api.tinode.co", local: "localhost:6060"}; +const KNOWN_HOSTS = {hosted: 'api.tinode.co', local: 'localhost:6060'}; // Default host name and port to connect to. const DEFAULT_HOST = KNOWN_HOSTS.hosted; // var DEFAULT_HOST = KNOWN_HOSTS.local; @@ -30,7 +30,7 @@ const DEFAULT_HOST = KNOWN_HOSTS.hosted; const POP_SOUND = new Audio('audio/msg.mp3'); // API key. Use https://github.com/tinode/chat/tree/master/keygen to generate your own -const API_KEY = "AQEAAAABAAD_rAp4DJh05a1HAwFT3A6K"; +const API_KEY = 'AQEAAAABAAD_rAp4DJh05a1HAwFT3A6K'; // Minimum time between two keypress notifications, milliseconds. const KEYPRESS_DELAY = 3*1000; @@ -197,7 +197,7 @@ function base64DecodedLen(n) { // The string may be base64-URL encoded without the padding. function base64ReEncode(str) { if (str) { - str = str.replace("-", "+").replace("_", "/"); + str = str.replace('-', '+').replace('_', '/'); try { str = btoa(atob(str)); } catch(err) { @@ -222,7 +222,7 @@ function imageFileScaledToBase64(file, width, height, forceSquare, onSuccess, on onError("Invalid image"); return; } - var canvas = document.createElement("canvas"); + var canvas = document.createElement('canvas'); canvas.width = dim.dstWidth; canvas.height = dim.dstHeight; var ctx = canvas.getContext('2d'); @@ -232,7 +232,7 @@ function imageFileScaledToBase64(file, width, height, forceSquare, onSuccess, on var mime = (this.width != dim.dstWidth || this.height != dim.dstHeight || - SUPPORTED_IMAGE_FORMATS.indexOf(file.type) < 0) ? "image/jpeg" : file.type; + SUPPORTED_IMAGE_FORMATS.indexOf(file.type) < 0) ? 'image/jpeg' : file.type; var imageBits = canvas.toDataURL(mime); var parts = imageBits.split(','); // Get actual image type: 'data:image/png;base64,' @@ -244,9 +244,9 @@ function imageFileScaledToBase64(file, width, height, forceSquare, onSuccess, on // Ensure the image is not too large var quality = 0.78; if (base64DecodedLen(imageBits.length) > MAX_INBAND_ATTACHMENT_SIZE) { - mime = "image/jpeg"; + mime = 'image/jpeg'; } - if (mime == "image/jpeg") { + if (mime == 'image/jpeg') { // Reduce size of the jpeg by reducing image quality while (base64DecodedLen(imageBits.length) > MAX_INBAND_ATTACHMENT_SIZE && quality > 0.45) { imageBits = canvas.toDataURL(mime, quality); @@ -267,7 +267,7 @@ function imageFileScaledToBase64(file, width, height, forceSquare, onSuccess, on // Convert uploaded image file to base64-encoded string without scaling/converting the image function imageFileToBase64(file, onSuccess, onError) { var reader = new FileReader(); - reader.addEventListener("load", function() { + reader.addEventListener('load', function() { var parts = reader.result.split(','); var mime = getMimeType(parts[0]); if (!mime) { @@ -291,7 +291,7 @@ function imageFileToBase64(file, onSuccess, onError) { function fileToBase64(file, onSuccess, onError) { var reader = new FileReader(); - reader.addEventListener("load", function() { + reader.addEventListener('load', function() { onSuccess(file.type, reader.result.split(',')[1], file.name); }); reader.readAsDataURL(file); @@ -303,13 +303,13 @@ function filePasted(event, onImageSuccess, onAttachmentSuccess, onError) { var items = (event.clipboardData || event.originalEvent.clipboardData || {}).items; for (var i in items) { var item = items[i]; - if (item.kind === "file") { + if (item.kind === 'file') { var file = item.getAsFile(); if (!file) { console.log("Failed to get file object from pasted file item", item.kind, item.type); continue; } - if (file.type && file.type.split("/")[0] == "image") { + if (file.type && file.type.split('/')[0] == 'image') { // Handle inline image if (file.size > MAX_INBAND_ATTACHMENT_SIZE || SUPPORTED_IMAGE_FORMATS.indexOf(file.type) < 0) { imageFileScaledToBase64(file, MAX_IMAGE_DIM, MAX_IMAGE_DIM, false, onImageSuccess, onError); @@ -330,27 +330,27 @@ function filePasted(event, onImageSuccess, onAttachmentSuccess, onError) { // Make shortcut icon appear with a green dot + show unread count in title. function updateFavicon(count) { - var oldIcon = document.getElementById("shortcut-icon"); + var oldIcon = document.getElementById('shortcut-icon'); if (oldIcon) { var head = document.head || document.getElementsByTagName('head')[0]; var newIcon = document.createElement('link'); - newIcon.type = "image/png"; - newIcon.id = "shortcut-icon"; - newIcon.rel = "shortcut icon"; - newIcon.href = "img/logo32x32" + (count > 0 ? 'a' : '') + ".png"; + newIcon.type = 'image/png'; + newIcon.id = 'shortcut-icon'; + newIcon.rel = 'shortcut icon'; + newIcon.href = 'img/logo32x32' + (count > 0 ? 'a' : '') + '.png'; head.removeChild(oldIcon); head.appendChild(newIcon); } - document.title = (count > 0 ? '('+count+') ' : '') + "Tinode"; + document.title = (count > 0 ? '('+count+') ' : '') + 'Tinode'; } // Get 32 bit integer hash value for a string. Ideally it should produce the same value // as Java's String#hash(). function stringHash(value) { var hash = 0; - value = "" + value; + value = '' + value; for (var i = 0; i < value.length; i++) { - hash = ((hash<<5)-hash) + value.charCodeAt(i); + hash = ((hash << 5) - hash) + value.charCodeAt(i); hash = hash & hash; // Convert to 32bit integer } return hash; @@ -366,11 +366,11 @@ function parseUrlHash(hash) { let params = {}; let path = []; if (parts[0]) { - path = parts[0].substr(1).split("/"); + path = parts[0].substr(1).split('/'); } if (parts[1]) { - parts[1].split("&").forEach(function(part) { - let item = part.split("="); + parts[1].split('&').forEach(function(part) { + let item = part.split('='); if (item[0]) { params[decodeURIComponent(item[0])] = decodeURIComponent(item[1]); } @@ -384,15 +384,15 @@ function navigateTo(url) { } function composeUrlHash(path, params) { - var url = path.join("/"); + var url = path.join('/'); var args = []; for (var key in params) { if (params.hasOwnProperty(key)) { - args.push(key + "=" + params[key]); + args.push(key + '=' + params[key]); } } if (args.length > 0) { - url += "?" + args.join("&"); + url += '?' + args.join('&'); } return url; } @@ -461,10 +461,10 @@ function vcard(fn, imageDataUrl) { card.fn = fn.trim(); } if (imageDataUrl) { - var dataStart = imageDataUrl.indexOf(","); + var dataStart = imageDataUrl.indexOf(','); card.photo = { data: imageDataUrl.substring(dataStart+1), - type: "jpg" + type: 'jpg' }; } } @@ -500,25 +500,25 @@ class ContextMenu extends React.Component { // Preconfigured menu items. this.MenuItems = { - "topic_info": {title: "Info", handler: null}, + 'topic_info': {title: "Info", handler: null}, - "messages_clear": {title: "Clear messages", handler: (params, errorHandler) => { + 'messages_clear': {title: "Clear messages", handler: (params, errorHandler) => { this.deleteMessages(true, false, params, errorHandler); }}, - "messages_clear_hard": {title: "Clear for All", handler: (params, errorHandler) => { + 'messages_clear_hard': {title: "Clear for All", handler: (params, errorHandler) => { this.deleteMessages(true, true, params, errorHandler); }}, - "message_delete": {title: "Delete", handler: (params, errorHandler) => { + 'message_delete': {title: "Delete", handler: (params, errorHandler) => { this.deleteMessages(false, false, params, errorHandler); }}, - "message_delete_hard": {title: "Delete for All", handler: (params, errorHandler) => { + 'message_delete_hard': {title: "Delete for All", handler: (params, errorHandler) => { this.deleteMessages(false, true, params, errorHandler); }}, - "topic_unmute": {title: "Unmute", handler: this.topicPermissionSetter.bind(this, "+P")}, - "topic_mute": {title: "Mute", handler: this.topicPermissionSetter.bind(this, "-P")}, - "topic_unblock": {title: "Unblock", handler: this.topicPermissionSetter.bind(this, "+J")}, - "topic_block": {title: "Block", handler: this.topicPermissionSetter.bind(this, "-J")}, - "topic_delete": {title: "Delete", handler: (params, errorHandler) => { + 'topic_unmute': {title: "Unmute", handler: this.topicPermissionSetter.bind(this, '+P')}, + 'topic_mute': {title: "Mute", handler: this.topicPermissionSetter.bind(this, '-P')}, + 'topic_unblock': {title: "Unblock", handler: this.topicPermissionSetter.bind(this, '+J')}, + 'topic_block': {title: "Block", handler: this.topicPermissionSetter.bind(this, '-J')}, + 'topic_delete': {title: "Delete", handler: (params, errorHandler) => { let topic = this.props.tinode.getTopic(params.topicName); if (!topic) { console.log("Topic not found: ", params.topicName); @@ -526,13 +526,13 @@ class ContextMenu extends React.Component { } topic.delTopic().catch((err) => { if (errorHandler) { - errorHandler(err.message, "err"); + errorHandler(err.message, 'err'); } }); }}, - "permissions": {title: "Edit permissions", handler: null}, - "member_delete": {title: "Remove", handler: (params, errorHandler) => { + 'permissions': {title: "Edit permissions", handler: null}, + 'member_delete': {title: "Remove", handler: (params, errorHandler) => { let topic = this.props.tinode.getTopic(params.topicName); if (!topic || !params.user) { console.log("Topic or user not found: '" + params.topicName + "', '" + params.user + "'"); @@ -540,14 +540,14 @@ class ContextMenu extends React.Component { } topic.delSubscription(params.user).catch((err) => { if (errorHandler) { - errorHandler(err.message, "err"); + errorHandler(err.message, 'err'); } }); }}, - "member_mute": {title: "Mute", handler: this.topicPermissionSetter.bind(this, "-P")}, - "member_unmute": {title: "Unmute", handler: this.topicPermissionSetter.bind(this, "+P")}, - "member_block": {title: "Block", handler: this.topicPermissionSetter.bind(this, "-J")}, - "member_unblock": {title: "Unblock", handler: this.topicPermissionSetter.bind(this, "+J")}, + 'member_mute': {title: "Mute", handler: this.topicPermissionSetter.bind(this, '-P')}, + 'member_unmute': {title: "Unmute", handler: this.topicPermissionSetter.bind(this, '+P')}, + 'member_block': {title: "Block", handler: this.topicPermissionSetter.bind(this, '-J')}, + 'member_unblock': {title: "Unblock", handler: this.topicPermissionSetter.bind(this, '+J')}, }; } @@ -606,7 +606,7 @@ class ContextMenu extends React.Component { topic.delMessagesList([params.seq], hard); promise.catch((err) => { if (errorHandler) { - errorHandler(err.message, "err"); + errorHandler(err.message, 'err'); } }); } @@ -633,7 +633,7 @@ class ContextMenu extends React.Component { topic.setMeta({sub: {user: params.user, mode: am}}).catch((err) => { if (errorHandler) { - errorHandler(err.message, "err"); + errorHandler(err.message, 'err'); } }); } @@ -647,7 +647,7 @@ class ContextMenu extends React.Component { } if (item && item.title) { menu.push( - item.title == "-" ? + item.title == '-' ?
: