Get drag and drop image from another tab as base64String - javascript

With this code, I get only the URL. So I have to call this URL to restore the image.
Is it possible to get the image data itself directly without calling this URL again?
That's to avoid CORS depending on some server.
var dropbox = document.getElementById('dropbox');
dropbox.addEventListener('dragenter', noopHandler, false);
dropbox.addEventListener('dragexit', noopHandler, false);
dropbox.addEventListener('dragover', noopHandler, false);
dropbox.addEventListener('drop', drop, false);
function noopHandler(evt) {
evt.stopPropagation();
evt.preventDefault();
}
function drop(evt) {
evt.stopPropagation();
evt.preventDefault();
var imageUrl = evt.dataTransfer.getData('URL');
console.log(imageUrl)
alert(imageUrl);
}
#dropbox {
border: solid 1px red;
width: 200px;
height: 200px;
}
<div>Drag this image to the drop zone:</div>
<img src="http://www.google.com/logos/2012/Julia_Child-2012-hp.jpg" alt="" />
<div id="dropbox">
DropZone => you could drop any image from any page here
</div>

That's to avoid CORS
It sounds rather like you are trying to avoid Same-Origin-Policy (SOP).
CORS is a way to relax SOP, so it doesn't block some domains to access resources on your server.
SOP is a protection, if you find a way to avoid it that's a security issue, and you should probably report this to browser vendors since they can be generous with such bug reports.
So to answer your question, No, you can't.
As you have already thought, having the image's data passed into the DataTransfer would mean that a cross-origin script would be able to read the content of a cross-domain resource, and we don't want this to happen.
What you can do, as you already found too, is to fetch again that resource using the URL that has been passed into the DataTransfer, but if the server there doesn't allow you to read that content, you still won't be able to do so.
Ps: If the image on the other page was served through CORS, or simply same-origin, and you had access to that page, you could then append the data as a File in the DataTransfer. But I guess if you were in that situation, you could also simply setup your server so that it allows your other ones to read the data there.

Please, run the snippet below.
Before the "ev.target.appendChild(document.getElementById(data))" over this code, you must to follow this instructions:
How can I convert an image into Base64 string using JavaScript?
...It's possible inside<Canvas>
function DopHere(ev) {
ev.preventDefault();
}
function image_drags(ev) {
ev.dataTransfer.setData("text", ev.target.id);
}
function drop(ev,div_id) {
ev.preventDefault();
var hasImages =hasImage(div_id);
var data = ev.dataTransfer.getData("text");
if(hasImages==false){
var data = ev.dataTransfer.getData("text");
ev.target.appendChild(document.getElementById(data));
}else{
alert('div already have an image.');
}
}
function hasImage(id) {
var arrival_div=document.getElementById(id);
var childElements = document.getElementById(id).childNodes;
for (var i = 0; i < childElements.length; i++) {
if (childElements[i].localName != null && childElements[i].localName.toLowerCase() == "img") {
return true;
}
}
return false;
}
#drop_container{border:1px solid #000; width:170px; height:100px; padding:5px; float:left; margin:20px;}
#dropback_container{border:1px solid #000; width:170px; height:100px; padding:5px;float:left; margin:20px;}
img{
max-width:170px;
height:auto;
}
<div id="drop_container" ondrop="drop(event,'drop_container')" ondragover="DopHere(event)"><img id="image_drag" src="http://www.google.com/logos/2012/Julia_Child-2012-hp.jpg" draggable="true"
ondragstart="image_drags(event)"></div>
<div id="dropback_container" ondrop="drop(event,'dropback_container')" ondragover="DopHere(event)"></div>
https://jsfiddle.net/b7p8k5cf/1/

Related

Multiple image upload JavaScript array Stringify struggles with large images base64

