views:

790

answers:

3

Hi everyone,

I'm a mostly-newbie Javascript'er and I'm trying it on a webpage which, upon pressing a button, pops up a window which shows a cyclic "movie" with the images from the main window. From what I've tried Googling around I can sense I'm pretty close, but something is eluding me.

I know what follows results in two separate questions, which merit two separate posts. But I figure because both are related with the same problem/objective, maybe this belongs in a single (albeit long) post. So I hope the size of it doesn't enfuriate people too much ... ;-)

Anyway, here's a snapshot of what I think is the relevant code:

<html>
<head>
<script language="javascript">
function wait() {}
function anim() {
  var timeout; var next;
  var popuptitle='Movie';
  var main=parent;
  var popup=parent.open("","",
      "width="+main.document.images[0].width+",height="+(main.document.images[0].height+40)+
      "toolbar=no,location=no,directories=no,status=no,"+
      "menubar=no,scrollbars=no,copyhistory=no,resizable=no");
  popup.document.write('<html><head><title>'+popuptitle+'</title></head><body>'+
    '<p align="center"><img name="anim" width="100%" alt=""></p>'+
    '<p align="center"><button name="close" onclick="javascript:window.close();">Close</button></p>'+
    '</body></html>');
  /*while(true)*/
  for(i=0; i<main.document.images.length; i++) {
    next=main.document.images[i].src;
    popup.document.images[0].src=next;
    timeout=setTimeout('wait();',500);
  }
}
</script>
</head>
<body><h1>Pictures + animation</h1>
<p><button name="exec" onclick="javascript:anim();">Animate (popup)</button></p>
<p><img src="img1.jpg"></p>
....
<p><img src="img16.jpg"></p>
</body>
</html>

I typed/adapted this for relevancy; I hope I didn't make any typos...

I'm working with the Debian Etch's Iceweasel (Firefox 2.x rebrand); I haven't tried this with other browsers. In Iceweasel, what happens is:

  1. The popup show up as is supposed to, but it seems the cycle goes straight to the last picture. setTimeout seems to have no effect in "pausing" between pictures.
  2. The last picture is shown, and the popup's status bar shows its progress bar midway, suggesting something is loading.

So my questions are:

  1. How exactly am I supposed to use the setTimeout call here? I've tried to make it call an "empty" function, so it works as a "pause" in the cycle having the setTimeout(), where the cycle updates the popup single image from the main window's images array.
  2. I find that, if I load the popup by loading the HTML code from an external file (anim.html), the statusbar seems to show from the "progress bar" that the window keeps expecting a reload. I'm still going to try if it's from somewhere else, but what I want to know if it is important/relevant that I load the HTML page from an external file with the window.open(), versus loading an empty window and doing a writeln to it to "write" the HTML.
  3. I've commented the "while(true)" in the cycle, because otherwise the browser stops responding and the computer goes to 100%CPU. I could make an "if" in the "for" cycle to set the counter back to zero before the last item, but is there another "elegant" or "more appropriate" way to make this an infinite cycle -- or does the "while(true)" do just fine?

I appretiate your comments in advance, and if possible a pointer to existing bibliography describing similar solutions.

+3  A: 

I do not think this means what you think it means:

timeout=setTimeout('wait();',500);

Apparently, you're trying to sleep() with this. That's not how the JS timeouts work - this happens onclick in your code: you loop through the images array, immediately switch images from 0th to 1st ... to last; also, on every switch, you say "run the wait() function, 500 ms from now".

window.setTimeout(foo,bar,baz) does this: it sets a timer for bar milliseconds and returns. Code execution continues with the next statement. After bar milliseconds, function foo(baz) is automagically called. The 3rd and following arguments for setTimeout are optional and will be passed to the function in 1st argument.

What you could do:

function anim() { 
  var timeout; var next;
  var popuptitle='Movie';
  var main=parent;
  var popup=parent.open("","",
      "width="+main.document.images[0].width+",height="+
      (main.document.images[0].height+40)+
      "toolbar=no,location=no,directories=no,status=no,"+
      "menubar=no,scrollbars=no,copyhistory=no,resizable=no");
  popup.document.write('<html><head><title>'+popuptitle+
    '</title></head><body>'+
    '<p align="center"><img name="anim" width="100%" alt=""></p>'+
    '<p align="center"><button name="close" ' + 
    'onclick="javascript:window.close();">Close</button></p>'+
    '</body></html>');

  // *changed below*
  // start the animation with the 0th image
  next_image(0,main.document.images,popup.document.images[0]);
}

function next_image(index,source_image_array,target_image) {
    // if not at end of array
    if (source_image_array.length < index) { 
        next=source_image_array[index].src;
        target_image.src=next;

        // do this again in 500 ms with next image
        window.setTimeout(next_image,500, index+1 ,
                            source_image_array,target_image);
    }
}

This way, at the end of your anim() function, you call next_image(0), which sets the image to the 0th in array and sets a timer to call next_image(1) in 500 ms; when that happens, the image will be set to the 1st and a timer will be set to call next_image(2) in another 500 ms, and so on, until there are no more images in the array.

Piskvor
+1  A: 

This isn't a direct answer to your question, but by using the JavaScript framework jQuery and a plugin, you can easily have a image slideshow. I think it's great that you want to learn JavaScript from the grounds up, but going the jQuery+plugin route can save you many, many hours. Heck, even if you want to DIY, I would still recommend using jQuery because it makes DOM manipulation so much easier.

BeefTurkey
A: 

To Piskvor: Thank you for your reply, this is exactly what I needed to know:

setTimeout(foo,bar,baz) does this: it sets a timer for bar milliseconds and returns. Code execution continues with the next statement. After bar milliseconds, function foo(baz) is automagically called. The 3rd and following arguments for setTimeout are optional and will be passed to the function in 1st argument.

So, here follows the corrected example; I hope it helps other Googlers ;-)

<html>
<head>
<script language="javascript">
function display(img,i, popup) {
  var next; var after_ms=750; var max=img.length;
  if(i>=max) i=0;  /* so we can cycle infinitely */
  next=img[i].src; popup.document.images[0].src=next;
  setTimeout(display,(i+1<max?after_ms:4*after_ms), img,i+1,popup);
}
function anim() {
  var popuptitle='Movie';
  var popup_properties="width="+document.images[0].width+
      ",height="+(document.images[0].height+40)+
      ",toolbar=no,location=no,directories=no,status=no"+
      ",menubar=no,scrollbars=no,copyhistory=no,resizable=no"
  var popup=parent.open("", popuptitle, popup_properties);
  popup.document.write('<html><head><title>'+popuptitle+'</title></head><body>'+
    '<p align="center"><img name="anim" width="100%" alt=""></p>'+
    '<p align="center"><button name="close" onclick="javascript:window.close();">Close</button></p>'+
    '</body></html>');
  display(document.images,0, popup);
}
</script>
</head>
<body><h1>Pictures + animation</h1>
<p><button name="exec" onclick="javascript:anim();">Animate (popup)</button></p>
<p><img name="1"  src="img1.jpg"></p>
....
<p><img name="16" src="img16.jpg"></p>
</body>
</html>

What I've also learned:

  1. The "while(true)" is evil, it makes the browser hang. Instead, I've used a condition in the anim() function which sets the index back to zero when it reaches the end.
jbatista