Persistent symbol with an iFrame inside

Sounds very good!
Will give it another try…

Have read the structure approach thread several times. Don’t get how a simple example of ‘inject code’ at runtime would be.

Once it works, get the idea with HypeGlobalBehaviour.js from @MaxZieb :slight_smile:

Attached, a small test project.
In the document main.hype, the last scene contains a simple test.

Keyboard arrow keys are used to navigate between the scenes in the main document. If the embedded document ‘contentA’ gets input focus, a click in the dark surrounding area will give focus back to the main document, for keyboard navigation. (That issue I think I know how to get rid of once everything else works as wanted.) (697.1 KB)

@h_classen I found a couple of lines of javascript in a document you have uploaded! :slight_smile: Thanks!!

Managed to get it to work. Almost…

Now have a persistent symbol, it gets injected code and displays another Hype document without an iFrame involved. The Hype document within the persistent symbol keeps it state, regardless of what scene it is on in the main Hype document.

However, elements in the main document disappears when scene changes happens in the main document.

My feeling: something is wrong with paths/contexts for the autogenerated Hype javascripts…
…or is there some kind of conflict with two HYPE-664.full.min.js ?…
…auto generated unique ids not unique…
…something missing…

On Symbol Load for the persistent symbol:
(seems to happen only once, as wanted)

