Howdy, Stranger!

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

[SugarCube] Hook to call a function after DOM rendering has taken place

I am using a custom scrollbar plugin (iScroll) that needs to be programmatically refreshed after the DOM updates in order to deal with dynamic content (such as displaying a new passage). The  Is there a callback or other hook I could use to call a function after the display code has updated, or do I need to override the definition for History.prototype.display?

(PassageDone and postrender both occur too early to be used for this purpose.)

Comments

  • Have you actually tried doing it from PassageDonePassageDone is called after the DOM has been updated, as opposed to postrender tasks which are called before.

    From their documentation it seems like doing something like this:

    <<script>>
    myScroll.refresh();
    <</script>>
    Or, if that doesn't work, this:

    <<script>>
    setTimeout(function () {
    myScroll.refresh();
    }, 1);
    <</script>>
    Should work just fine from PassageDone.  As noted, you may to lengthen the timeout duration, but I'd try without doing that first.
  • Good call. I did try it in PassageDone and it failed, but that was outside of a timeout. Inside of a timeout callback, it works nicely.

    ...I did try it in a timeout in postrender, but that failed too, and thanks to your reply I now know that this is because postrender is called before PassageDone.

    Thanks for the help!
  • A follow-up to this: Is there a built-in way to determine, from code executed in PassageDone, whether we are loading the first passage in a session? I need to set the refresh the custom scrollbar on a pretty long timeout on the first passage, presumably due to loading processes interfering with browser update somehow (I'm not sure why this is exactly, but in the first-rendered passage of a session the container element appears not to reach its final height until one to two seconds after the PassageDone code is executed). Anyway, having it on a 2000ms timeout interferes with display on subsequent passages, where the long delay isn't needed and essentially no delay is optimal.

    Just to recap, here's what I'm doing now:
    :: PassageDone
    <<script>>
    setTimeout(function () {
    myScroll.refresh();
    }, 2000);
    <</script>>
    Here's what I hope to be able to do:
    :: PassageDone
    <<script>>
    var timeout = firstPassageOfSession ? 2000 : 1;
    setTimeout(function () {
    myScroll.refresh();
    }, timeout);
    <</script>>
  • I'm not entirely sure how you're handling sessions, however, you may be able to use turns() or, failing that, set a flag in the session store.

    Via turns():

    :: PassageDone
    <<script>>
    setTimeout(function () {
    myScroll.refresh();
    }, (turns() === 1) ? 2000 : 1);
    <</script>>
    Via a session flag:

    :: PassageDone
    <<script>>
    var timeout = 1;
    if (!session.hasItem("et.firstPassageDone")) {
    timeout = 2000;
    session.setItem("et.firstPassageDone", true);
    }
    setTimeout(function () {
    myScroll.refresh();
    }, timeout);
    <</script>>
  • Thanks! turns() won't work for me, since I am using both an autosave and the new autoload. I didn't know that there was a session store, and that sounds like it would likely do just what I asked for.

    But I actually decided to tackle this differently. It seems to work so far, though I haven't tested it on every device yet. I just check for the content div to be resized using a timer interval, and when it is, do the refresh:

    <<script>>
    var refresh = setInterval(function() {
    if (parseInt($(".content").css("height")) > 0) {
    customScroll.refresh();
    clearInterval(refresh);
    }
    }, 200);
    <</script>>
Sign In or Register to comment.