The image is not showing because this:
var imageurl = "url(" + URL.createObjectURL(event.target.files[0]) + ")";
should be:
var imageurl = URL.createObjectURL(event.target.files[0]);
as you can see in the following demo.
$(document).ready(function() {
$("#getfile").change(function(event) {
// Check if a file was selected.
if (! event.target.files.length) {
return;
}
var imageurl = URL.createObjectURL(event.target.files[0]);
// For testing purposes, I set the width to 150px.
var image = '<p><img src=' + imageurl + ' width="150"></p>';
var sel, range, node;
if (window.getSelection) {
sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
range = window.getSelection().getRangeAt(0);
node = range.createContextualFragment(image);
range.insertNode(node);
}
} else if (document.selection && document.selection.createRange) {
document.selection.createRange().pasteHTML(image);
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="file" id="getfile" value="Go!" />
<div id="divbox" contenteditable="true">The Quick Brown Fox Jumped Over The Lazy Dog</div>
I also added this part, which would prevent errors when no file/image is selected:
if (! event.target.files.length) {
return;
}
Just a suggestion
For optimal performance and memory usage, MDN recommends that the object URL be explicitly unloaded using URL.revokeObjectURL()
. So in the below snippet, I did what MDN recommended based on their example:
$(document).ready(function() {
$("#getfile").change(function(event) {
// Check if a file was selected.
if (! event.target.files.length) {
return;
}
var img = document.createElement('img');
img.src = URL.createObjectURL(event.target.files[0]);
img.onload = function(){
URL.revokeObjectURL(this.src);
console.log('Object URL unloaded');
};
// For testing purposes, I set the width to 150px.
var image = '<p><img src=' + img.src + ' width="150"></p>';
var sel, range, node;
if (window.getSelection) {
sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
range = window.getSelection().getRangeAt(0);
node = range.createContextualFragment(image);
range.insertNode(node);
}
} else if (document.selection && document.selection.createRange) {
document.selection.createRange().pasteHTML(image);
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="file" id="getfile" value="Go!" />
<div id="divbox" contenteditable="true">The Quick Brown Fox Jumped Over The Lazy Dog</div>
And another one..
If no selection was made (inside the #divbox
area), then the image is appended to the end of that area's content:
$(document).ready(function() {
$("#getfile").change(function(event) {
// Check if a file was selected.
if (! event.target.files.length) {
return;
}
var img = document.createElement('img');
img.src = URL.createObjectURL(event.target.files[0]);
img.onload = function(){
URL.revokeObjectURL(this.src);
console.log('Object URL unloaded');
};
// For testing purposes, I set the width to 150px.
var image = '<p><img src=' + img.src + ' width="150"></p>';
var sel, range, node, has_selection;
if (window.getSelection) {
sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
range = window.getSelection().getRangeAt(0);
node = range.createContextualFragment(image);
range.insertNode(node);
has_selection = true;
}
} else if (document.selection && document.selection.createRange) {
document.selection.createRange().pasteHTML(image);
has_selection = true;
}
if (! has_selection) {
document.querySelector('#divbox').innerHTML += image;
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="file" id="getfile" value="Go!" />
<div id="divbox" contenteditable="true">The Quick Brown Fox Jumped Over The Lazy Dog</div>
UPDATE
In IE 11 the image gets inserted at the end of the text no matter
where the cursor is placed.
Apparently, IE 11 "loses" (or resets?) the selection data when the #getfile
button is focused.
So one way to overcome that, is by saving the selection range via the mouseleave
event of the #divbox
element: (the demo below is based on the third demo above)
var _range;
$('#divbox').mouseleave(function(){
if (window.getSelection) {
var sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
_range = window.getSelection().getRangeAt(0);
}
}
});
$(document).ready(function() {
var _range;
$('#divbox').mouseleave(function(){
if (window.getSelection) {
var sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
_range = window.getSelection().getRangeAt(0);
}
}
});
$("#getfile").change(function(event) {
// Check if a file was selected.
if (! event.target.files.length) {
return;
}
var img = document.createElement('img');
img.src = URL.createObjectURL(event.target.files[0]);
img.onload = function(){
URL.revokeObjectURL(this.src);
console.log('Object URL unloaded');
};
// For testing purposes, I set the width to 150px.
var image = '<p><img src=' + img.src + ' width="150"></p>';
var node, has_selection;
if (_range) {
node = _range.createContextualFragment(image);
_range.insertNode(node);
has_selection = true;
} else if (document.selection && document.selection.createRange) {
document.selection.createRange().pasteHTML(image);
has_selection = true;
}
if (! has_selection) {
$('#divbox').append(image);
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="file" id="getfile" value="Go!" />
<div id="divbox" contenteditable="true">The Quick Brown Fox Jumped Over The Lazy Dog</div>
Using $('#getfile').mouseenter(...)
works as well, and there could be other options (i.e. workarounds for the IE 11 issue), but the above approach works for me.