From df66450c2e6d7333d99fda0a27b08c5e4d2a4d41 Mon Sep 17 00:00:00 2001 From: Roy van Kaathoven Date: Fri, 10 Oct 2014 23:18:29 +0200 Subject: [PATCH 1/4] start firefox prototype --- demo/firefox.html | 78 ++++++++++++++++++++++++++++++++++++++++ src/inline-attachment.js | 27 ++++++++++++++ 2 files changed, 105 insertions(+) create mode 100644 demo/firefox.html diff --git a/demo/firefox.html b/demo/firefox.html new file mode 100644 index 0000000..64b6cbb --- /dev/null +++ b/demo/firefox.html @@ -0,0 +1,78 @@ + + + + + Firefox Inline Attachment Demo + + + + + + + + + \ No newline at end of file diff --git a/src/inline-attachment.js b/src/inline-attachment.js index 9314586..5b93307 100644 --- a/src/inline-attachment.js +++ b/src/inline-attachment.js @@ -103,6 +103,33 @@ 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 = unescape(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}); } }; From d1495ad035d61895c79b4775f1378897ed11ea00 Mon Sep 17 00:00:00 2001 From: Roy van Kaathoven Date: Thu, 16 Oct 2014 22:08:36 +0200 Subject: [PATCH 2/4] moved firefox paste capturing to inlineAttachment logic --- src/inline-attachment.js | 96 +++++++++++++++++++++++++++++++++- src/input.inline-attachment.js | 82 +++++++++++++++++------------ 2 files changed, 144 insertions(+), 34 deletions(-) diff --git a/src/inline-attachment.js b/src/inline-attachment.js index 5b93307..a20083e 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 * @@ -349,7 +440,10 @@ clipboardData = e.clipboardData, items; - if (typeof clipboardData === "object") { + if (inlineAttachment.util.browser.isFirefox) { + var element = this.editor.getPasteElement(); + } + else if (typeof clipboardData === "object") { items = clipboardData.items || clipboardData.files || []; for (var i = 0; i < items.length; i++) { 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 From d52c63a5e9a11da8fb95ca1f0828a6d5c5dc7284 Mon Sep 17 00:00:00 2001 From: Roy van Kaathoven Date: Thu, 16 Oct 2014 22:09:36 +0200 Subject: [PATCH 3/4] remove old firefox prototype --- demo/firefox.html | 78 ----------------------------------------------- 1 file changed, 78 deletions(-) delete mode 100644 demo/firefox.html diff --git a/demo/firefox.html b/demo/firefox.html deleted file mode 100644 index 64b6cbb..0000000 --- a/demo/firefox.html +++ /dev/null @@ -1,78 +0,0 @@ - - - - - Firefox Inline Attachment Demo - - - - - - - - - \ No newline at end of file From 3b2b2367a6cfff5a57b0d7ab0506734360ad56ff Mon Sep 17 00:00:00 2001 From: Roy van Kaathoven Date: Thu, 16 Oct 2014 22:18:38 +0200 Subject: [PATCH 4/4] fixed jslint warnings --- src/inline-attachment.js | 46 +++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/src/inline-attachment.js b/src/inline-attachment.js index a20083e..e52e447 100644 --- a/src/inline-attachment.js +++ b/src/inline-attachment.js @@ -56,14 +56,14 @@ */ 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); - } + 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); + } }); }, @@ -105,15 +105,15 @@ 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; + 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(); @@ -206,10 +206,11 @@ 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) + if (dataURI.split(',')[0].indexOf('base64') >= 0) { byteString = atob(dataURI.split(',')[1]); - else - byteString = unescape(dataURI.split(',')[1]); + } else { + byteString = encodeURI(dataURI.split(',')[1]); + } // separate out the mime component var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]; @@ -440,10 +441,7 @@ clipboardData = e.clipboardData, items; - if (inlineAttachment.util.browser.isFirefox) { - var element = this.editor.getPasteElement(); - } - else if (typeof clipboardData === "object") { + if (typeof clipboardData === "object") { items = clipboardData.items || clipboardData.files || []; for (var i = 0; i < items.length; i++) {