Dynamically change icon in HTA

273 Views Asked by At

NOTE: This question is not a duplicate of Can I embed an icon to a .hta file? - For more details, compare the issues and read the comments

I am trying to build an HTA that will automatically perform certain tasks when executed, without user action. The reason I want to use an HTA instead of just a bare VBScript is to inform the user of progress as the routine executes, since it takes some time, and I don't want the user wondering if it hung, maybe restarting it, and so on. There are ten tasks, and I would like to have ten lines in my HTA display, each one with a few words describing what is happening at that point. So far, so good – that is simple enough.

I would also like to have a small icon before each line, that would initially display one icon. When the task on that line begins, it would switch to a second icon, and when it completes it would switch to a third icon.

For several reasons not pertinent to my question, I want to keep it ALL in my HTA – no references to external files. I found a site that led me to using a tag like:

<img src='data:image/gif;base64,R0lGODlhIAAgAOY…'/>

to display a green check mark. It does that very nicely, but I would like to change that dynamically, and there I am running aground. In my HTA, I have VBScript that does this:

x="<img src='data:image/gif;base64,R0lGODlhIAAgAOY…'/>"

(Shortened – the actual image string is quite long.)

and then I have:

img1.InnerHTML = x

to refer to this placeholder in my HTML code:

<span id = "img1"></span>

The code executes, but does not display the green check, only a small black square with a white 'x'. Am I doing something wrong, or is this just not possible? It seems like it should be possible, but no syntax I have tried so far has worked.

2

There are 2 best solutions below

0
Stephen Quan On

It seems that this question is now unlocked, so I am posting the two answers that I posted in the comments.

The first answer is more imperative, in that we need Javascript to convert SVG into a data URI via the svgToDataURL() function. This example is good because you can see the SVG definition in clear text which makes it easier to maintain and change.

<html>
<head> 
<meta http-equiv="x-ua-compatible" content="ie=edge" />
<script>
function svgToDataURL(svg) {
  return "data:image/svg+xml;charset=utf-8," + encodeURIComponent(svg);
  //return "data:image/svg+xml;base64," + btoa(svg); // this works too!
  //return "data:image/svg+xml;charset=utf-8," + svg; // this only works in modern browsers
}
var assets = {
    redCross: svgToDataURL('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path stroke="red" d="M23.985 8.722L16.707 16l7.278 7.278-.707.707L16 16.707l-7.278 7.278-.707-.707L15.293 16 8.015 8.722l.707-.707L16 15.293l7.278-7.278z"/></svg>'),
    greenTick: svgToDataURL('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path stroke="green" d="M13.5 22.142L7.59 16.42l.636-.636L13.5 20.87 26.721 7.8l.637.637z"/></svg>')
};
</script>
</style>
</head>

<body>

1 + 1 = 2 <img id="demoSVG" width="16" height="16"> <p>

<script>
var demoSVG = document.getElementById("demoSVG");
demoSVG.src = assets.redCross;
</script>

<button type="button" onclick="demoSVG.src = assets.greenTick">Change SVG!</button>
</body>
</html>

The second answer uses CSS style to configure the image as a background style. This means the Javascript required to change the image is shorter. However, it requires you to URL encode your SVG. Note that this full encoding requirement exists because HTA is more sensitive to what it accepts as a URL. If this was an HTML question instead of HTA, the URL encoding requirement is relaxed and you could have used unencoded SVG in this solution as well.

<html>
<head> 
<meta http-equiv="x-ua-compatible" content="ie=edge" />
<style>
div.redCross {
  display: inline-block; 
  width: 16px;
  height: 16px;
  background-image: url(data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cpath%20stroke%3D%22red%22%20d%3D%22M23.985%208.722L16.707%2016l7.278%207.278-.707.707L16%2016.707l-7.278%207.278-.707-.707L15.293%2016%208.015%208.722l.707-.707L16%2015.293l7.278-7.278z%22%2F%3E%3C%2Fsvg%3E);
}
div.greenTick {
  display: inline-block; 
  width: 16px;
  height: 16px;
  background-image: url(data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cpath%20stroke%3D%22green%22%20d%3D%22M13.5%2022.142L7.59%2016.42l.636-.636L13.5%2020.87%2026.721%207.8l.637.637z%22%2F%3E%3C%2Fsvg%3E);
}
</style>
</head>

<body>

