Using Story Variables in JavaScript
A minor (3.x) version increase usually shouldn't have significant incompatibilities with existing code, but there is something I must mention: arbitrary Javascript syntax embedded in Harlowe macro calls is no longer permitted, and will produce an error. This includes stuff like
(if: (document.title = "Wowie") is 1)[]
(which does nothing except change the window title to "Wowie") or writing(set: $a = 1)
instead of(set: $a to 1)
.
Then it would be nice to simply have a (javascript:)
macro, wouldn't it? Granted, you can use <script></script>
, but you can't use story variables without also using a scope escalation hack, which gets really messy. It's nice to be able to just embed JavaScript into our code, and can allow someone to do very powerful things, like using a database for a leaderboard or backups for save files. I personally don't see why we're not allowed to access story variables in JS. While most users won't need it, and therefore won't use it, some will. Instead you have to use an escalation hack and do stuff like this:
<script>
// after the escalation hack, not gonna say how to do this lol
var variable1 = harlowe.State.variables['var1'];
// do stuff with variable1, like even just alerting it
alert(variable1);
// you could also directly reference that in the print statement, but...
alert(harlowe.State.variables['var1']); // just sucks
// and setting the story variable would be
harlowe.State.variables['var1'] = "whatever";
</script>
^As you can see, that is an absolute disaster.
Now the question is, how would we make this (javascript:)
macro work?
- We could try using a CodeHook. Now, the question is: where do we put it?
(javascript:[])
or(javascript:)[]
? Now for the hardest part: how would we handle this? Javascript uses the brackets for arrays and such, so that wouldn't work. So can we really use a CodeHook? - We could use a string argument. We could simply do something like
(javascript:"alert($a)")
, and just use regex to find story variables and replace them withharlowe.State.variables['a']
(or however it's actually accessed by the engine). This would also easily allow dynamic JS in the story. Problem: that's a terrible idea and is basically JSeval()
all over again. - We could just override the new macro-running code and treat it the old way. But that makes it into a syntax tree, then makes it into a string, then uses the funny
eval()
command, which this entire process is both slow as hell and sketchy. - We scrap the idea of a
(javascript:)
macro and just allow the user to access story variables in<script></script>
via, say,story.variables['var1']
, like we do in the scope escalation hack, but without the need of doing the actual hack.