I'm trying to add a multiple image up-loader which returns a JavaScript array that is populated by the user selecting images. I will be using this image up-loader with other input form elements which will all submit together, in this case i'm not using AJAX. The maximum file upload size is 2MB. The JavaScript array contains the base 64 encoded image with all the details including size, type etc.
I have used $('#j_son').val(JSON.stringify(AttachmentArray)); outside the array to populate the hidden input field everytime the array is populated (input unhidden to show JSON string). Lightweight Multiple File Upload with Thumbnail Preview using HTML5 and Client Side Scripts
On submit I will use PHP to decode the new JSON string and and put the multiple images in a folder called uploads.
The problem I am facing is that selecting image attachments larger than 200 KB seem to slow the output of images inside the div container and the JSON string inside the hidden input field and anything to large will cause "aw snap" error inside chrome and crash the browser, I don't know where I'm going wrong. I also have a click event that when the user clicks X remove button and the hidden input field is repopulated with the updated JSON array, this to is really slow and crashes if the files are to large. The PHP side of things has no problem decoding the JSON string it seems to either fall on the JavaScript code or the extra functionality I have added at the bottom of the script. Is there a way to stop this from happening? I have added the full code including the PHP if anybody wants to test it.
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8" />
<style>
/*Copied from bootstrap to handle input file multiple*/
.btn {
display: inline-block;
padding: 6px 12px;
margin-bottom: 0;
font-size: 14px;
font-weight: normal;
line-height: 1.42857143;
text-align: center;
white-space: nowrap;
vertical-align: middle;
cursor: pointer;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
background-image: none;
border: 1px solid transparent;
border-radius: 4px;
}
/*Also */
.btn-success {
border: 1px solid #c5dbec;
background: #D0E5F5;
font-weight: bold;
color: #2e6e9e;
}
/* This is copied from https://github.com/blueimp/jQuery-File-
Upload/blob/master/css/jquery.fileupload.css */
.fileinput-button {
position: relative;
overflow: hidden;
}
.fileinput-button input {
position: absolute;
top: 0;
right: 0;
margin: 0;
opacity: 0;
-ms-filter: 'alpha(opacity=0)';
font-size: 200px;
direction: ltr;
cursor: pointer;
}
.thumb {
height: 80px;
width: 100px;
border: 1px solid #000;
}
ul.thumb-Images li {
width: 120px;
float: left;
display: inline-block;
vertical-align: top;
height: 120px;
}
.img-wrap {
position: relative;
display: inline-block;
font-size: 0;
}
.img-wrap .close {
position: absolute;
top: 2px;
right: 2px;
z-index: 100;
background-color: #D0E5F5;
padding: 5px 2px 2px;
color: #000;
font-weight: bolder;
cursor: pointer;
opacity: .5;
font-size: 23px;
line-height: 10px;
border-radius: 50%;
}
.img-wrap:hover .close {
opacity: 1;
background-color: #ff0000;
}
.FileNameCaptionStyle {
font-size: 12px;
}
</style>
<script type="text/javascript" src="scripts/jquery-1.10.2.js"></script>
<script type="text/javascript">
//I added event handler for the file upload control to access the files
properties.
document.addEventListener("DOMContentLoaded", init, false);
//To save an array of attachments
var AttachmentArray = [];
$('#j_son').val(JSON.stringify(AttachmentArray));
//counter for attachment array
var arrCounter = 0;
//to make sure the error message for number of files will be shown only
one time.
var filesCounterAlertStatus = false;
//un ordered list to keep attachments thumbnails
var ul = document.createElement('ul');
ul.className = ("thumb-Images");
ul.id = "imgList";
function init() {
//add javascript handlers for the file upload event
document.querySelector('#files').addEventListener('change',
handleFileSelect, false);
}
//the handler for file upload event
function handleFileSelect(e) {
//to make sure the user select file/files
if (!e.target.files) return;
//To obtaine a File reference
var files = e.target.files;
// Loop through the FileList and then to render image files as
thumbnails.
for (var i = 0, f; f = files[i]; i++) {
//instantiate a FileReader object to read its contents into
memory
var fileReader = new FileReader();
// Closure to capture the file information and apply validation.
fileReader.onload = (function (readerEvt) {
return function (e) {
//Apply the validation rules for attachments upload
ApplyFileValidationRules(readerEvt)
//Render attachments thumbnails.
RenderThumbnail(e, readerEvt);
//Fill the array of attachment
FillAttachmentArray(e, readerEvt)
};
})(f);
// Read in the image file as a data URL.
// readAsDataURL: The result property will contain the
//file/blob's data encoded as a data URL.
// More info about Data URI scheme
//https://en.wikipedia.org/wiki/Data_URI_scheme
fileReader.readAsDataURL(f);
}
document.getElementById('files').addEventListener('change',
handleFileSelect, false);
}
//To remove attachment once user click on x button
jQuery(function ($) {
$('div').on('click', '.img-wrap .close', function () {
var id = $(this).closest('.img-wrap').find('img').data('id');
//to remove the deleted item from array
var elementPos = AttachmentArray.map(function (x) { return
x.FileName; }).indexOf(id);
if (elementPos !== -1) {
AttachmentArray.splice(elementPos, 1);
}
//to remove image tag
$(this).parent().find('img').not().remove();
//to remove div tag that contain the image
$(this).parent().find('div').not().remove();
//to remove div tag that contain caption name
$(this).parent().parent().find('div').not().remove();
//to remove li tag
var lis = document.querySelectorAll('#imgList li');
for (var i = 0; li = lis[i]; i++) {
if (li.innerHTML == "") {
li.parentNode.removeChild(li);
}
}
});
}
)
//Apply the validation rules for attachments upload
function ApplyFileValidationRules(readerEvt)
{
//To check file type according to upload conditions
if (CheckFileType(readerEvt.type) == false) {
alert("The file (" + readerEvt.name + ") does not match the
upload conditions, You can only upload jpg/png/gif files");
e.preventDefault();
return;
}
//To check file Size according to upload conditions
if (CheckFileSize(readerEvt.size) == false) {
alert("The file (" + readerEvt.name + ") does not match the
upload conditions, The maximum file size for uploads should not
exceed 300 KB");
e.preventDefault();
return;
}
//To check files count according to upload conditions
if (CheckFilesCount(AttachmentArray) == false) {
if (!filesCounterAlertStatus) {
filesCounterAlertStatus = true;
alert("You have added more than 10 files. According to
upload conditions you can upload 10 files maximum");
}
e.preventDefault();
return;
}
}
//To check file type according to upload conditions
function CheckFileType(fileType) {
if (fileType == "image/jpeg") {
return true;
}
else if (fileType == "image/png") {
return true;
}
else if (fileType == "image/gif") {
return true;
}
else if (fileType == "image/jpg") {
return true;
}
else {
return false;
}
return true;
}
//To check file Size according to upload conditions
function CheckFileSize(fileSize) {
if (fileSize < 2000000) {
return true;
}
else {
return false;
}
return true;
}
//To check files count according to upload conditions
function CheckFilesCount(AttachmentArray) {
//Since AttachmentArray.length return the next available index in
//the array,
//I have used the loop to get the real length
var len = 0;
for (var i = 0; i < AttachmentArray.length; i++) {
if (AttachmentArray[i] !== undefined) {
len++;
}
}
//To check the length does not exceed 10 files maximum
if (len > 9) {
return false;
}
else
{
return true;
}
}
//Render attachments thumbnails.
function RenderThumbnail(e, readerEvt)
{
var li = document.createElement('li');
ul.appendChild(li);
li.innerHTML = ['<div class="img-wrap"> <span class="close">×
</span>' +
'<img class="thumb" src="', e.target.result, '" title="',
escape(readerEvt.name), '" data-id="',
readerEvt.name, '"/>' + '</div>'].join('');
var div = document.createElement('div');
div.className = "FileNameCaptionStyle";
li.appendChild(div);
div.innerHTML = [readerEvt.name].join('');
document.getElementById('Filelist').insertBefore(ul, null);
}
//Fill the array of attachment
function FillAttachmentArray(e, readerEvt)
{
AttachmentArray[arrCounter] =
{
AttachmentType: 1,
ObjectType: 1,
FileName: readerEvt.name,
FileDescription: "Attachment",
NoteText: "",
MimeType: readerEvt.type,
Content: e.target.result.split("base64,")[1],
FileSizeInBytes: readerEvt.size,
};
arrCounter = arrCounter + 1;
//THIS IS THE PART I ADDED TO POPULATE THE HIDDEN INPUT FIELD
$('#j_son').val(JSON.stringify(AttachmentArray));
}
//THIS IS TO UPDATE THE INPUT FIELD WHEN A FILE IS REMOVED
$(document).on('click', '.close', function(){
var myString = JSON.stringify(AttachmentArray);
$('#j_son').val(myString);
});
</script>
</head>
<body>
<div>
<label style="font-size: 14px;">
<span style='color:navy;font-weight:bold'>Attachment Instructions :
</span>
</label>
<ul>
<li>
Allowed only files with extension (jpg, png, gif)
</li>
<li>
Maximum number of allowed files 10 with 2 MB for each
</li>
<li>
you can select files from different folders
</li>
</ul>
<form method="POST" action="" enctype="multipart/form-data">
<span class="btn btn-success fileinput-button">
<span>Select Attachment</span>
<input type="file" name="files[]" id="files" multiple
accept="image/jpeg, image/jpg image/png, image/gif,"><br />
</span>
<!--input field to be populated by the array-->
<input type="text" name="j_son" id="j_son" style="width: 500px;">
<!--Submit and post to get decoded JSON string-->
<button type="submit" id="image_post" name="post_it">Submit</button>
</form>
<output id="Filelist"></output>
</div>
<?php
if(isset($_POST['post_it']))
{
//other input fields
$file = $_POST['j_son'];
$tempData = html_entity_decode($file);
$cleanData = json_decode($tempData, true);
foreach($cleanData as $p)
{
echo $p['Content']."</br>";
//insert code to uploads folder
}
}
?>
</body>
</html>
-- edit --
This may be because of a known issue in chrome. Try using a blob as recommended in this post
How can javascript upload a blob?
function uploadAudio( blob ) {
var reader = new FileReader();
reader.onload = function(event){
var fd = {};
fd["fname"] = "test.wav";
fd["data"] = event.target.result;
$.ajax({
type: 'POST',
url: 'upload.php',
data: fd,
dataType: 'text'
}).done(function(data) {
console.log(data);
});
};
reader.readAsDataURL(blob);
}
-- /edit --
ok it seems like you are adding an onChange event listener multiple times to the "files" id. Once in the init and once every time the handleFileSelect function is called. This could for sure be your slowdown problem.
Also, if you are going to have a file upload size that maxes out at 2MB you should set this in your PHP file using upload_max_filesize and also set post_max_size.
ini_set('upload_max_filesize', '2M');
ini_set('post_max_size', '2M');
from php.net:
upload_max_filesize
The maximum size of an uploaded file.
post_max_size
Sets max size of post data allowed. This setting also affects file upload. To upload large files, this value must be larger than upload_max_filesize. Generally speaking, memory_limit should be larger than post_max_size. When an integer is used, the value is measured in bytes.
Also if your upload ends up timing out you might also want to extend the execution time by using max_input_time or max_execution time though I think that max_input_time should be enough.
ini_set('max_input_time', 300);
ini_set('max_execution_time', 300);
max_input_time
This sets the maximum time in seconds a script is allowed to parse input data, like POST and GET. Timing begins at the moment PHP is invoked at the server and ends when execution begins. The default setting is -1, which means that max_execution_time is used instead. Set to 0 to allow unlimited time.
max_execution_time
This sets the maximum time in seconds a script is allowed to run before it is terminated by the parser. This helps prevent poorly written scripts from tying up the server. The default setting is 30. When running PHP from the command line the default setting is 0.
This needs to be added at the top of your PHP file before other output.

How to save data in local hd with javascript?

I'm using CKEditor to create text in a website that create documents. The problem is the internet connection, the PC is far away from town and it's unstable 3G connection. I already have a routine to save a draft every ten seconds (or the time the user wish to be) in the server for safe - simple task. The problem is that if the internet goes down, the user will have to select - copy the text and try to save it locally with some text editor (maybe Word, that will make a mess).
So I'm wondering if already exists a way of to create a file and download to the local HD without remote server, just the JavaScript and navigator. Also, it might be another way to save the job but keeping CPU on and navigator open, but couldn't find in stack overflow.
I found just one non-standard API FireFox compatible:
Device Storage API
Of course, is not JavaScript standard so I don't know if it's a good idea to use right now.
Any ideas?
[Compatibility Note]
This solution uses <a> attribute download, to save the data in a text file.
This html5 attribute is only supported by Chrome 14+, Firefox 20+ and Opera
15+ on
desktop, none on iOS and all current majors except WebView on Android.
-A workaround for IE 10+ is to not hide/destroy the link generated by clickSave()and ask user to right-click > Save target As…
-No known workaround for Safari.
Also note that data will still be accessible via
localStorage.getItem()
for Firefox 3.5+, Chrome&Safari 4+, Opera 10.5+ and IE 9+ (xhr will
crash IE 8-)
I would do it like so, assuming your actual code saves the data via xhr.
function saveData() {
var xhr = new XMLHttpRequest();
//set a timeout, in ms, to see if we're still connected
xhr.timeout = 2000;
xhr.addEventListener('timeout', localStore, false);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
// not a good news
if (xhr.status !== 200) {
localStore();
}
else{
document.querySelector('#local_alert').style.display = 'none';
}
}
}
//I assume you already have the part where you set the credentials
xhr.open('POST', 'your/url.php');
xhr.send();
}
//Show the link + Store the text in localStorage
function localStore() {
document.querySelector('#local_alert').style.display = 'block';
var userText = document.querySelector('textArea').value;
localStorage.setItem("myAwesomeTextEditor", userText);
}
//provide a link to download a file with txt content
window.URL = window.URL || window.webkitURL;
function clickSave(e) {
var userText = document.querySelector('textArea').value;
var blob = new Blob([userText], {type: 'plain/text'});
var a = document.createElement('a');
a.download = "myAwesomeTextEditor" + (new Date).getTime() + '.txt';
a.href = URL.createObjectURL(blob);
a.style.display = "none";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
setInterval(saveData, 3000);
#local_alert {
display: none;
position: static;
width: 100%;
height: 3em;
background-color: #AAA;
color: #FFF;
padding: 0.5em;
}
body,
html {
margin: 0
}
<div id="local_alert">You're actually offline, please beware your draft is not saved on our server
<button onclick="clickSave()">Save Now</button>
</div>
<textarea></textarea>
Ps: If your user leaves the page without connection, you'll be able to get the text back via localStorage.getItem("myAwesomeTextEditor")
PPs: A more "live" example can be found here (it won't save to server but you've got the rest of the logic working). Try to disconnect , then reconnect.
Try
var editor = document.getElementById("editor");
var saveNow = document.getElementById("save");
function saveFile() {
if (confirm("save editor text")) {
var file = document.createElement("a");
file.download = "saved-file-" + new Date().getTime();
var reader = new FileReader();
reader.onload = function(e) {
file.href = e.target.result;
document.body.appendChild(file);
file.click();
document.body.removeChild(file);
};
reader.readAsDataURL(new Blob([editor.value], {
"type": "text/plain"
}));
}
};
saveNow.addEventListener("click", saveFile, false);
<button id="save">save editor text</button><br />
<textarea id="editor"></textarea>

Browse Image and Insert into Iframe

I was wondering if this is possible.
I want to create a function to retrieve an image and insert into an iframe. The user must be able to choose a file (image/video) and it will be inserted into an iframe.
main.html
<input type="file" id="addImage"> I have used this for the user to choose a file.
<iframe class="frame" id="frame" src="insert.html"></iframe> And this for the iframe. The iframe src is another html document.
insert.html
<span id="edit"></span> is within the insert.html where the image needs to be inserted to.
I don't quite understand how javascript can be used to retrieve the image from the users selection and insert into the iframe.
Is this possible?
Yes, here is an example. The key is to hook onto the iframe and then use its contentWindow.
EDIT
Additionally, I don't know if you meant the browse for file or the drag'n'drop API so I implemented both.
Lots of help from these sources:
file-api : How to interact with the file-api
drag-drop events : Events to key off of when dragging and dropping
And here is a fiddle:
JSFiddle
CSS
*{
font-family: Arial;
}
.section{
width: 400px;
padding: 20px;
margin: auto;
}
#dragDiv{
background-color: #ffffcc;
}
#browseDiv{
background-color: #ccffcc;
}
#iframeDiv{
background-color: #ffcccc;
}
#dropTarget{
width: 300px;
height: 300px;
border-style: dashed;
border-width: 5px;
}
.dropEnabled{
border-color: #999999;
}
.dropEnabled:hover{
border-color: #ff9933;
}
.dropMe{
border-color: #99ff99;
}
JS
/**
* I set up the listeners for dragging and dropping as well
* as creating an iFrame for holding dragged in images
* #returns {undefined}
*/
function main() {
// The div that receives drops and the new iFrame
var targetDiv = document.getElementById("dropTarget"),
iframe = document.createElement("iframe");
// Set the iframe to a blank page
iframe.src = "about:blank";
// Append it to the target
document.getElementById("iframeTarget").appendChild(iframe);
// Drag over is when an object is hovering over the div
// e.preventDefault keeps the page from changing
targetDiv.addEventListener("dragover", function(e) {
e.preventDefault();
this.className = "dropMe";
}, false);
// Drag leave is when the object leaves the div but isn't dropped
targetDiv.addEventListener("dragleave", function(e) {
e.preventDefault();
this.className = "dropEnabled";
}, false);
// Drop is when the click is released
targetDiv.addEventListener("drop", function(e) {
e.preventDefault();
this.className = "dropEnabled";
loadFile(e.dataTransfer.files[0], iframe);
}, false);
document.getElementById("upload").addEventListener("click", function() {
var file = document.getElementById("browsedFile").files[0];
loadFile(file, iframe);
}, false);
}
/**
* Load a file and then put it on an ifrmae
* #param {Element} f The file that needs to get loaded
* #param {Element} destination The iframe that the file is appended to
* #returns {undefined}
*/
function loadFile(f, destination) {
// Make a file reader to interpret the file
var reader = new FileReader();
// When the reader is done reading,
// Make a new image tag and append it to the iFrame
reader.onload = function(event) {
var newImage = document.createElement("img");
newImage.src = event.target.result;
destination.contentWindow.document.getElementsByTagName("body")[0].appendChild(newImage);
};
// Tell the reader to start reading asynchrounously
reader.readAsDataURL(f);
}
// Run the main script
window.onload = main;
HTML
<!DOCTYPE html>
<html>
<head>
<title>I framed it</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
</head>
<body>
<div id="dragDiv" class="section">
<div>The div below receives dragged in files</div>
<div id="dropTarget" class="dropEnabled"></div>
</div>
<div id="browseDiv" class="section">
<div>I upload stuff the boring way</div>
<input type="file" id="browsedFile"><button id="upload">Upload</button>
</div>
<div id="iframeDiv" class="section">
<div>And below me, an iFrame gets created</div>
<div id="iframeTarget"></div>
</div>
</body>
</html>
And here is the result:
And the DOM:
EDIT
A comment was made about how to do this with videos as well. There are several ways to do it, but here is one way that I would do it using the HTML5 <vido> tag which you can find more information on here: HTML Videos.
One tricky thing that I'm sure is rather cludgy is how to say what kind of file you should be loading. I use a switch() on the file's type attribute which usually evaluates to something like: image/png or video/mp4 for MP4 videos. However, this ties you to a specific file format. A better way to do it would be to make a regular expression that figures out if it's just an image or a video and ignore the format since the process is rougly the same for all files of those types.
I added my own regular expression implementation. Probably, not the best, but it allows all appropriate image types to come through now.
Also, I tried using some sample videos from Apple which can be found here: Sample QuickTime Movies. However, those did not work for some reason. So after that, I just downloaded the sample videos that W3Schools uses in their tutorial. I'm telling you this so that in case you try it and it doesn't work, it might be the file itself and not your code.
Edited loadFile() Function
/**
* Load a file and then put it on an ifrmae
* #param {Element} f The file that needs to get loaded
* #param {Element} destination The iframe that the file is appended to
* #returns {undefined}
*/
function loadFile(f, destination) {
// Make a file reader to interpret the file
var reader = new FileReader(),
loaderFunc = null,
typeRegEx = /^(\w+)\//,
contentType = f.type.match(typeRegEx)[1];
// Figure out how to load the data
switch (contentType) {
case "video":
loaderFunc = function(event) {
var newVideo = document.createElement("video"),
newVideoSource = document.createElement("source");
newVideo.width = 300;
newVideo.height = 300;
newVideo.setAttribute("controls");
newVideoSource.src = event.target.result;
newVideoSource.type = f.type;
destination.contentWindow.document.getElementsByTagName("body")[0].appendChild(newVideo);
newVideo.appendChild(newVideoSource);
};
break;
case "image":
loaderFunc = function(event) {
var newImage = document.createElement("img");
newImage.src = event.target.result;
destination.contentWindow.document.getElementsByTagName("body")[0].appendChild(newImage);
};
break;
default:
console.log("Unknown file type");
return;
}
// We should have returned, but just make sure
if (loaderFunc) {
// When the reader is done reading,
// Make a new image tag and append it to the iFrame
reader.onload = loaderFunc;
// Tell the reader to start reading asynchrounously
reader.readAsDataURL(f);
}
}
You can manipulate directly an iframe from an other if they are from same domain.
See jQuery/JavaScript: accessing contents of an iframe
What you can do if this is not the case is :
Setting up a communication process between both pages (see How to communicate between iframe and the parent site?)
or
Uploading your file to a server, and refresh the "insert.html" page to display the uploaded image.

