Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Sugarcube: Prevent inconsistent jump to new content with

Hi there. Sometimes, whenever I append stuff in Sugarcube in response to a click, usually entire passages at once, the page jumps to the content that was just appended. I want this to not happen, since the abrupt shift can cause readers to get lost. In addition, if I stop this, I can animate a scroll to the start of the newly appended passage. It's a very inconsistent thing. I can't figure out a single thing that has anything to do with whether or not it happens. At first, I thought preventDefault would fix it, but it didn't. Then I thought it had something to do with whether or not I did any scrolling before the first append happens. It doesn't seem that's the case either. It kind of seems like it's more likely to happen if I'm scrolled to the bottom of the page. Like, if it's happening, then it's going to keep happening as long as I'm scrolled to the bottom, but I can stop it if I scroll up even just a tiny bit.

Does any of this make sense to anyone? Any ideas on how to stop it?

If you need an example of a game where this is happening, here: http://tiz.qc.to/pub/shine-0.0.3.html It very often happens in the intro segment, and sometimes in the conversation with TZ (computer -> use -> pesterchum -> answer.) The source for the game is here: http://tiz.qc.to/pub/shine-0.0.3.zip It is intended for use with twee/tweego.

Comments

  • The source you posted uses jQuery.animate() in <<widget actCont>> (from: libdynamicstory.tw) to force the page to scroll to the new content.  I must be missing something.


    Tangentially, I did notice another scrolling issue.  Your <<widget interact>> (from: libdynamicstory.tw) has a bad call to window.scrollTo().  Seen here:

    <<run scrollTo(0, window.scrollMaxY)>>\
    The window.scrollMaxY property only exists in Gecko-based browsers like Firefox (maybe Seamonkey as well).  In most (all?) other browsers that will evalute as:

    <<run scrollTo(0, undefined)>>\
    Which will be interpreted as:

    <<run scrollTo(0, 0)>>\
    Which will cause them to jump to the top of the scrollable page instead of the bottom.

    If you want to force a jump to the bottom of the page, then I'd suggest using something like this, which should work in all browsers:

    <<run window.scroll(0, document.body.scrollHeight)>>\
    n.b. window.scroll() and window.scrollTo() are essentially the same thing, however, window.scroll() is preferred.
  • TheMadExile wrote:

    The source you posted uses jQuery.animate() in &lt;&lt;widget actCont&gt;&gt; (from: libdynamicstory.tw) to force the page to scroll to the new content.  I must be missing something.

    Yeah, it's supposed to *animate* smoothly to the new content. That's the effect I'd like. But sometimes instead it *jumps* there immediately, which means there is then nothing to animate. If the scrolling is disabled, you still get the jumps. I wish I could figure out how to reproduce the issue consistently.

    [quote]Tangentially, I did notice another scrolling issue.  Your &lt;&lt;widget interact&gt;&gt; (from: libdynamicstory.tw) has a bad call to window.scrollTo().  Seen here:

    <<run scrollTo(0, window.scrollMaxY)>>\
    The window.scrollMaxY property only exists in Gecko-based browsers like Firefox (maybe Seamonkey as well).  In most (all?) other browsers that will evalute as:

    <<run scrollTo(0, undefined)>>\
    Which will be interpreted as:

    <<run scrollTo(0, 0)>>\
    Which will cause them to jump to the top of the scrollable page instead of the bottom.

    If you want to force a jump to the bottom of the page, then I'd suggest using something like this, which should work in all browsers:

    <<run window.scroll(0, document.body.scrollHeight)>>\
    n.b. window.scroll() and window.scrollTo() are essentially the same thing, however, window.scroll() is preferred.
    Oh! Thank you very much, that's good to know! The files in lib/ are things I want to eventually distribute, as drop-in files that give functionality. I can't rightly be giving out a library that only works on a portion of the browser userbase. :V
  • TiZ wrote:

    Yeah, it's supposed to *animate* smoothly to the new content. That's the effect I'd like. But sometimes instead it *jumps* there immediately, which means there is then nothing to animate. If the scrolling is disabled, you still get the jumps. I wish I could figure out how to reproduce the issue consistently.


    I didn't notice jumping in any of the browsers I tried it in when I disabled the animation, I had to manually scroll down every time.  What browser (and version) are you using (Firefox, I assume because of the other issue)?
  • Pale Moon 24.5, actually. A fork based on Firefox ESR. I hate Australis's uncustomizability so much that I left Firefox behind entirely. I still have Firefox 29 around. On Firefox 29, it still happens. I think I can reproduce the issue on both if you go to the conversation, click all the links (or enough to scroll it a lot), then refresh that page, and click any of the links. I can't reproduce it so far on Chromium, at least not in the conversation. However, on both Mozilla browsers and Chromium, if you have a fairly small window, like about 768px high, in the intro, the "Wake up already." link triggers it fairly often.

    I don't know if this makes any difference, but I am on Linux.
  • Also, because I'm curious, does the same thing happen if you change the jQuery animation from this:

    <<run $('html, body').animate({
    scrollTop: $($libds_contScroll).offset().top - 4
    }, 1500);>>\
    To this: (selects body directly and switches to the linear easing function)

    <<run $(document.body).animate({
    scrollTop: $($libds_contScroll).offset().top - 4
    }, 1500, "linear");>>\
    Also, what about if you replace it entirely with this: (this one will likely be pretty fast)

    <<run scrollWindowTo(document.querySelector($libds_contScroll));>>\

    [EDIT] Not that I'm expecting these to solve the "jumping with no animation in use" issue.  Just curious if they make it more bearable.
  • TiZ wrote:

    Pale Moon 24.5, actually.


    Close enough.  Being Geko-based was the idea really.


    TiZ wrote:

    I don't know if this makes any difference, but I am on Linux.


    Maybe.  I don't have a current VM to take a look with.
  • Okay, I just tested it on a Windows VM with Firefox on it, no extensions or anything. I am reproducing the behavior there, too. And the window is actually even smaller on there, so I discovered even more. During the conversation, I click all the links then refresh... then it is scrolled to the very bottom at the very start. In fact, when you click the first link (which spits out a lot of text), I notice that it scrolls *up* to reach the top of the newly added passage, starting from the bottom. What can we do to make sure the window is scrolled to the top at the start of a passage, refreshed, restarted, or otherwise?

    As for your animation suggestions; the scrollWindowTo is too fast. I like the one with the linear easing... but it doesn't work with $(document.body), it has to be $("html, body"). They don't do anything about the bearability of the page jump. In fact, they don't really affect it at all.
  • Ah.  It wasn't triggering for me because I hadn't been hitting refresh.  After doing that, I'm seeing the behavior you describe.  And, yes, that's just odd.  I have no idea what's causing that.  I know it's nothing in SugarCube (or nothing specific to SugarCube), or shouldn't be at any rate, but that's not really helpful in nailing down what is causing it or finding a solution.

    I thought that it might be the &lt;&lt;remove&gt;&gt; triggering some edge-case behavior in the browser (because you're removing content, thereby changing the scroll height), but testing disproved that idea.

    I'm honestly kind of at a loss here.


    ----
    Another catch from libdynamicstory.tw:

    I'd suggest you replace this:

    <<widget dispid>>\
    <<set $args[2] = $args[0]>>\
    <<id $args[2]>><<display $args[0]>><</id>>\
    <</widget>>
    With something like this:

    <<widget dispid>>\
    <<print '<div id="' + $args[0] + '"><<display "' + $args[0] + '">></div>'>>\
    <</widget>>
    Or this:

    <<widget dispid>>\
    <<print String.format('<div id="{0}"><<display "{0}">></div>', $args[0])>>\
    <</widget>>
    There's no reason to assign the first argument to another element there (I'm unsure why you'd want to do that in the first place), you can just reference it again.  &lt;&lt;id&gt;&gt; is deprecated, and has been for a very long time (where did you even dig that up).
  • TheMadExile wrote:
    I'm honestly kind of at a loss here.

    Well, crap. :( I have a couple of ideas to try, but they involve PassageDone, and I'd rather not put something in PassageDone becuase then the library wouldn't be drop-in anymore. If only PassageDone had something like postrender. The problem is, postrender happens before the content is actually put on the page, and PassageDone happens after it's put on the page, and one is a passage with a special name of which only one can exist, and the other is a javascript object that can have as many things hooked into it as one would want.

    [quote]Another catch from libdynamicstory.tw:

    I'd suggest you replace this: [...]

    There's no reason to assign the first argument to another element there (I'm unsure why you'd want to do that in the first place), you can just reference it again.
    Oh, that is some old code I forgot to get rid of. I used to be putting something in front of the passage name for the id, and most macros don't take well to trying to use $bluh + whatever as parameters because they don't do expressions. I see how the way you do it works; I'll do it like that from now on.

    [quote]&lt;&lt;id&gt;&gt; is deprecated, and has been for a very long time (where did you even dig that up).
    I don't remember; one of the many Twine help sites on the web. I was using it simply as a convenience for less typing, but if it's deprecated and going to go away, I guess I'll go with regular old span.
  • TiZ wrote:

    I have a couple of ideas to try, but they involve PassageDone, and I'd rather not put something in PassageDone becuase then the library wouldn't be drop-in anymore.


    Why don't you try your ideas out, at least.  If they don't work, then you haven't lost anything.  If they do work, then you can worry about the drop-in status of your library.


    TiZ wrote:

    If only PassageDone had something like postrender. The problem is, postrender happens before the content is actually put on the page, and PassageDone happens after it's put on the page, and one is a passage with a special name of which only one can exist, and the other is a javascript object that can have as many things hooked into it as one would want.


    I have thought about adding passageready and passagedone as tags before (which would allow as many such passages as you'd like).  Push come to shove, I suppose I could do that.

    Regardless, what seems to be the issue with the postrender task object?  The content buffer is passed in as one of its two parameters (first one, actually), so you can target and modify the rendered content regardless of it not having been added to the document yet.  For example:

    postrender["doAThing"] = function (content, taskName)
    {
    // via jQuery
    var snarf = $("#snarf", content); // cache the jQuery object returned by selecting "#snarf" on the content buffer
    snarf.;

    // plain old ECMAScript
    var snarf = content.querySelector("#snarf"); // cache the DOM object returned by selecting "#snarf" on the content buffer
    snarf.;
    };
  • TheMadExile wrote:
    Why don't you try your ideas out, at least.  If they don't work, then you haven't lost anything.  If they do work, then you can worry about the drop-in status of your library.

    Regardless, what seems to be the issue with the postrender task object?  The content buffer is passed in as one of its two parameters (first one, actually), so you can target and modify the rendered content regardless of it not having been added to the document yet.

    The problem with postrender is that it happens before the content is actually on the page, and my idea needed to take place after the content was on the page. My idea was basically just to scroll the window to the top after everything's been rendered, but it didn't work.

    There appears to be a bug report for the issue we're struggling with: https://bugzilla.mozilla.org/show_bug.cgi?id=706792 I'll keep looking into it and if I figure anything out, I'll report it here.

    [quote]I have thought about adding passageready and passagedone as tags before (which would allow as many such passages as you'd like).  Push come to shove, I suppose I could do that.
    That (including one for storyinit) would be awesome to have regardless, even just for better organizational capabilities.
Sign In or Register to comment.