diff --git a/src/inline-attachment.js b/src/inline-attachment.js index 9314586..e52e447 100644 --- a/src/inline-attachment.js +++ b/src/inline-attachment.js @@ -23,11 +23,102 @@ */ inlineAttachment.editors = {}; + /** + * Global variables used on a page + */ + inlineAttachment.globals = { + /** + * The last focused editor, used to switch back after + * pasting an image using a pasteElement + * + * @type {HtmlElement} + */ + lastFocusedEditor: null + }; + /** * Utility functions */ inlineAttachment.util = { + /** + * Simple browser sniffing + */ + browser: { + isFirefox: (typeof window.mozInnerScreenX !== 'undefined') + }, + + /** + * Hooks into the Ctrl + V event of the given inlineAttachment element + * + * @param {inlineAttachment} inlineAttach inlineAttachment instance + * @return {Void} + */ + initPasteElement: function(inlineAttach) { + inlineAttach.editor.getElement().addEventListener("keydown", function(e){ + inlineAttachment.globals.lastFocusedEditor = this; + // Listen for Ctrl + V + if (e.ctrlKey && e.keyCode === 86) { + inlineAttach.editor.getPasteElement().focus(); + setTimeout(function() { + inlineAttachment.util.checkPasteElementForInput(inlineAttach); + }, 1); + } + }); + }, + + /** + * Creates a new PasteElement, this is a div in which paste data will be captured. + * Used for browsers who do not support clipboard data like Firefox + * + * @return {Void} + */ + createPasteElement: function() { + var pasteElement = document.createElement("div"); + pasteElement.opacity = 0; + // Firefox allows images to be pasted into contenteditable elements + pasteElement.setAttribute("contenteditable", ""); + + // We can hide the element and append it to the body, + pasteElement.style.opacity = 0; + document.body.appendChild(pasteElement); + return pasteElement; + }, + + /** + * Checks the given inlineAttachment element for a paste element + * and checks if it contains an image. + * + * If an image is found then capture it and upload it + * After that refocus the last inlineAttachment editor + * + * @param {InlineAttachment} inlineAttach + * @return {Void} + */ + checkPasteElementForInput: function(inlineAttach) { + // Store the pasted content in a variable + var pasteElement = inlineAttach.editor.getPasteElement(), + child = pasteElement.childNodes[0]; + + // Clear the inner html to make sure we're always + // getting the latest inserted content + pasteElement.innerHTML = ""; + if (child) { + if (child.tagName === "IMG") { + var pastedImage = new Image(); + pastedImage.onload = function() { + var imageFile = inlineAttachment.util.dataURItoBlob(pastedImage.src); + if (inlineAttach.isFileAllowed(imageFile)) { + inlineAttach.onFileInserted(imageFile); + inlineAttach.uploadFile(imageFile); + } + }; + pastedImage.src = child.src; + } + } + inlineAttachment.globals.lastFocusedEditor.focus(); + }, + /** * Simple function to merge the given objects * @@ -103,6 +194,34 @@ el.focus(); } el.scrollTop = scrollPos; + }, + + /** + * Converts a dataURI to a blob which can be used for FormData + * + * @see http://stackoverflow.com/a/5100158/916247 + * @param {String} dataURI DataUri from a file or image + * @return {Blob} Converted blob data + */ + dataURItoBlob: function(dataURI) { + // convert base64/URLEncoded data component to raw binary data held in a string + var byteString; + if (dataURI.split(',')[0].indexOf('base64') >= 0) { + byteString = atob(dataURI.split(',')[1]); + } else { + byteString = encodeURI(dataURI.split(',')[1]); + } + + // separate out the mime component + var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]; + + // write the bytes of the string to a typed array + var ia = new Uint8Array(byteString.length); + for (var i = 0; i < byteString.length; i++) { + ia[i] = byteString.charCodeAt(i); + } + + return new Blob([ia], {type:mimeString}); } }; diff --git a/src/input.inline-attachment.js b/src/input.inline-attachment.js index 8fdd52f..04639a6 100644 --- a/src/input.inline-attachment.js +++ b/src/input.inline-attachment.js @@ -3,46 +3,62 @@ (function() { 'use strict'; - inlineAttachment.editors.input = { - Editor: function(instance) { - - var input = instance; - - return { - getValue: function() { - return input.value; - }, - insertValue: function(val) { - inlineAttachment.util.insertTextAtCursor(input, val); - }, - setValue: function(val) { - input.value = val; + var inputEditor = {}; + + inputEditor.Editor = function(instance) { + + var input = instance, + pasteElement; + + return { + getValue: function() { + return input.value; + }, + insertValue: function(val) { + inlineAttachment.util.insertTextAtCursor(input, val); + }, + setValue: function(val) { + input.value = val; + }, + getElement: function() { + return input; + }, + getPasteElement: function() { + if (!pasteElement) { + pasteElement = inlineAttachment.util.createPasteElement(input); } - }; - }, - attachToInput: function(input, options) { - options = options || {}; + return pasteElement; + } + }; + }; - var editor = new inlineAttachment.editors.input.Editor(input), - inlineattach = new inlineAttachment(options, editor); + inputEditor.attachToInput = function(input, options) { + options = options || {}; + var editor = new inlineAttachment.editors.input.Editor(input), + inlineattach = new inlineAttachment(options, editor); + + if (inlineAttachment.util.browser.isFirefox) { + inlineAttachment.util.initPasteElement(inlineattach); + } else { input.addEventListener('paste', function(e) { inlineattach.onPaste(e); }, false); - input.addEventListener('drop', function(e) { - e.stopPropagation(); - e.preventDefault(); - inlineattach.onDrop(e); - }, false); - input.addEventListener('dragenter', function(e) { - e.stopPropagation(); - e.preventDefault(); - }, false); - input.addEventListener('dragover', function(e) { - e.stopPropagation(); - e.preventDefault(); - }, false); } + input.addEventListener('drop', function(e) { + e.stopPropagation(); + e.preventDefault(); + inlineattach.onDrop(e); + }, false); + input.addEventListener('dragenter', function(e) { + e.stopPropagation(); + e.preventDefault(); + }, false); + input.addEventListener('dragover', function(e) { + e.stopPropagation(); + e.preventDefault(); + }, false); }; + inlineAttachment.editors.input = inputEditor; })(); \ No newline at end of file