<div>1 + 1 = 2 <div id="demo2" class="redCross"></div></div> <p>

<script>
var demo2 = document.getElementById("demo2");
</script>

<button type="button" onclick="demo2.className = 'greenTick'; ">Change SVG!</button>
</body>
</html>
0
LesFerch On

Below, are two examples that demonstrate how to dynamically select among different base64 embedded images (icons) in an HTA file. The first one switches the display style from none to inline to cycle through the images. The second one changes the image by replacing the innerHTML contents. The complete examples are here.

Here are the examples with the base64 code truncated:

Example 1:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" http-equiv="X-UA-Compatible" content="IE=9">
<script language="VBScript">
window.resizeTo 250,350
Dim Text,TextIndex
Text = "ABCD"
TextIndex = 1

Sub window_onLoad
  idTitle.innerText = Text
  document.getElementById(Mid(Text,TextIndex,1)).Style.Display = "inline"
  idLetter.innerText = Mid(Text,TextIndex,1)
End Sub

Sub GoLeft
  If TextIndex=1 Then Exit Sub
  document.getElementById(Mid(Text,TextIndex,1)).Style.Display = "none"
  TextIndex = TextIndex - 1
  document.getElementById(Mid(Text,TextIndex,1)).Style.Display = "inline"
  idLetter.innerText = Mid(Text,TextIndex,1)
End Sub

Sub GoRight
  If TextIndex=Len(Text) Then Exit Sub
  document.getElementById(Mid(Text,TextIndex,1)).Style.Display = "none"
  TextIndex = TextIndex + 1
  document.getElementById(Mid(Text,TextIndex,1)).Style.Display = "inline"
  idLetter.innerText = Mid(Text,TextIndex,1)
End Sub

</script>
<style>
body  {background-color:Black; color:White}
.NoShow {display:none}
.Show {display:inline}
.LgFont {font-size:24pt}
</style>
</head>
<body>
  <h2 id=idTitle></h2>
  <img id=A class=NoShow src='data:image/gif;base64,iVBORw0KGgo...'>
  <img id=B class=NoShow src='data:image/gif;base64,iVBORw0KGgo...'>
  <img id=C class=NoShow src='data:image/gif;base64,iVBORw0KGgo...'>
  <img id=D class=NoShow src='data:image/gif;base64,iVBORw0KGgo...'>
  <br><br>
  <input class=LgFont id=GL type=button value= onClick=GoLeft()>
  <input class=LgFont id=GR type=button value= onClick=GoRight()>
  <span class=LgFont id=idLetter>
</body>
</html>

Example 2:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" http-equiv="X-UA-Compatible" content="IE=9">
<script language="VBScript">
window.resizeTo 250,350
Const BeginTag = "<img src='data:image/gif;base64,"
Const EndTag = "'>"
Dim Text,TextIndex
ReDim AImg(128)
AImg(65) = "iVBORw0KGgo..."
AImg(66) = "iVBORw0KGgo..."
AImg(67) = "iVBORw0KGgo..."
AImg(68) = "iVBORw0KGgo..."
Text = "ABCD"
TextIndex = 1

Sub window_onLoad
  idTitle.innerText = Text
  idImage.innerHTML = BeginTag & AImg(Asc(Mid(Text,TextIndex,1))) & EndTag
  idLetter.innerText = Mid(Text,TextIndex,1)
End Sub

Sub GoLeft
  If TextIndex=1 Then Exit Sub
  TextIndex = TextIndex - 1
  idImage.innerHTML = BeginTag & AImg(Asc(Mid(Text,TextIndex,1))) & EndTag
  idLetter.innerText = Mid(Text,TextIndex,1)
End Sub

Sub GoRight
  If TextIndex=Len(Text) Then Exit Sub
  TextIndex = TextIndex + 1
  idImage.innerHTML = BeginTag & AImg(Asc(Mid(Text,TextIndex,1))) & EndTag
  idLetter.innerText = Mid(Text,TextIndex,1)
End Sub

</script>
<style>
body  {background-color:Black; color:White}
.LgFont {font-size:24pt}
</style>
</head>
<body>
  <h2 id=idTitle></h2>
  <div id=idImage></div>
  <br><br>
  <input class=LgFont id=GL type=button value= onClick=GoLeft()>
  <input class=LgFont id=GR type=button value= onClick=GoRight()>
  <span class=LgFont id=idLetter>
</body>
</html>