I have an application where I am embedding a Twine story in an iFrame on a web page and I want to be able to access the variables that get set with the native Twine macros through Javascript. So say I set an variable called $test. How do I get teh value of $test into a Javascript variable outside of the iFrame?
Comments
The following solution uses an undocumented feature which may not exist in future releases of Harlowe, it uses a Scope Escalation hack to make that undocumented feature available globally, and it contains no error checking so you need to add your own.
Use the following solution at your own risk.
The following is broken into two parts:
1. Making Harlowe's variable State available globally.
a. You can use the undocumented State.variables property object to access variables via Javascript within a Passage like so: ... but the State property only has a Local Scope which means that while Harlowe currently supports you accessing it internally from Passages and the Story Javascript area, it does not support accessing it externally via things like the Developer Console (or an iFrame container)
b. You can use a Scope Escalation hack to make Scope available globally, the following code is placed within your Story Javascript area. It defines a new global property named harlowe which contains access to the State property. ... you should now be able to access the State property within the Developer Console using code like the following:
2. Accessing Harlowe's variable State from an iFrame container.
note: The twine Story HTML file and the HTML file containing the iFrame need to be hosted on the same domain.
The following is a skeleton of a HTML file containing the Javascript needed to access the internal window object of an iFrame, and via that the escalated Harlowe State object. It assumes that the Story HTML file is named story.html
eg. Based on the passage example from 1a. you would use the following command in the Developer Console to access the externally access the value of $var
If you do decide to change to SugarCube then know that TheMadExile (the developer) recommends using the 2.x series as it is the one that is being actively updated/extended, where as the 1.x series mostly only receives bug fixes.
While code within the <iframe> could be setup to respond to messages from the parent (i.e. parent posts a message requesting the value of $test, child responds with the value of $test), that is not the only way to communicate.
There's no reason the code running within the <iframe> could not simply push data at the parent at predefined points (e.g. when passage navigation happens or simply at regular intervals).
There are two major issues with directly accessing the contents of the <iframe> from its parent:
Assuming that they're doing something very simple, they may not need to use postMessage() at all—that's why I used the words "Ideally" and "should" in my original post, rather than "must".