i have been trying create slideshow using php , javascript mainly. however, reason there no response after click >>
or <<
move next or previous slide.
the php script used grab images folder , form them array. use javascript within php via echo
transform php-array javascript-array.
i used this website tutorial.
thanks help!
<?php //php script: getimages.php //header("content-type: text/javascript"); //this function gets file names of images in current directory //and ouputs them javascript array function returnimages($dirname='c:\apache\htdocs\psych211lifespandevchpt1') { echo "in return images"; $files = array(); $curimage = 0; if ($handles = opendir($dirname)) { echo "in handles"; while (false !== ($file = readdir($handles))) { echo "in while"; $path_info = $_files['file']['name']; $extensions = pathinfo($path_info, pathinfo_extension); echo $extensions; if ($extensions=='png') //if(eregi($pattern, $file)) { //if file valid image //output javascript array element //$files->append($file); $files[$curimage] = $file; array_push($files,$file); //echo $files[$curimage]; // 'slides['.$curimage.']="'.$file .'";'; //echo $curimage; $curimage++; //} } echo $curimage; echo count($files); closedir($handle); } echo '<html> <head> <script type="text/javascript"> var slides = []; slides = '.json_encode($files).'; document.write(slides.length); function cacheimage(imagesource) { // turns string image object var imageobject = new image(); imageobject.src = imagesource; return imageobject; } function showslide(direction) { if (slideready) { nextslide = currentslide + direction; // disable buttons (ie-only) document.slideshow.previous.disabled = (nextslide == 0); document.slideshow.next.disabled = (nextslide == (slides.length-1)); if ((nextslide >= 0) && (nextslide < slides.length)) { document.images["screen"].src = slides[nextslide].src; currentslide = nextslide++; message = "picture " + (currentslide+1) + "of " + slides.length; self.defaultstatus = message; if (direction == 1) cachenextslide(); } return true; } } function download() { if (slides[nextslide].complete) { slideready = true; self.defaultstatus = message; } else settimeout("download()", 100); // checks download status every 100 ms return true; } function cachenextslide() { if ((nextslide < slides.length) && (typeof slides[nextslide] == "string")) { // caches images once slideready = false; self.defaultstatus = "downloading next picture..."; slides[nextslide] = cacheimage(slides[nextslide]); download(); } return true; } function startslideshow() { currentslide = -1; slides[0] = cacheimage(slides[0]); var slideready = true; showslide(1); } </script> </head> <body onload="startslideshow()"> <form name="slideshow"> <table> <tr> <td colspan=2><img src="psych211lifespandevchpt1/slide-1.png" name="screen" width=108 height=135></td> </tr> <tr> <td><input type="button" name="previous" value=" << " onclick="showslide(-1)"></td> <td align="right"><input type="button" name="next" value=" >> " onclick="showslide(1)"></td> </table> </form> </body> </html>'; //return($files); } //echo 'var slides=new array();'; //define array in javascript returnimages() //output array elements containing image file names ?>
most of functions use implicit global variable name slideready
. in startslideshow
use var slideready = true;
try , set it. because prefaced var
setting local variable named slideready
, not global variable other functions have access to, global slideready
remains undefined
.
so when startslideshow
calls showslide
, line
if (slideready) {
is interpreted as
if (false) {
because global slideready
undefined
, falsy value. falsy value coerced false
inside if
statement, code inside of if
block never runs , slide never changes.
using linter jshint or stricter jslint avoid these kinds of errors. running code in strict mode have made kind of error more apparent. there number of other implicit globals in code (nextslide
, currentslide
, message
). implicit globals can cause errors or more insidious ones.
other things improved
window.self isn't commonly used. in particular way code uses bare self
without prefacing window
cause headaches. many people use variable named self
store reference this
in situations need access this
object of outer function inside function using closure. using self
refer window.self
cause confusion reading code uses it. (it did me, has been long since have seen reference window.self
forgot existed!)
window.defaultstatus
has been obsolete long time, browsers don't have status bar anymore; no 1 see messages being posted there.
this code has lot of variable names capitalized. valid code , run, in javascript has become convention constructor functions capitalized. in simplest of terms, constructor function function needs called new
keyword. if in future (including you) works on code, function name being capitalized reminder need use new
keyword before it. linters use convention automatically spot missing new
s you.
accessing form elements via document.formname.elementname
, images via document.images
outdated techniques. using document.formname.elementname
can cause problems if form element has same name property of form. instead giving each button id
and accessing via document.getelementbyid
. in fact, don't need use form , buttons, easy style div
or span
element button.
using onclick
dated way of attaching events, embedding in onclick
in html. less obtrusive use addeventlistener
instead.
for number of reasons many people writing modern javascript prefer use function expressions define function
s instead of function declaration. function declarations can cause puzzling bugs, whereas function expression stored in variable behaves more predictably.
global variables bad , can lead sorts of weird bugs, different parts of code need access common variables. can allow without creating globals wrapping code in immediately-invoked function expression (iife) (sometimes called self-invoking function).
(function () { 'use strict'; var shared = true, foo = function () { // has access shared }, bar = function () { // has access shared }; // can access shared here }()); // can't access shared here because not global
i don't feel necessary or worth preload images. people have reasonably fast connection , if images encoded load in progressively , viewable in state quicker code won't display image until loaded. loading next image before user requests wastes bandwidth important if on mobile.
if think preloading images important, instead of using overly complex system won't display next picture until downloaded, preload them @ beginning:
slides.foreach(function (url) { (new image()).src = url; });
this download each image , store in browsers cache instead of keeping in memory in array code posted does.
modernizing code
a more modern version of javascript code tutorial might more this:
<img id="slide"></td> <div class="slide-controls"> <span class="button" id="prev-slide">«</span> <span class="button" id="next-slide">»</span> </div> <script> (function () { 'use strict'; var slides = [ 'http://www.placecage.com/300/200', 'http://www.placecage.com/g/300/200', 'http://www.placecage.com/c/300/200', 'http://www.placecage.com/gif/300/200' ], currentslide = 0, doc = document, elslide = doc.getelementbyid('slide'), elprev = doc.getelementbyid('prev-slide'), elnext = doc.getelementbyid('next-slide'), showslide = function (index) { if (index > -1 && index < slides.length) { currentslide = index; elprev.classlist.remove('disabled'); elnext.classlist.remove('disabled'); if (index === 0) { elprev.classlist.add('disabled'); } else if (index === slides.length - 1) { elnext.classlist.add('disabled'); } elslide.src = slides[index]; elslide.title = 'picture ' + (index + 1) + 'of ' + slides.length; } }, changeslide = function (step) { var index = currentslide + step; showslide(index); }, prevslide = changeslide.bind(null, -1), nextslide = changeslide.bind(null, 1); elprev.addeventlistener('click', prevslide, false); elnext.addeventlistener('click', nextslide, false); showslide(0); }()); </script>
there no need use docuemnt
load
event (aka onload
), elements defined in markup above javascript code , available when javascript code runs.
instead of using defaultstatus
, putting status message in title
attribute on image, should show tool-tip in browsers if user mouses-over image. output message <div>
if want visible without mouse-over.
i used function.prototype.bind create event hanlders prevslide
, nextslide
.
the lines
prevslide = changeslide.bind(null, -1), nextslide = changeslide.bind(null, 1);
are equal to
prevslide = function () { changeslide(-1); }, nextslide = function () { changeslide(1); };
since separated changeslide
logic actual display of image , showslide
takes index instead of how many forward or go, easy make function jumps first or last slide too:
var firstslide = showslide.bind(null, 0), lastslide = showslide.bind(null, slides.length - 1);
other resources
here few resources related techniques used.
- crockford on javascript - section 8: programming style & brain particularly applicable of stuff discussed, the whole series worth watching. also, reading book "javascript: parts" helps explain reasons lot of stuff.
- the elements of javascript style part one, part two
- a description of function declaration vs function expressions
- namespaces, closures, self-invoking functions, , much, more...
- javascript , html script tags
- named function expressions demystified