Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Firefox Support #49

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 119 additions & 0 deletions src/inline-attachment.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand Down Expand Up @@ -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});
}
};

Expand Down
82 changes: 49 additions & 33 deletions src/input.inline-attachment.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
})();