function embedHypdeDocumentA(hypeDcument, element, event) {
	var htmlText = '<div id="contenta_hype_container" class="HYPE_document" style="margin:auto;position:relative;width:100%;height:100%;overflow:hidden;"></div>';
	var scriptSrc = 'contentA/contentA.hyperesources/contenta_hype_generated_script.js?49003';
	var hypeImportElement = document.getElementsByClassName("containerA")[0];
    const documentFragment = document.createDocumentFragment();
    const documentFragmentRoot = document.createElement("html");
    documentFragmentRoot.innerHTML = htmlText;
    const hypeDivElement = documentFragmentRoot.querySelector(".HYPE_document");
    let newScriptTag = document.createElement("script");
    newScriptTag.src = scriptSrc;
    newScriptTag.type = "text/javascript";
    newScriptTag.charset = "utf-8";

One more thing, as long as input focus is on the main Hype document, keyboard navigation UP/DOWN arrow can be used to navigate between scenes in the main document.

So… the ‘sub’ document can be set to e.g. scene 2 by using the Next button within the white area…
…and the main document set to e.g. scene 3. As this doesn’t work correctly for the moment with the buttons, it works by using the keyboard e.g. DOWN Arrow. To be sure to have the right input focus, click once in the dark grey area before hitting the arrow key.

Attached, my test project for this.
Help needed…
I think by taking a look in main.hype it is quite clear how this is constructed.

If I can ge this to work, next. step try to use HypeGlobalBehaviour from @MaxZieb. (741.4 KB)

i would think that this’ll do. can’t invest at the moment … @jonathan may know what happens …


(Above, added a short description of the keyboard navigation implemented.)

Having a Hype document’s DOM within another Hype document won’t work correctly. The issue you are hitting is caused by an exception while Hype is doing a scene transition. In fact, it may only be the fact that you are using persistent symbols that this issue occurs. Specifically the problematic line in Hype’s runtime is:

var descendantsOfPersistentSymbol = getElementsByClassName("HYPE_element", domElement);

For various reasons, Hype needs to look at the descendant elements of persistent symbols and do a bit of work on them when the scene changes. This code is run in the main document, but finds Hype elements from the child document that it knows nothing about, and then barfs since it is expecting to know about all its Hype elements.

I’d recommend instead an approach where your child document is outside the main DOM structure, and you overlay on top with a z-index.

I’m uncertain about the keyboard issue as that part seems to work for me, but perhaps it is related in a way I can’t trigger. Feel free to send an ordered list of repro steps there.


ah sry, so that’s an iFrame-Setup … thx for info @jonathan
Too bad … :wink:

1 Like

No worries!
Have had that gut feeling these last days. Now we know, don’t try this with current version of Hype.

“child document is outside the main DOM structure, and you overlay on top with a z-index”…
…have to think about that again, more than twice. It’s like plan D out of A – F.

Thing is, the responsive settings for this project has become… a bit complex, yet visually distinctive and clear. The guide modes, ON/OFF — look way up in this thread for a hint — puts the entire thing in one of two different visual modes. The mode switch, animated on several layers of elements, timelines.

Wish I could share a sample of the real project. NDA and all of that.

Keyboard navigation works fine. No problem with that.

@MaxZieb see something like another Hype extension here?… :slight_smile:

Using Global Behavior and iFrames should work fine. Just make sure to include the JS in the main and iFrame HTML wrapper and your good to go. I will use some of the spare time the coronavirus is given us all to document stuff better. Take care!

1 Like

Thanks @MaxZieb
will consider and try that.

Guess many of us are privileged to be ‘within the IT business’, quite easy to switch to work from home, use online meeting tools a bit more frequently.

Hype and iFrames, in my case…

sub document A contains 8.9 MB of data, video and image resources,
several parallel timelines (animations) on each one of 3 major scenes,
for each scene, animations run from about 1.5 to 8 seconds.

With an iFrame that needs to be reloaded because it is within a main document, present on 3 scenes,
feels like there needs to be a way to
only load that data once

[ 'create offline cache' for that sub Hype document? ]

And a way — Global Behavior ? — to very early send postMessages,
In order to get a quick, fluid, stable user experience (34.4 KB)

external hypedoc connected to a symbolsstyleproperties … i short tests it did the job. simple setup.


The way this would be setup is you would still have a Hype element that would be a fake parent. This element would have the flexible layout options. You would query this element to determine the global position via element.getBoundingClientRect(), and then set the outside element to this position on scene load. You would also add an event listener to the window’s "resize" event, which is what Hype uses to determine if it needs to relayout. (This may need a 1ms delay to ensure it fires after Hype has done its relayout).

that’s what my provided example does :slight_smile:

1 Like

Oh ha, sorry I skimmed through the rest and it sounded like your solution was going a different route! I should have looked more closely and at the document :smiley:.

except this … just added @MaxZieb’s MutationObserver-Solution … :slight_smile:

@h_classen @jonathan together with a talented developer colleague – a bit familiar with Hype – we have solved it I think, hope… (like 97% now); things look and behave as intended. Seems to be stable, robust, tested in popular browsers. No persistent symbol with iFrame or injected code. Another way…

Must say; really, really like how you quickly give hints and help here at this forum!
Will try to help more myself.

Will take a look at the Hype document you posted @h_classen… element.getBoundingClientRect @jonathan

Can’t post a copy of this client project.

A hint… below is a snippet from the main html file with the code for the main Hype documents, there are two now. One for the ‘guide’ in our case and one for the ‘demo containers’, a scene with an iFrame for each demo to load. (And a bunch of demos, each one a Hype document.)

Sometimes the Hype ‘guide’ document spans 3 scenes, the ‘demoContainers’ stays steady with its iFrame content and that Hype document in a certain state – when a scene change occurs in the Hype ‘guide’ document. In guide mode, a message is sent to the document in the current iFrame… timelines continued… scene changes… etc.

For each demo there is different number of guide steps and different messages needed to be sent to the current demo. Going backwards through the sequence doesn’t work perfectly now…

…so we will take another look at @MaxZieb HypeGlobalBehavior. If time left for this first version, we will use it. Otherwise for next version!

Will restructure this before delivery, anyway… here you get an idea:

(position: absolute, z-indexes - two Hype docs on top of each other. Both of them, a lot of flexible layout settings, layers, layers, timelines. Top one with transparent background.)

    <div class="appMaxSize">
        <div id="index_hype_container" class="HYPE_document" style="margin:auto;position:absolute;width:100%;height:100%;overflow:hidden;z-index:2;pointer-events:none;">
            <script type="text/javascript" charset="utf-8" src="index.hyperesources/index_hype_generated_script.js?6203"></script>
      <div id="democontainers_hype_container" class="HYPE_document" style="margin:auto;position:absolute;width:100%;height:100%;overflow:hidden;z-index:1;">
        <script type="text/javascript" charset="utf-8" src="demoContainers.hyperesources/democontainers_hype_generated_script.js?456"></script>
<script type="text/javascript">
    function demoContainerShowNone() {
        // Default scene at start for 'demoContainers'.
        HYPE.documents['demoContainers'].showSceneNamed('none', HYPE.documents['demoContainers'].kSceneTransitionInstant);
    function demoContainerShowMsituDemo() {
        if (HYPE.documents['demoContainers'].currentSceneName() !== 'msitu') {
        	HYPE.documents['demoContainers'].showSceneNamed('msitu', HYPE.documents['demoContainers'].kSceneTransitionInstant);
    function doSignInMsituDemo() {
        if (HYPE.documents['demoContainers'].currentSceneName() !== 'msitu') {
        	HYPE.documents['demoContainers'].showSceneNamed('msitu', HYPE.documents['demoContainers'].kSceneTransitionInstant);
        var msituIframe = HYPE.documents['demoContainers'].getElementById('msitu_iFrame').querySelector('iframe');
        msituIframe.contentWindow.HYPE.documents['msitu'].continueTimelineNamed('Main Timeline', msituIframe.contentWindow.HYPE.documents['msitu'].kDirectionForward, false);

    function msituShowPatientDevices() {
        if (HYPE.documents['demoContainers'].currentSceneName() !== 'msitu') {
        	HYPE.documents['demoContainers'].showSceneNamed('msitu', HYPE.documents['demoContainers'].kSceneTransitionInstant);
        var msituIframe = HYPE.documents['demoContainers'].getElementById('msitu_iFrame').querySelector('iframe');
        msituIframe.contentWindow.HYPE.documents['msitu'].showSceneNamed('patientDevices_usr_1', msituIframe.contentWindow.HYPE.documents['msitu'].kSceneTransitionInstant);
    function demoContainerShowFuonKeyAccountsDemo() {
        if (HYPE.documents['demoContainers'].currentSceneName() !== 'fuonKeyAccounts') {
        HYPE.documents['demoContainers'].showSceneNamed('fuonKeyAccounts', HYPE.documents['demoContainers'].kSceneTransitionInstant);
    function doSignInFuonKeyAccounts() {
        if (HYPE.documents['demoContainers'].currentSceneName() !== 'fuonKeyAccounts') {
        HYPE.documents['demoContainers'].showSceneNamed('fuonKeyAccounts', HYPE.documents['demoContainers'].kSceneTransitionInstant);
        var fuonKeyAccountsIframe = HYPE.documents['demoContainers'].getElementById('fuonKeyAccounts_iFrame').querySelector('iframe');
        fuonKeyAccountsIframe.contentWindow.HYPE.documents['index'].continueTimelineNamed('Main Timeline', fuonKeyAccountsIframe.contentWindow.HYPE.documents['index'].kDirectionForward, false);
1 Like

I don’t get it. Will ask my developer friend tomorrow! :slight_smile: