+1 vote
by (250 points)
edited by

I am trying to alter this maintain scroll position code:

https://twinery.org/forum/discussion/comment/18148/#Comment_18148

This code remembers the vertical scroll position for the passage, but only when you navigate away & return to it. If you link the passage to itself, the scroll position goes back to the top. What I want to happen is, when you link the passage to itself, it keeps your vertical scroll position instead of returning to the top of the page. However, my knowledge of Javascript is basically 0 so I have no idea how to alter the code to make this happen. Any help?

Here's the relevant code; passage name is ScrollTest (you'll see <br> a lot, as I'm using it to test if my vertical scroll position is being remembered):

<<script>>
if (window.localStorage) {
    var ls = window.localStorage;
    window.setTimeout(function() {
        var val = Number(ls['zcwScrollPosition']);
        $(document).scrollTop(val);
    }, 50);
    $(document).scroll(function(e) {
        ls['zcwScrollPosition'] = $(document).scrollTop();
    });
    $('tw-link, tw-icon.undo, tw-icon.redo').click(function() {
        $(document).off('scroll');
    });
}
<</script>>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
Test line.


<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<<link "Testing scroll thing" ScrollTest>><</link>>

 

2 Answers

0 votes
by (154k points)

Please don't put Twine or Story Format version related information within the Question Title, it unnecessarily pads the title and serves no useful purpose. That information should be specified using the Question Tags, like you done.

WARNING: The example you included (and linked to) was written for the Harlowe story format and makes a number of assumptions:

a. That you want to track the scroll position of ONLY ONE specific Passage within your story, meaning that that code (as is) can not be added to a second Passage.

b. That the permanently tracked position information will effect the specific Passage every time it is viewed, even if that viewing occurs after a "Restart" or after the Reader returns to the Story (assuming that they are using the same web-browser instance and that its Local Storage cache hasn't been flushed.)

The following example should achieve what you want, assuming that your requirements include both of the above. It also assumes that your project contains a passage named Other that links back to the the current passage.

<div style="min-height: 80em;"></div>
Test line.

<div style="min-height: 15em;"></div>
[[Visit the current passage again|passage()]]
[[Go to Other passage|Other]]

<<script>>
/* Only track the current scroll position if LocalStorage is enabled. */
if (window.localStorage) {

	/* Execute the following after the current Passage has been displayed. */
	$(document).one(':passagedisplay', function () {

		var ls      = window.localStorage;
		var saved   = Number(ls['zcwScrollPosition']);
		var current = $(document).scrollTop();

		/*
			Monitor the 'Scroll' event and update the saved value whenever the User
			scrolls the current page.
		*/
		$(document).on('scroll.track-scroll-position', function () {
			ls['zcwScrollPosition'] = $(document).scrollTop();
		});

		/*
			Attach handler to remove the 'Scroll' event monitoring whenever the User
			does something that causes a Passage Transition to occur.
		*/
		$(document).one(':passageinit', function () {
			$(document).off('scroll.track-scroll-position');
		});

		/* Scroll page to saved position if required. */
		if (saved != current) {
			$(document).scrollTop(saved);
		}
	});
}
<</script>>

 

by (250 points)
Ah, thank you; I saw some other posts doing that so I put it in mine. I edited the title to take that out now!

As for your solution, I tried it and it doesn't seem to be working; it neither brings me to my current vertical scroll position nor remembers my vertical scroll position when I close & reopen the passage (which is what the original code that I referred to does). I'm not sure why it's not working; like I said, I know virtually nothing about Javascript. Is it working on your end?

Also, both the assumptions you mentioned, a & b, are true for me!
0 votes
by (154k points)

NOTE: For Harlowe story format users.

The original example included (and linked to) by @Eliana contains a potential timing issue, which can cause it to not behave correctly if the Undo or Redo links are used to revisit the associate passage.

The following example tries to overcome that timing issue by delaying the attaching of both the 'Scroll' event handler and and Link 'Click' event handlers. It assumes that your project contains a passage named Other that links back to the the current passage.

<div style="display: inline-block; min-height: 40em;"></div>
Test line.

<div style="display: inline-block; min-height: 15em;"></div>
(link-goto: "Visit the current passage again", (passage:)'s name)
[[Go to Other passage->Other]]

<script>
/* Only track the current scroll position if LocalStorage is enabled. */
if (window.localStorage) {
    var ls = window.localStorage;

	/*
		Execute the following after the current Passage has been displayed and after
		Harlowe has reset the document scrollTop position to 0.
	*/
    window.setTimeout(function () {
        var saved   = Number(ls['zcwScrollPosition']);
		var current = $(document).scrollTop();

		/*
			Monitor the 'Scroll' event and update the saved value whenever the User
			scrolls the current page.
		*/
		$(document).on('scroll.track-scroll-position', function () {
        	ls['zcwScrollPosition'] = $(document).scrollTop();
    	});

		/*
			Attach handler to remove the 'Scroll' event monitoring whenever the User
			does something that	causes a Passage Transition to occur.
		*/
		$('tw-link, tw-icon.undo, tw-icon.redo')
			.one('click.track-scroll-position', function () {
				$(document).off('scroll.track-scroll-position');
			});

		/* Scroll page to saved position if required. */
		if (saved != current) {
	        $(document).scrollTop(saved);
		}
    }, 50);
}
</script>

 

...