Why does my file-preview not show my file the first time?

I want to read the picture from user's local file. (the user is under ie7 -ie9, so it doesn't support fully version of html5) I find the first time I assume the input|file value, the picture doesn't show, the second time I change another picture, the image can show. Just want to know how to make the first time I input picture it is can show.
I want read the picture from user's local file, I apply below code:
function ShowImage(obj){
var allowSuffix=".jpg|.gif|.bmp|.png"; //.jpg,.bmp,.gif,.png
var suffix=obj.value.substring(obj.value.lastIndexOf(".")+1).toLowerCase();
var browserVersion= window.navigator.userAgent.toUpperCase();
if(allowSuffix.indexOf(suffix)>-1){
if(browserVersion.indexOf("MSIE 7.0")>-1 || browserVersion.indexOf("MSIE 8.0")>-1 || browserVersion.indexOf("MSIE 9.0")>-1){//ie7, ie8, ie9
obj.select();
var source=document.selection.createRange().text;
obj.blur();
var newPreview = document.getElementById("divNewPreview");
newPreview.filters.item("DXImageTransform.Microsoft.AlphaImageLoader").src = source;
newPreview.style.width = 160;
newPreview.style.height = 170;
newPreview.filters.item("DXImageTransform.Microsoft.AlphaImageLoader").sizingMethod = 'scale';
$("#divPreview").attr("style","display:none");
$("#divNewPreview").attr("style","filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=image);width:160px;height:170px;border:solid 1px #d2e2e2;");
}
}
}
the html part code is easy like:
<div id="divNewPreview" style="filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=image ); width: 160px; height: 170px; border: solid 1px #d2e2e2; display: none;"></div>
<p>
input file: <input type="file" onchange="ShowImage(this)" />
</p>
Older browsers have no access to the local filesystem. You need to post it to the server before you can view the file.

