tmedwards / sugarcube-2

SugarCube is a free (gratis and libre) story format for Twine/Twee.
https://www.motoslave.net/sugarcube/2/
BSD 2-Clause "Simplified" License
177 stars 41 forks source link

Config.ui.updateStoryElements = false; makes :passageend trigger before UI bar special passages on page reload #115

Closed gulumige closed 2 years ago

gulumige commented 3 years ago

SugarCube 2.35.0 Tweego 2.1.1

Error under specific circumstances. Not sure if the title describes the actual issue.

Config.ui.updateStoryElements is set to false. There are elements with IDs inside of the StoryCaption passage. I have added a macro <<end>> that is identical to the new <<done>> macro except it wikifies its content on :passageend instead of :passagedisplay.

The goal is to have <<replace>> macros inside my <<end>> macros that could target an element in the UI bar and update its content even if the page was reloaded, however, when I do reload the page the <<replace>> always throws the 'no elements matched the selector "..."' error. It works on regular passage navigations and/or if Config.ui.updateStoryElements is set to true.

Is this expected or is it a misunderstanding on my part?

tmedwards commented 3 years ago

If updating the UI bar story elements is disabled, then after the initial render they're never touched by SugarCube again. Thus, any elements that result from that initial, and only, render will be on, and stay on, the page unless you do something that results in their removal. You should be able to find them at any point after they're rendered.

Questions:

ezsh commented 3 years ago

I had a similar problem, although there is no StoryCaption passage in my case, but #story-caption div in the ui-bar was created by me (to avoid changing other code that renders there) during JS loading phase. Then I render some content into it from a :passagedisplay handler, but afterwards SC removes the div. Changed #story-caption to another id and it "survives" file reloading.

My expectation was Config.ui.updateStoryElements = false means no updates at all, including no content removing.

tmedwards commented 3 years ago

My expectation was Config.ui.updateStoryElements = false means no updates at all, including no content removing.

Do not update each turn does not mean do not initialize or perform an initial render.

Beyond that. Attempting to manually create or remove elements with special meaning to SugarCube, #story-caption in this case, is unwise.

ezsh commented 3 years ago

Of course, but my point was about the difference between the SC behaviour after file reloading and the normal passage update. It looks like events chains are different, or the one-time ui bar cleanup is performed after user rendering.

gulumige commented 3 years ago

tw

:: Start
[[Second]]

:: Second
[[Start]]
<<end>>
    <<replace '#my-element'>>REPLACED TEXT<</replace>>
<</end>>

:: StoryCaption
@@#my-element;ORIGINAL TEXT@@

js

Config.ui.updateStoryElements = false;

Macro.add('end', {
  skipArgs: true,
  tags: null,

  handler() {
    const contents = this.payload[0].contents.trim();

    // Do nothing if there's no content to process.
    if (contents === '') {
      return;
    }

    // Replaced :passagedisplay with :passageend
    $(document).one(
      ':passageend',
      this.createShadowWrapper(() => $.wiki(contents)),
    );
  },
});

Reloading the page when Second is the active passage throws an error.

tmedwards commented 3 years ago

It's an order of operations issue. Try something like the following <<end>> macro:

Macro.add('end', {
    skipArgs : true,
    tags     : null,

    handler() {
        const contents = this.payload[0].contents.trim();

        // Do nothing if there's no content to process.
        if (contents === '') {
            return;
        }

        // Wikify the content on a later frame to give the
        // DOM time to reflect updates.
        setTimeout(this.createShadowWrapper(
            () => $.wiki(contents)
        ), Engine.minDomActionDelay * 2);
    }
});
tmedwards commented 2 years ago

Assuming this can be closed.