Screen capture of the actual HTML Preview explained in this article
What is HTML Preview
HTML Preview is a tool answering a need I have got for a couple of years, actually since I started storing tons of
HTML archives on my hard drives. My problem is likely to be yours : how to preview
HTML pages without actually double-clicking on each item thus waiting for Internet Explorer to render it.
The amazing thing is that out there on the Internet, you have hundreds if not thousands of image thumbnailer sharewares, but you don't have a single tool to build automatically and with ease an aesthetic preview of all
HTML pages in a given folder.
So let it be there.
Playing with HTML Preview
Before you intend to read the remainder of this article (if you like, or if you can), you may play with the provided
HTML source code by doing the following. Once downloaded htmlpreview.html:
- copy this file in the target folder
- of course you need html pages to play with,
- double-click on it
- answer Yes when IE asks you if ActiveX scripting should be let run
- just watch!
Building the HTML Preview from scratch
The story begins with the Windows Explorer web folders feature. You know, that space hungry thing anyone disables after a couple of days, which shows a zoomed out view of a selected picture, html or even doc file. Well, as anyone certainly guesses, this feature is full of
HTML behind the wheel. Read
this
MS article for more info. Namely, when the web folders are activated, the operating system looks for either a
<user profile>\folder.htt file or for the default
<windowsdir>\web\folder.htt file. This .htt file is in fact simple
HTML with ActiveX scripting inside (remember to enable ActiveX scripting in your Internet configuration panel).
What I've done is figure out the actual elementary ActiveX component that builds the preview of one picture or document, and then put some application logic to reflect the fact that I want not a single preview in the output, but the preview of all
HTML pages.
Below is the key data for this ActiveX :
-
ActiveX friendly name: ThumbCl class
-
CLSID : 1D2B4F40-1F10-11D1-9E88-00C04FDCAB92
-
Automation-enabled
-
Exposed methods:
HRESULT displayFile([IN] BSTR filepath)
HRESULT haveThumbnail([OUT] BOOL *bThumbnail)
-
Exposed properties :
[propget] HRESULT freeSpace( long *);
[propget] HRESULT usedSpace( long *);
[propget] HRESULT totalSpace( long *);
Of course as anyone guesses the one and only method that is worth mentioning is that
displayFile([IN] BSTR filepath). It uses the client area declared in the
HTML <object...> tag to render a preview of the passed file.
In fact, in HTML, that's simple code like follows :
<table>
<tr>
<td>
<object id=Thumbnail_0
classid="clsid:1D2B4F40-1F10-11D1-9E88-00C04FDCAB92"
width=120 height=100>
</object>
</td>
<td> </td>
</tr>
</table>
<script>
function Init_0()
{
Thumbnail_0.displayFile( 'D:\\new_stuff\\codeproject_homepage.htm' )
}
</script>
So far that's easy. Now let's put this in true dirty Javascript code. In order to do this, we assume the following (to keep things simpler for the moment) :
- we have an file enumerator called fc to browse all files of the current folder.
fc.item()
returns the current file, and fc.moveNext()
switches to next.
- we are working with a variable curdir, which holds the current folder being previewed.
thisfilename = htmlpreview.html
The Javascript code to do the previewing of all *.htm(l) pages is as follows :
<script language="javascript">
var imgsize = " width=160 height=140";
var clsid = " classid='clsid:1D2B4F40-1F10-11D1-9E88-00C04FDCAB92'";
var fso = new ActiveXObject("Scripting.FileSystemObject"), f, fc;
f = fso.GetFolder(curdir);
fc = new Enumerator(f.files);
s = "";
sf = "<script language="'javascript'"> function Init() { ";
i = 0;
for (; !fc.atEnd(); fc.moveNext())
{
name = "Thumbnail"+i
s = "<object id=" + name + clsid + imgsize + "></"+"object>";
if (fc.item().Name.indexOf(".htm",0)>-1 && fc.item().Name!=thisfilename)
{
s = "<a href='"+fc.item().Name+"'>" + s + "</a>";
document.write(s);
s = name +
".displayFile( '" + fc.item().Path.replace(/\\/g, "\\\\") + "');";
sf += s;
i++;
}
}
sf += "} </"+ "script>";
document.writeln(sf);
</script>
Again sorry for those who don't speak Javascript.
OK, now before providing the full uncensored listing, let's discuss the initial steps : When you double-click on htmlpreview.html in any folder, we begin with retrieving the full qualified path of htmlpreview.html, for instance c:\ Documents and Settings \ Administrator \ My Documents \ htmlpreview.html. But instead of getting just that with :
var fullpath = location.href;
we rather get something of the form
file:/// c:/ Documents%20and%20Settings / Administrator / My%20Documents / htmlpreview.html because javascript is cross-platform by design, thus returns a file://-protocol compliant URI.
We remove, strip down, replace some stuff out of this one to prepare URIs that are meaning something for the web browser when htmlpreview.html is being rendered. That's why you'll see the following code :
<script language="javascript">
var fullpath, curdir, thisfilename;
fullpath = location.href;
fullpath = fullpath.replace(/file:\/\/\
fullpath = fullpath.replace(/\
fullpath = fullpath.replace(/%20/g," ");
var iLastBackslash = fullpath.lastIndexOf("\\");
// = htmlpreview.html
var thisfilename = fullpath.substring( iLastBackslash+1, fullpath.length);
// remove filename from full path, we are just interested in the path
var curdir = fullpath.substring( 0, iLastBackslash );
</script>
Ok now for full listing of
htmlpreview.html :
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> HTML Preview </TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" onload="Init()">
<script language="javascript">
var fullpath, curdir, thisfilename;
fullpath = location.href;
fullpath = fullpath.replace(/file:\/\/\
fullpath = fullpath.replace(/\
fullpath = fullpath.replace(/%20/g," ");
var iLastBackslash = fullpath.lastIndexOf("\\");
// = htmlpreview.html
var thisfilename = fullpath.substring( iLastBackslash+1, fullpath.length);
// remove filename from full path, we are just interested in the path
var curdir = fullpath.substring( 0, iLastBackslash );
// purpose : use directory file enumerator to list all *.htm* files
// and prepare a table cell to preview it using the preview ActiveX
// put the following line in comment if you don't want scaling
var imgsize = " width=160 height=140";
var clsid = " classid='clsid:1D2B4F40-1F10-11D1-9E88-00C04FDCAB92'";
var fso = new ActiveXObject("Scripting.FileSystemObject"), f, fc;
f = fso.GetFolder(curdir);
fc = new Enumerator(f.files);
s = "";
sf = "<script language="'javascript'"> function Init() { ";
i = 0;
for (; !fc.atEnd(); fc.moveNext())
{
// create an ActiveX instance for the preview of this html file
name = "Thumbnail"+i
s = "<object id=" + name + clsid + imgsize + "></"+"object>";
if (fc.item().Name.indexOf(".htm",0)>-1 && fc.item().Name!=thisfilename)
{
// and add an hyperlink to play with
s = "<a href='"+fc.item().Name+"'>" + s + "</a>";
document.write(s);
// attach initialisation code to it
// .replace(/\\/g, "\\\\") replaces simple backslashes with double-backslashes
s = name + ".displayFile( '" + fc.item().Path.replace(/\\/g, "\\\\") + "');";
sf += s;
i++;
}
}
sf += "} </"+ "script>";
document.writeln(sf);
</script>
The hyperlinks we have inserted while generating the HTML code are of course enabled : just right-click on previews.
Last remark, if you would like to change the size of thumbnails, just change the imgsize value.
The sample Code project preview then becomes (fraction-only to avoid full size) :