1

First off, for Chromecast reasons, I want to, currently, limit the solution to the Chrome browser.

What I'd like to do is package up a directory of images, with a launcher batch file (cmd or sh) and an html file. The html file is to be completely self contained, with no imports.

The bat file would contain something like:

"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --allow-file-access-from-files "file://%CD%\SlideShow1.2.html?slideDir=%CD%\Slides"

Currently I can use

<input type="file" id="slideInput" multiple="multiple" webkitdirectory="webkitdirectory" onchange="appendToSlideList();" accept=".png,.gif,.jpg,.jpeg" />

to manually select files, and

  var slideList = [];
  var numSlides = 0;

  function appendToSlideList()
  {
    var slideInput = document.getElementById("slideInput");
    var slides = slideInput.files;

    for(j = 0; j < slides.length; j++)
    {
      slideList[numSlides++] = slides[j];
    }
  }

to append pictures from selected directories to the master slide list. Then the following, via a Timer() object displays the slides:

  function showNext()
  {
    if(picture == null)
    {
      picture = document.getElementById("slideShow");
      intervalElem = document.getElementById("interval");
    }
    if(currentPicture == numSlides)
    {
      currentPicture = 0;
    }
    // this comes from https://www.w3.org/TR/file-upload/#file
    picture.src = window.URL.createObjectURL(slideList[currentPicture++]);

    var interval = parseInt(intervalElem.value) * 1000;
    timer = new Timer(showNext, interval);
  }

If you've read this far, kudos :). So, all this (plus other auxiliary code that is not germane to the desired solution) works to show a slideshow based on user input from the object.

My desire is to package things up so that all the user has to do is double click on the bat file, and the browser proceeds to show the slide show.

So, after all this, my question is, how do I take the directory passed in, and get all the graphic files in that directory, for use in the already working code.

I've spent the last six hours researching this question, much on StackOverflow, and it appears, to me, currently, that this is an impossible quest.

Here's a fiddle with 'complete' minimalist code: https://jsfiddle.net/hrvrdfjs/

Thanks!

Tom.

  • Would it be okay if the batch file creates an additional file (in the directory with the images or in the temp folder) before calling the browser? – NineBerry Jan 07 '18 at 18:06
  • It depends: I'm planning this to be burnt to cd/dvd/bluray, whataver, so the file would have to be created BEFORE the medium is created, as it would subsequently be read-only. – Tom Kimpton Jan 07 '18 at 19:29

2 Answers2

0

There is currently no way for JavaScript in the browser to list files from a directory without the user explicitly choosing the directory in the browser.


However, you can easily create a JavaScript file that contains a list of the image files in the directory from a batch file like this:

@echo off
echo var toC = ` > "C:\slides\data.js"
dir  C:\slides\*.png,*.gif,*.jpg,*.jpeg  /B >> "C:\slides\data.js"
echo `;  >> C:\slides\data.js

This will create file data.js which looks like this:

var toC = ` 
funny.png
serious.png
holidays.jpeg
`;  

Explanations:

echo var toC = ` > "C:\slides\data.js"

Creates or overwrites the file C:\slides\data.js with the javascript code that is the first part of creating a template literal.

dir  C:\slides\*.png,*.gif,*.jpg,*.jpeg  /B >> "C:\slides\data.js"

Tells dir to list the files with the given extensions in the given directory and appends the file names to the file data.js. The parameter /B makes dir only output the files names, no other information and also skip outputting a header and footer for the listing.

echo `;  >> C:\slides\data.js

This appends the end of the javascript template literal.

In JavaScript ES6 and newer, template literals can be used to create string literals that span multiple lines and can contain arbitrary characters.


Load the file data.js dynamically from your html document (by inserting a script tag that refers to the file) and you can access the variable toC which contains the list of files as a multi-line string.

This is a demo where the data.js file is statically included:

<html>
<head>
<script src="C:\slides\data.js"></script>
</head>
<body>
  <script>
    window.alert(toC);
  </script>
</body>
</html>
NineBerry
  • 26,306
  • 3
  • 62
  • 93
0

I wasn't able to use the "dir" command as given above, perhaps because I'm using windows 7. Here is what I came up with, instead:

mkdir C:\Temp\slideShow

rem Replace each instance of a back slash with two, as javascript will remove a single backslash
rem (Unless it is followed by a 'valid' backslash char (r,n,etc.), which is not what we want.).
echo var topLocation = '%CD:\=\\%'; > C:\Temp\slideShow\topLocation.js

echo var slideDirContents = ' > "C:\Temp\slideShow\slideDirContents.js"
dir  %CD%\Slides\*.jpeg %CD%\Slides\*.jpg %CD%\Slides\*.png %CD%\Slides\*.gif   /B /ON >> "C:\Temp\slideShow\slideDirContents.js"
echo ';  >> C:\Temp\slideShow\slideDirContents.js

Then, to split out each file from the input .js file, and create a file path that would later be used to build an URL that the img.src could present the file (NOTE: the add function had to be done after the page was loaded, so the textarea element would be present for the javascript to modify):

  function doOnloadFunctions()
  {
    addStaticsToSlideList();
  }

  function addStaticsToSlideList()
  {
    // Empty dir on Windows == size 2 (CR-LF)
    // Empty dir on others == size 1 (CR or LF)
    if((slideDirContents.length != 2) && (slideDirContents.length != 1))
    {
      var slidelistElem = document.getElementById("slidelist");
      // Linux/Unix/BSD based line separator = \n
      // Windows based line separator = \r\n
      // Mac based line separator = \r
      var re = /\n|\r\n|\r/;
      var slides = slideDirContents.split(re);
      for(j = 0; j < slides.length; j++)
      {
        var aFile = {};
        var theName = slides[j].trim();
        if(theName.length > 0)
        {
          var fileName = slides[j];
          aFile.fileName = topLocation + '\\Slides\\' + fileName;
          // Set the original index to the current insertion point.
          aFile.oi = numSlides;
          // Set the shuffle index simply to instantiate it. We'll
          // set the si for real when we want to shuffle the array.
          aFile.si = 0;

          var listElem = document.createElement("li");
          listElem.appendChild(document.createTextNode(fileName));
          slidelistElem.appendChild(listElem);
          slideList[numSlides++] = aFile;
        }
      }
    }
  }

There's a <file> input element that can be used to append local files to the slide list, the <file> input doesn't fill in fileName it just fills in name thus this is the differentiating code that instantiates each <img> with the proper url:

    if(!(typeof slideList[currentPicture].fileName === 'undefined' || slideList[currentPicture].fileName === null))
    {
      // variable is defined and not null
      picture.src = "file://" + slideList[currentPicture++].fileName;
    }
    else
    {
      // this comes from https://www.w3.org/TR/file-upload/#file
      picture.src = window.URL.createObjectURL(slideList[currentPicture++]);
    }

Thanks to NineBerry for the code and suggestions!