2

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?

2 Answers2

2

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:

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:

enter image description here

And the DOM:

enter image description here

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);
    }
 }
Community
  • 1
  • 1
zero298
  • 20,481
  • 7
  • 52
  • 83
  • Thanks but I would like the user to choose their own image, that's why i used tag. so how can i retrieve their image and insert into the iframe? –  Jan 07 '14 at 20:37
  • @User Alright, try this then. It uses both the `` and the Drag and Drop API in HTML5. – zero298 Jan 07 '14 at 21:47
  • Thanks I'm currently testing it out now. It seems to work on JSFiddle, though I've been trying to use it on IE and Chrome. There's an error in the JS that keeps popping up JavaScript runtime error: Unable to get property 'addEventListener' of undefined or null reference. –  Jan 20 '14 at 15:43
  • In IE or Chrome? Any time I get that error, I've mismatched the `id` of the Element in the DOM and the `getElementById` call. Double check that those ids match. If you post a fiddle of your code, I could double check it. Also, if this is only happening when you run IE, what version of IE are you using? Internet Explorer did not support `addEventListener` until version 9. – zero298 Jan 20 '14 at 15:47
  • I tried it on both IE and Chrome, did not work for neither of them. Though IE showed me where the error was. And its IE 9. I used your code where I noticed the error. So I'll check the ids –  Jan 20 '14 at 16:00
  • I've put the code in fiddle. http://jsfiddle.net/J_patel/Lnchf/ But like I said, it works on this. I am using Visual Studios to debug, and whenever I run the code on IE, it doesn't work. –  Jan 20 '14 at 16:39
  • @User Ah, I know what the problem is. The reason it works in the fiddle, is that the fiddle makes sure that the HTML is loaded before the JS executes which means that there **is** a DOM element with the appropriate ID whenever the JS executes. When you run outside of fiddle, the JS can execute before the DOM is fully loaded. If you look at line 29 and 30 in the fiddle, you'll see `29 //window.onload = main; 30 main();` The `window.onload` means, wait till the DOM is fully loaded. Uncomment *that* in the non fiddle and comment out the direct call to `main()` – zero298 Jan 20 '14 at 16:55
  • Done, but the error still comes up in visual studios when trying to run on IE –  Jan 20 '14 at 17:13
  • @User Yes, check my second edit at the bottom of my answer. It's a rewrite of the `loadFile()` function that supports videos. – zero298 Jan 21 '14 at 19:07
0

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.

Community
  • 1
  • 1
cubitouch
  • 1,839
  • 13
  • 27