diff --git a/index.html b/index.html index d00c83a6..57c9ca0a 100644 --- a/index.html +++ b/index.html @@ -84,7 +84,7 @@ var MAX_IMAGE_SIZE = 768; // Supported image MIME types and corresponding file extensions. - var SUPPORTED_FORMATS = ['image/jpeg', 'image/gif', 'image/png', 'image/svg', 'image/svg+xml']; + var SUPPORTED_IMAGE_FORMATS = ['image/jpeg', 'image/gif', 'image/png', 'image/svg', 'image/svg+xml']; var MIME_EXTENSIONS = ['jpg', 'gif', 'png', 'svg', 'svg']; // Helper functions for storing values in localStorage. @@ -113,6 +113,19 @@ {hour12: false, year: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit'}); } + // Convert a number of bytes to human-readable format. + function bytesToHumanSize(bytes) { + if (!bytes || bytes == 0) { + return '0 Bytes'; + } + + var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']; + var bucket = Math.floor(Math.log2(bytes) / 10) | 0; + var count = bytes / Math.pow(1024, bucket); + var round = bucket > 0 ? (count < 10 ? 2 : (count < 100 ? 1 : 0)) : 0; + return count.toFixed(round) + ' ' + sizes[bucket]; + } + // Make a data URL from public.photo function makeImageUrl(photo) { return (photo && photo.type && photo.data) ? @@ -141,7 +154,7 @@ // Ensure file's extension matches mime content type function fileNameForMime(fname, mime) { - var idx = SUPPORTED_FORMATS.indexOf(mime); + var idx = SUPPORTED_IMAGE_FORMATS.indexOf(mime); var ext = MIME_EXTENSIONS[idx]; var at = fname.lastIndexOf('.'); @@ -187,7 +200,7 @@ ctx.drawImage(this, 0, 0, this.width, this.height, 0, 0, canvas.width, canvas.height); } - var mime = (forceSquare || SUPPORTED_FORMATS.indexOf(file.type) < 0) ? "image/jpeg" : file.type; + var mime = (forceSquare || 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,' @@ -216,12 +229,12 @@ // Convert uploaded image file to base64-encoded string without scaling/converting the image function imageFileToBase64(file, onSuccess, onError) { if (file.size > MAX_ATTACHMENT_SIZE) { - onError("The file size " + bytesToHumanSize(file.size) + + onError("The image size " + bytesToHumanSize(file.size) + " exceeds the " + bytesToHumanSize(MAX_ATTACHMENT_SIZE) + " limit.", "err"); return; } - var reader = new FileReader(); + var reader = new FileReader(); reader.addEventListener("load", function() { var parts = reader.result.split(','); var mime = getMimeType(parts[0]); @@ -244,6 +257,45 @@ reader.readAsDataURL(file); } + function fileToBase64(file, onSuccess, onError) { + if (file.size <= MAX_ATTACHMENT_SIZE) { + var reader = new FileReader(); + reader.addEventListener("load", function() { + onSuccess(file.type, reader.result.split(',')[1], file.name); + }); + reader.readAsDataURL(file); + } else { + onError("The file size " + bytesToHumanSize(file.size) + + " exceeds the " + bytesToHumanSize(MAX_ATTACHMENT_SIZE) + " limit.", "err"); + } + } + + // File pasted from the clipboard. It's either an inline image or a file attachment. + 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") { + var file = item.getAsFile(); + if (file.type.split("/")[0] == "image") { + // Handle inline image + if (file.size > MAX_ATTACHMENT_SIZE) { + imageFileScaledToBase64(file, MAX_IMAGE_SIZE, MAX_IMAGE_SIZE, false, onImageSuccess, onError); + } else { + imageFileToBase64(file, onImageSuccess, onError); + } + } else { + // Handle file attachment + fileToBase64(file, onAttachmentSuccess, onError) + } + // Indicate that the pasted data contains a file. + return true; + } + } + // No file found. + return false; + } + // Make shortcut icon appear with a green dot + show unread count in title. function updateFavicon(count) { var oldIcon = document.getElementById("shortcut-icon"); @@ -383,19 +435,6 @@ return true; } - // Convert a number of bytes to human-readable format. - function bytesToHumanSize(bytes) { - if (!bytes || bytes == 0) { - return '0 Bytes'; - } - - var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']; - var bucket = Math.floor(Math.log2(bytes) / 10) | 0; - var count = bytes / Math.pow(1024, bucket); - var round = bucket > 0 ? (count < 10 ? 2 : (count < 100 ? 1 : 0)) : 0; - return count.toFixed(round) + ' ' + sizes[bucket]; - } - /* BEGIN Context Menu: popup/dropdown menu */ // Function is used by context menu to set permissions. @@ -3630,12 +3669,40 @@ }; }, + componentDidMount: function() { + this.pasteFile.addEventListener('paste', this.handlePasteEvent, false); + }, + + componentWillUnmount: function() { + this.pasteFile.removeEventListener('paste', this.handlePasteEvent, false) + }, + + handlePasteEvent: function(e) { + if (this.props.disabled) { + return; + } + var instance = this; + if (filePasted(e, + function(bits, mime, width, height, fname) { + instance.props.sendMessage(Drafty.insertImage(null, + 0, mime, bits, width, height, fname)); + }, + function(mime, bits, fname) { + instance.props.sendMessage(Drafty.attachFile(null, mime, bits, fname)); + }, + instance.props.onError)) { + + // If file was pasted, don't paste base64 daata into input field. + e.preventDefault(); + } + }, + handleAttachImage: function(e) { if (e.target.files && e.target.files.length > 0) { var instance = this; var files = e.target.files; // Check if the uploaded file is indeed an image and if it isn't too large. - if (files[0].size > MAX_ATTACHMENT_SIZE || SUPPORTED_FORMATS.indexOf(files[0].type) < 0) { + if (files[0].size > MAX_ATTACHMENT_SIZE || SUPPORTED_IMAGE_FORMATS.indexOf(files[0].type) < 0) { // Convert image for size or format. imageFileScaledToBase64(files[0], MAX_IMAGE_SIZE, MAX_IMAGE_SIZE, false, // Success @@ -3667,19 +3734,12 @@ handleAttachFile: function(e) { if (e.target.files && e.target.files.length > 0) { - var file = e.target.files[0]; - if (file.size > MAX_ATTACHMENT_SIZE) { - this.props.onError("The file size " + bytesToHumanSize(file.size) + - " exceeds the " + bytesToHumanSize(MAX_ATTACHMENT_SIZE) + " attachment limit.", "err"); - return; - } - - var reader = new FileReader(); var instance = this; - reader.addEventListener("load", function() { - instance.props.sendMessage(Drafty.attachFile(null, file.type, reader.result.split(',')[1], file.name)); - }, false); - reader.readAsDataURL(file); + fileToBase64(e.target.files[0], + function(mime, bits, fname) { + instance.props.sendMessage(Drafty.attachFile(null, mime, bits, fname)); + }, + this.props.onError); } // Clear the value so the same file can be uploaded again. e.target.value = ''; @@ -3735,6 +3795,7 @@