I am trying to un-jQuery-fy a clever piece of code, but one that is just a bit too clever.
The objective is simple. Drag images from the desktop to the browser.
During this unjQueryfication, I find that, lo and behold, a dollar-sign function is actually implemented in Chrome and Firefox. So even without including jQuery, it sort of works already.
Here is what I came up with so far. What am I missing?
var el = document.getElementById('holder');
function stop_and_prevent(e) {
e.stopPropagation();
e.preventDefault();
}
function load_images(files) {
var images = document.getElementById("images");
files.map(function(file) {
var reader = new FileReader();
reader.onload = function(event) {
if (file.type.match('image.*')) {
var img = document.createElement('img');
img.src = event.target.result;
images.appendChild(img);
reader.readAsDataURL(file);
}}
});
}
function onDrop(e) {
e.stop_and_prevent();
load_images(e.dataTransfer.files);
return false;
}
el.addEventListener('dragenter', stop_and_prevent, false);
el.addEventListener('dragover', stop_and_prevent, false);
el.addEventListener('dragleave', stop_and_prevent, false);
el.addEventListener('drop', onDrop, false);
div#holder {
border: 5px dashed #ccc;
height:400px;
width:400px;
font-family:Verdana;
text-align:center;
}
<div id="holder">
<p>Drag files here</p>
<div id="images"></div>
</div>
You probably meant to use:
stop_and_prevent(e);
in your drop handler instead of the current:
e.stop_and_prevent();
Also, since files is of type FileList and not Array you won't be able to use map() directly on it. Just use a normal loop or a [].forEach.call() instead.
You don't need to prevent events on the dragleave handler.
Updated code:
var el = document.getElementById('holder');
function stop_and_prevent(e) {
e.stopPropagation();
e.preventDefault();
}
function load_images(files) {
var images = document.getElementById("images");
[].forEach.call(files, function(file) {
if (file.type.match('image.*')) {
var reader = new FileReader();
reader.onload = function() {
var img = document.createElement('img');
img.src = this.result; //=reader.result, or use event.target.result
images.appendChild(img);
}
reader.readAsDataURL(file);
}
});
}
function onDrop(e) {
stop_and_prevent(e);
load_images(e.dataTransfer.files);
return false;
}
el.addEventListener('dragenter', stop_and_prevent);
el.addEventListener('dragover', stop_and_prevent);
el.addEventListener('drop', onDrop);
div#holder {
border: 5px dashed #ccc;
height:400px;
width:400px;
font-family:Verdana;
text-align:center;
}
<div id="holder">
<p>Drag files here</p>
<div id="images"></div>
</div>
Related
I am displaying images before upload using jquery, when i upload some new files i want to remove or hide the previous upload files here's my jquery code:
$(function()
{
// Multiple images preview in browser
var imagesPreview = function(input, placeToInsertImagePreview)
{
if (input.files)
{
var filesAmount = input.files.length;
for (i = 0; i < filesAmount; i++)
{
var reader = new FileReader();
reader.onload = function(event)
{
$($.parseHTML('<img class="p-3" width="350px" height="250px">')).attr('src', event.target.result).appendTo(placeToInsertImagePreview);
}
reader.readAsDataURL(input.files[i]);
}
}
}
$('#file_input').on('change', function()
{
imagesPreview(this, 'div#viewUploadItems');
});
});
And my HTML Code:
<input type="file" name="images[]" id="file_input" class="deletable" multiple />
<div id="viewUploadItems"></div>
I try this code but this won't display any image.
$("#file_input").on("click",function()
{
$('input.deletable').val('');
$('#viewUploadItems').remove();
});
Perhaps you could take the following approach, where in your imagePreview() function you:
first call empty() on the preview selector to clear any prior image contents
then proceed to read and display any selected images, by using the FileReader API as you currently are (see below for revised approach)
Also, consider checking the type of the file object, to ensure that it is an image before attempting to display it via the following:
if (file.type.match("image.*")) {
/* file is image type, so attempt to preview it */
}
Bringing these ideas together, you could revise your code as follows:
$(function() {
function imagesPreview(input, targetSelector) {
/* Empty the target area where previews are shown */
$(targetSelector).empty();
/* Iterate each file via forEach in own closure */
Array.from(input.files).forEach(function(file) {
/* If file is image type proceed to preview */
if (file.type.match("image.*")) {
/* Create filereader and set it up for reading */
var reader = new FileReader();
reader.onload = function(event) {
/* Append a new image element, prepopulated with
required attrbutes, and assigned with p-3 class */
$(targetSelector).append($('<img>', {
width: '350px',
height: '250px',
src : reader.result
}).addClass('p-3'))
}
reader.readAsDataURL(file);
}
})
}
$('#file_input').on('change', function() {
imagesPreview(this, 'div#viewUploadItems');
});
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<input type="file" name="images[]" id="file_input" class="deletable" multiple />
<div id="viewUploadItems"></div>
Easier to clear the div before display : $(placeToInsertImagePreview).html("");
$(function()
{
// Multiple images preview in browser
var imagesPreview = function(input, placeToInsertImagePreview)
{
if (input.files)
{
$(placeToInsertImagePreview).html("");
var filesAmount = input.files.length;
for (i = 0; i < filesAmount; i++)
{
var reader = new FileReader();
reader.onload = function(event)
{
$($.parseHTML('<img class="p-3" width="350px" height="250px">')).attr('src', event.target.result).appendTo(placeToInsertImagePreview);
}
reader.readAsDataURL(input.files[i]);
}
}
}
$('#file_input').on('change', function()
{
imagesPreview(this, 'div#viewUploadItems');
});
});
Say, user opens a page, clicks on a button, and popup with images appears. How do I detect when all of the images have been loaded? I can't use window.onload here, since the page had already been loaded with all the assets. To make it clear, I want to find out final extents of the popup.
Popup is added to DOM like so:
var popup = document.createElement('div');
popup.innerHTML = '...';
document.body.appendChild(popup);
Simply:
var image = document.getElementById('image');
image.onload = function () {
alert ("The image has loaded!");
};
setTimeout(function(){
image.src = "http://lorempixel.com/500/500";
}, 5000);
<img id="image" src="">
See https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onload and Javascript callback for knowing when an image is loaded for more.
Based on this answer. Hopefully that is enough.
var cons = document.querySelector('#console');
var popup = document.createElement('div');
popup.className = 'popup';
popup.innerHTML = _.range(10).map(function(i) {
return '<img src="http://via.placeholder.com/50/50">';
}).join('');
document.body.insertBefore(popup, cons);
waitForImages(popup).then(function() {
d('loaded');
})
function d(s) {
var text = document.createTextNode(s);
cons.appendChild(text);
var br = document.createElement('br');
cons.appendChild(br);
}
function waitForImages(el) {
var images = document.querySelectorAll('img');
return Promise.all(_.compact(_.map(images, function(img) {
if (img.complete) {
d('img.complete');
return;
} else
return new Promise(function(resolve, reject) {
img.addEventListener('load', function() {
d('onload event');
resolve();
});
});
})));
}
.popup {
overflow: hidden;
}
img {
float: left;
margin: 0 5px 5px 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/bluebird/3.5.0/bluebird.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
<div id="console">
</div>
<div class="top-main-section">
<%= form_for #usr_vendor_web_slide ,url:{action: "slidecreate"} , html: {class: "form-horizontal"} do |f| %>
<div class="top-main-section-area">
<div id="upload-area" class="uploader1" onclick="$('#post_image').click()">
<%= f.file_field :images, :onchange => 'readURL(this)', class:'slide-img', multiple: true, id:'slide-img'%>
<img id="slide_image" src="#" alt="image" style="display: none;" class="slide_image" />
</div>
</div>
<%= f.submit({:class => 'btn btn-primary'}) %>
<% end %>
</div>
<div id="thumbnail" class="thumbnail">
<img id="slide_image1" src="#" alt="" style="" />
</div>
javascript file
var data = [];
function readURL(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
var ids = $("#slide_image");
insert();
function insert() {
var id;
id = ids;
data.push({
id: id,
});
clearAndShow()
}
function clearAndShow() {
// Clear our fields
ids = "";
console.log(data)
}
reader.onload = function(e) {
$("#slide_image").style.display = 'block';
$('#slide_image').attr('src', e.target.result).width(1000).height(480);
$("#slide_image").style.display = 'block';
$('#slide_image1').attr('src', e.target.result).width(100).height(100);
};
reader.readAsDataURL(input.files[0]);
}
}
I'm try to show images thumbnails before submit . I'll success in current dropped image show in top main section area and show it's thumbnail in thumbnail part. but i want to show all thumbnails in thumbnail part before submit. I'll try to make a javascript array and store images in that array. but i cannot get image src to show in thumbnail part. appreciate your ideas
function readURL(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
document.getElementById("slide_image").style.display = 'block';
$('#slide_image')
.attr('src', e.target.result)
.width(1000)
.height(480);
};
reader.readAsDataURL(input.files[0]);
}
}
window.onload = function() {
document.getElementById('files').addEventListener('change',
handleFileSelect, false);
function handleFileSelect(evt) {
console.log("hariii");
var files = evt.target.files;
// Loop through the FileList and render image files as thumbnails.
for (var i = 0, f; f = files[i]; i++) {
// Only process image files.
if (!f.type.match('image.*')) {
continue;
}
var reader = new FileReader();
// Closure to capture the file information.
reader.onload = (function (theFile) {
return function (e) {
// Render thumbnail.
var span = document.createElement('span');
span.innerHTML =
[
'<img style="height: 75px; border: 1px solid #000;
margin: 5px" src="',
e.target.result,
'" title="', escape(theFile.name),
'"/>'
].join('');
document.getElementById('thumbnail').insertBefore(span,
null);
};
})(f);
// Read in the image file as a data URL.
reader.readAsDataURL(f);
}
}
}
this is my solution and it works fine for my proect
Showing Thumbnail preview for the images which user selected to upload will help user to make sure they are selected the right images. Here is the code which can show preview of images as thumbnail for the selected objects. You can try either selecting or drag and drop for previewing the images.
This code uses the HTML5 features and may not work with old browsers. The two main HTML5 features used by this code are FileReader and Canvas.
Javascript
jQuery(function($){
var fileDiv = document.getElementById("upload");
var fileInput = document.getElementById("upload-image");
console.log(fileInput);
fileInput.addEventListener("change",function(e){
var files = this.files
showThumbnail(files)
},false)
fileDiv.addEventListener("click",function(e){
$(fileInput).show().focus().click().hide();
e.preventDefault();
},false)
fileDiv.addEventListener("dragenter",function(e){
e.stopPropagation();
e.preventDefault();
},false);
fileDiv.addEventListener("dragover",function(e){
e.stopPropagation();
e.preventDefault();
},false);
fileDiv.addEventListener("drop",function(e){
e.stopPropagation();
e.preventDefault();
var dt = e.dataTransfer;
var files = dt.files;
showThumbnail(files)
},false);
function showThumbnail(files){
for(var i=0;i<files.length;i++){
var file = files[i]
var imageType = /image.*/
if(!file.type.match(imageType)){
console.log("Not an Image");
continue;
}
var image = document.createElement("img");
// image.classList.add("")
var thumbnail = document.getElementById("thumbnail");
image.file = file;
thumbnail.appendChild(image)
var reader = new FileReader()
reader.onload = (function(aImg){
return function(e){
aImg.src = e.target.result;
};
}(image))
var ret = reader.readAsDataURL(file);
var canvas = document.createElement("canvas");
ctx = canvas.getContext("2d");
image.onload= function(){
ctx.drawImage(image,100,100)
}
}
}
});
HTML
<input type="file" style="display:none" id="upload-image" multiple="multiple"></input>
<div id="upload" class="drop-area">
Upload File
</div>
<div id="thumbnail"></div>
CSS
.drop-area{
width:100px;
height:25px;
border: 1px solid #999;
text-align: center;
padding:10px;
cursor:pointer;
}
#thumbnail img{
width:100px;
height:100px;
margin:5px;
}
canvas{
border:1px solid red;
}
Say, user opens a page, clicks on a button, and popup with images appears. How do I detect when all of the images have been loaded? I can't use window.onload here, since the page had already been loaded with all the assets. To make it clear, I want to find out final extents of the popup.
Popup is added to DOM like so:
var popup = document.createElement('div');
popup.innerHTML = '...';
document.body.appendChild(popup);
Simply:
var image = document.getElementById('image');
image.onload = function () {
alert ("The image has loaded!");
};
setTimeout(function(){
image.src = "http://lorempixel.com/500/500";
}, 5000);
<img id="image" src="">
See https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onload and Javascript callback for knowing when an image is loaded for more.
Based on this answer. Hopefully that is enough.
var cons = document.querySelector('#console');
var popup = document.createElement('div');
popup.className = 'popup';
popup.innerHTML = _.range(10).map(function(i) {
return '<img src="http://via.placeholder.com/50/50">';
}).join('');
document.body.insertBefore(popup, cons);
waitForImages(popup).then(function() {
d('loaded');
})
function d(s) {
var text = document.createTextNode(s);
cons.appendChild(text);
var br = document.createElement('br');
cons.appendChild(br);
}
function waitForImages(el) {
var images = document.querySelectorAll('img');
return Promise.all(_.compact(_.map(images, function(img) {
if (img.complete) {
d('img.complete');
return;
} else
return new Promise(function(resolve, reject) {
img.addEventListener('load', function() {
d('onload event');
resolve();
});
});
})));
}
.popup {
overflow: hidden;
}
img {
float: left;
margin: 0 5px 5px 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/bluebird/3.5.0/bluebird.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
<div id="console">
</div>
I am beginner in Knockout and java script. I have a problem in my project. I am using HTML5 Drag and Drop API using Knockout javascript. Now I need to show all drop items in separate div. I have some code which is display the name of droppable Items. But I want display file not file name. Below is my sample demo.
I am okay with either knockout or pure java script.
VIEW FIDDLE HERE
function ViewModel(){
var self = this;
this.dropZones = ko.observableArray([{
'elements' : ko.observableArray([]) // just to see that the output is correct
}]);
this.dragover = function(e){
console.log('dragOver');
e.stopPropagation();
e.preventDefault();
}
this.drop = function(e, data){
console.log('drop');
e.stopPropagation();
e.preventDefault();
var files = e.dataTransfer.files;
for (var i = 0, f; f = files[i]; i++) {
data.elements.push(f.name);
}
$('.drop_zone').css('background-color', '#ffffff');
}
this.dragenter = function(e, index){
console.log('dragEnter');
$('.drop_zone').eq(index).css('background-color', '#00ff00');
}
this.dragleave = function(e, index){
console.log('end');
$('.drop_zone').eq(index).css('background-color', '#ffffff');
}
}
ko.applyBindings(new ViewModel());
.drop_zone {
border: 2px dashed #bbb;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px;
padding: 25px;
text-align: center;
font: 20pt bold'Vollkorn';
color: #bbb;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div class="col-md-12" data-bind="foreach: dropZones">
<div class="drop_zone" data-bind="event:{
dragover: function(data, e){ $root.dragover(e);},
drop: function(data, e){ $root.drop(e, $data);},
dragenter: function(data, e){ $root.dragenter(e, $index());},
dragleave: function(data, e){ $root.dragleave(e, $index());}
}">Drop files here</div>
<ul data-bind="foreach: elements" style="height: 100px">
<li data-bind="text: $data"></li>
</ul>
</div>
Here's an example of how to get an image from a file and append it to a .preview element:
function readImage(file) {
var reader = new FileReader();
var image = new Image();
reader.readAsDataURL(file);
reader.onload = function(_file) {
image.src = _file.target.result;
image.onload = function() {
$(".preview").append('<img src="' + this.src + '"/>' + '<p>' + this.name +'</p>');
};
};
}
And a fiddle. HTH.