HTML5, JavaScript: Drag and Drop File from External Window (Windows Explorer)

Can I kindly ask for a good working example of HTML5 File Drag and Drop implementation? The source code should work if drag and drop is performed from external application(Windows Explorer) to browser window. It should work on as many browsers as possible.
I would like to ask for a sample code with good explanation. I do not wish to use third party libraries, as I will need to modify the code according to my needs. The code should be based on HTML5 and JavaScript. I do not wish to use JQuery.
I spent the whole day searching for good source of material, but surprisingly, I did not find anything good. The examples I found worked for Mozilla but did not work for Chrome.
Here is a dead-simple example. It shows a red square. If you drag an image over the red square it appends it to the body. I've confirmed it works in IE11, Chrome 38, and Firefox 32. See the Html5Rocks article for a more detailed explanation.
var dropZone = document.getElementById('dropZone');
// Optional. Show the copy icon when dragging over. Seems to only work for chrome.
dropZone.addEventListener('dragover', function(e) {
e.stopPropagation();
e.preventDefault();
e.dataTransfer.dropEffect = 'copy';
});
// Get file data on drop
dropZone.addEventListener('drop', function(e) {
e.stopPropagation();
e.preventDefault();
var files = e.dataTransfer.files; // Array of all files
for (var i=0, file; file=files[i]; i++) {
if (file.type.match(/image.*/)) {
var reader = new FileReader();
reader.onload = function(e2) {
// finished reading file data.
var img = document.createElement('img');
img.src= e2.target.result;
document.body.appendChild(img);
}
reader.readAsDataURL(file); // start reading the file data.
}
}
});
<div id="dropZone" style="width: 100px; height: 100px; background-color: red"></div>
The accepted answer provides an excellent link for this topic; however, per SO rules, pure link answers should be avoided since the links can rot at any time. For this reason, I have taken the time to summarize the content of the link for future readers.
Getting Started
Prior to implementing a method to upload files to your website, you should ensure that the browsers you choose to support will be capable of fully supporting the File API. You can test this quickly with the snippet of Javascript below:
// Check for the various File API support.
if (window.File && window.FileReader && window.FileList && window.Blob) {
// Great success! All the File APIs are supported.
} else {
alert('The File APIs are not fully supported in this browser.');
}
You can modify the snippet above to meet your needs of course.
Form Input
The most common way to upload a file is to use the standard <input type="file"> element. JavaScript returns the list of selected File objects as a FileList.
function handleFileSelect(evt) {
var files = evt.target.files; // FileList object
// files is a FileList of File objects. List some properties.
var output = [];
for (var i = 0, f; f = files[i]; i++) {
output.push('<li><strong>', escape(f.name), '</strong> (', f.type || 'n/a', ') - ',
f.size, ' bytes, last modified: ',
f.lastModifiedDate ? f.lastModifiedDate.toLocaleDateString() : 'n/a',
'</li>');
}
document.getElementById('list').innerHTML = '<ul>' + output.join('') + '</ul>';
}
document.getElementById('files').addEventListener('change', handleFileSelect, false);
<input type="file" id="files" name="files[]" multiple />
<output id="list"></output>
Drag and Drop
Making simple modifications to the snippet above allows us to provide drag and drop support.
function handleFileSelect(evt) {
evt.stopPropagation();
evt.preventDefault();
var files = evt.dataTransfer.files; // FileList object.
// files is a FileList of File objects. List some properties.
var output = [];
for (var i = 0, f; f = files[i]; i++) {
output.push('<li><strong>', escape(f.name), '</strong> (', f.type || 'n/a', ') - ',
f.size, ' bytes, last modified: ',
f.lastModifiedDate ? f.lastModifiedDate.toLocaleDateString() : 'n/a',
'</li>');
}
document.getElementById('list').innerHTML = '<ul>' + output.join('') + '</ul>';
}
function handleDragOver(evt) {
evt.stopPropagation();
evt.preventDefault();
evt.dataTransfer.dropEffect = 'copy'; // Explicitly show this is a copy.
}
// Setup the dnd listeners.
var dropZone = document.getElementById('drop_zone');
dropZone.addEventListener('dragover', handleDragOver, false);
dropZone.addEventListener('drop', handleFileSelect, false);
#drop_zone {
min-height: 10em;
background: #eee;
}
<div id="drop_zone">Drop files here</div>
<output id="list"></output>
Reading Files
Now you've obtained a reference to the File, you can instantiate a FileReader to read its contents into memory. When the load completes the onload event is fired and its result attribute can be used to access the file data. Feel free to look at the references for FileReader to cover the four available options for reading a file.
The example below filters out images from the user's selection, calls reader.readAsDataURL() on the file, and renders a thumbnail by setting the src attribute to a data URL.
function handleFileSelect(evt) {
var files = evt.target.files; // FileList object
// 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 class="thumb" src="', e.target.result,
'" title="', escape(theFile.name), '"/>'].join('');
document.getElementById('list').insertBefore(span, null);
};
})(f);
// Read in the image file as a data URL.
reader.readAsDataURL(f);
}
}
document.getElementById('files').addEventListener('change', handleFileSelect, false);
.thumb {
height: 75px;
border: 1px solid #000;
margin: 10px 5px 0 0;
}
<input type="file" id="files" name="files[]" multiple />
<output id="list"></output>
Slicing
In some cases reading the entire file into memory isn't the best option. For example, say you wanted to write an async file uploader. One possible way to speed up the upload would be to read and send the file in separate byte range chunks. The server component would then be responsible for reconstructing the file content in the correct order.
The following example demonstrates reading chunks of a file. Something worth noting is that it uses the onloadend and checks the evt.target.readyState instead of using the onload event.
function readBlob(opt_startByte, opt_stopByte) {
var files = document.getElementById('files').files;
if (!files.length) {
alert('Please select a file!');
return;
}
var file = files[0];
var start = parseInt(opt_startByte) || 0;
var stop = parseInt(opt_stopByte) || file.size - 1;
var reader = new FileReader();
// If we use onloadend, we need to check the readyState.
reader.onloadend = function(evt) {
if (evt.target.readyState == FileReader.DONE) { // DONE == 2
document.getElementById('byte_content').textContent = evt.target.result;
document.getElementById('byte_range').textContent =
['Read bytes: ', start + 1, ' - ', stop + 1,
' of ', file.size, ' byte file'].join('');
}
};
var blob = file.slice(start, stop + 1);
reader.readAsBinaryString(blob);
}
document.querySelector('.readBytesButtons').addEventListener('click', function(evt) {
if (evt.target.tagName.toLowerCase() == 'button') {
var startByte = evt.target.getAttribute('data-startbyte');
var endByte = evt.target.getAttribute('data-endbyte');
readBlob(startByte, endByte);
}
}, false);
#byte_content {
margin: 5px 0;
max-height: 100px;
overflow-y: auto;
overflow-x: hidden;
}
#byte_range { margin-top: 5px; }
<input type="file" id="files" name="file" /> Read bytes:
<span class="readBytesButtons">
<button data-startbyte="0" data-endbyte="4">1-5</button>
<button data-startbyte="5" data-endbyte="14">6-15</button>
<button data-startbyte="6" data-endbyte="7">7-8</button>
<button>entire file</button>
</span>
<div id="byte_range"></div>
<div id="byte_content"></div>
Monitoring Progress
One of the nice things that we get for free when using async event handling is the ability to monitor the progress of the file read; useful for large files, catching errors, and figuring out when a read is complete.
The onloadstart and onprogress events can be used to monitor the progress of a read.
The example below demonstrates displaying a progress bar to monitor the status of a read. To see the progress indicator in action, try a large file or one from a remote drive.
var reader;
var progress = document.querySelector('.percent');
function abortRead() {
reader.abort();
}
function errorHandler(evt) {
switch(evt.target.error.code) {
case evt.target.error.NOT_FOUND_ERR:
alert('File Not Found!');
break;
case evt.target.error.NOT_READABLE_ERR:
alert('File is not readable');
break;
case evt.target.error.ABORT_ERR:
break; // noop
default:
alert('An error occurred reading this file.');
};
}
function updateProgress(evt) {
// evt is an ProgressEvent.
if (evt.lengthComputable) {
var percentLoaded = Math.round((evt.loaded / evt.total) * 100);
// Increase the progress bar length.
if (percentLoaded < 100) {
progress.style.width = percentLoaded + '%';
progress.textContent = percentLoaded + '%';
}
}
}
function handleFileSelect(evt) {
// Reset progress indicator on new file selection.
progress.style.width = '0%';
progress.textContent = '0%';
reader = new FileReader();
reader.onerror = errorHandler;
reader.onprogress = updateProgress;
reader.onabort = function(e) {
alert('File read cancelled');
};
reader.onloadstart = function(e) {
document.getElementById('progress_bar').className = 'loading';
};
reader.onload = function(e) {
// Ensure that the progress bar displays 100% at the end.
progress.style.width = '100%';
progress.textContent = '100%';
setTimeout("document.getElementById('progress_bar').className='';", 2000);
}
// Read in the image file as a binary string.
reader.readAsBinaryString(evt.target.files[0]);
}
document.getElementById('files').addEventListener('change', handleFileSelect, false);
#progress_bar {
margin: 10px 0;
padding: 3px;
border: 1px solid #000;
font-size: 14px;
clear: both;
opacity: 0;
-moz-transition: opacity 1s linear;
-o-transition: opacity 1s linear;
-webkit-transition: opacity 1s linear;
}
#progress_bar.loading {
opacity: 1.0;
}
#progress_bar .percent {
background-color: #99ccff;
height: auto;
width: 0;
}
<input type="file" id="files" name="file" />
<button onclick="abortRead();">Cancel read</button>
<div id="progress_bar"><div class="percent">0%</div></div>
Look into ondragover event. You could simply have a inside of a div that is hidden until the ondragover event fires a function that will show the div with the in it, thus letting the user drag and drop the file. Having an onchange declaration on the would let you automatically call a function (such as upload) when a file is added to the input. Make sure that the input allows for multiple files, as you have no control over how many they are going to try and drag into the browser.
This technique works very well, but if you want a binary blob rather than just to put the dragged image in an html img element, you'll need to use the 'fetch' function twice.

Categories

Resources