while I'm at it

posted by tom / November 20, 2005 /

I hacked together some Javascript for Unfogged to help users (by which I mean me) keep track of their place in the site's fast-paced and sprawling comment threads. It'd be overkill for this site, but I may as well post the code. Perhaps someone else with a big Movable Type site will find it useful. It'd also be easy to adapt to any other HTML page that needs to remember users' scrolled positions from visit to visit. Code after the jump.

This code assumes the presence of the fixDate(), getCookie() and setCookie() functions, which are commonly found in the MT comment template. View the source to any comment page on this site if you need a copy of them.

Add this code to the javascript section of your MT comment template:

// ----------------------------
// junk added by tom
// ----------------------------

var _theTimer = null;
var _lastPosition = 0;

function T_setCommentOptionVisibility(p_blnMakeVisible){
	var temp = document.getElementById('CommentOptionsBlock');
	if(temp!=null)
		temp.style.display = (p_blnMakeVisible==true) ? 'block' : 'none';
}

function T_getCommentPreferences(){
	//retrieve the cookie
	var temp = getCookie('CommentPreferences');
	if(temp==''){
		temp = '0,0';
	}

	//split the string, convert to ints
	var temp2 = temp.split(',');
	for(var i=0;i<temp2.length;i++)
	{
		temp2[i] = parseInt(temp2[i]);
	}

	//set the form fields' values
	document.comments_form.commentMemoryPreference.selectedIndex = temp2[0];
	document.comments_form.commentJumpPreference.selectedIndex = temp2[1];

	return temp2;
}

function T_setCommentPreferences(){
    var now = new Date();
    fixDate(now);
    now.setTime(now.getTime() + 365 * 24 * 60 * 60 * 1000);
    var cookieValue = document.comments_form.commentMemoryPreference.selectedIndex + ',' +
        document.comments_form.commentJumpPreference.selectedIndex;
    setCookie('CommentPreferences', cookieValue, now, '', '', '');
    T_setCommentOptionVisibility(false);
    T_setupEventHandlers(parseInt(document.comments_form.commentMemoryPreference.selectedIndex));
}

function T_checkForScroll(){
	var intCurrentPos = T_getScrollPosition();
	if(intCurrentPos!=_lastPosition)
	{
		_lastPosition = intCurrentPos;
		T_recordScrolledPosition(intCurrentPos);
	}
}

function T_getScrollPosition()
{
	var scrollY = 0;
	if( document.documentElement && document.documentElement.scrollTop ) {
		scrollY = document.documentElement.scrollTop;
	}
	else if( document.body && document.body.scrollTop ) {
		scrollY = document.body.scrollTop;
	}
	else if( window.pageYOffset ) {
		scrollY = window.pageYOffset;
	}
	else if( window.scrollY ) {
		scrollY = window.scrollY;
	}
	return parseInt(scrollY);
}

function T_recordScrolledPosition(p_intPos){
    var now = new Date();
    fixDate(now);
    now.setTime(now.getTime() + 365 * 24 * 60 * 60 * 1000);
    setCookie('ScrolledPosition_<$MTEntryID$>', p_intPos, now, '', '', '');
}

function T_setScrolledPosition(p_intScrolledPos)
{
	window.scroll(0,p_intScrolledPos);
}

function T_retrieveScrolledPosition(){
	var intRecordedPosition = getCookie('ScrolledPosition_<$MTEntryID$>');
	if(intRecordedPosition=='')
		intRecordedPosition = -1;
	return parseInt(intRecordedPosition);
}

function T_setupEventHandlers(p_intValue){
	if(p_intValue==1){
		_theTimer = setInterval(function(){ T_checkForScroll(); },500);
	}else{
		clearInterval(_theTimer);
	}
}

function T_onLoad(){

	//load values from cookie
	document.getElementById("email").value = getCookie("mtcmtmail");
	document.getElementById("author").value = getCookie("mtcmtauth");
	document.getElementById("url").value = getCookie("mtcmthome");

	var settings = T_getCommentPreferences();

	if(settings[0]==1){
		T_setupEventHandlers(settings[0]);
	}

	//ignore all this stuff if an anchor is specified in the URL
	if(window.location.href.indexOf("#") == -1) {

		var blnScrollToBottom = false;

		//is vertical position memory on?
		if(settings[0]==1){

			//retrieve and scroll to the appropriate position
			var intScrollOffset = T_retrieveScrolledPosition();
			if(intScrollOffset>=0)
			{
				T_setScrolledPosition(intScrollOffset);
			}
			else
			{
				//or revert to top/bottom behavior if no pos. found
				blnScrollToBottom = true;
			}

		}else{

			//scroll to the bottom, if that behavior is set
			if(settings[1]==0){
				blnScrollToBottom = true;
			}
		}

		//scroll to bottom, if indicated
		if(blnScrollToBottom==true)
		{
			document.getElementById("author").focus();
			document.getElementById("author").select();
		}

	}

}

// ------------------------
// end of junk added by tom
// ------------------------

Add this next block of code to wherever in the HTML you'd like the "SET COMMENT OPTIONS" button to appear. I put it after the "FORGET PERSONAL INFORMATION" button.

<!-- ### additional junk added by tom ### -->

<input type="button" onclick="T_setCommentOptionVisibility(true)" value="SET COMMENT OPTIONS" />

<div id="CommentOptionsBlock" style="display:none; margin-top:10px">
<span style="width:150px;margin-right:10px">
Remember Vertical Pos:
<SELECT NAME="commentMemoryPreference">
<OPTION VALUE="no">no</OPTION>
<OPTION VALUE="yes">yes</OPTION>
</SELECT>
</span>
<span style="width:150px">
Default to:
<SELECT NAME="commentJumpPreference">
<OPTION VALUE="bottom">bottom</OPTION>
<OPTION VALUE="top">top</OPTION>
</SELECT>
</span>
&nbsp;
<INPUT TYPE="button" VALUE="OK" onclick="T_setCommentPreferences()"/>
</div>

<!-- ### end of of additional junk added by tom ### -->

Finally, change the onLoad attribute of the template's <BODY> tag to match the following:

<BODY onLoad="T_onLoad();">

That's it. Enjoy.

Comments

I think that, if memory of vertical position is set, you should set the event handlers even if an anchor is specified in the URL.

Posted by: ben wolfson on November 21, 2005 01:19 AM

Hmm. Yeah, you're probably right about that. I'll update the code here. I don't know whether ogged will want to go to the trouble of fixing the template, though.

Posted by: tom on November 21, 2005 09:31 AM

If you've got tweaked code, I want tweaked code.

Posted by: ogged on November 21, 2005 07:12 PM

the tweak is now present in the code. just copy the javascript T_onLoad() function over your template's existing one.

But there's no real shortcoming that's been fixed -- it's just a difference in behavior. Before, if a user was sent to a specific comment on a comment page, the page wouldn't try to remember its scroll position, even if the user had his preferences set to remember scroll position. I think you could make a case for this being desirable behavior (if you were holding your place in a thread, you wouldn't want it automatically moved by following a link to a comment you've already read).

But it's maybe a little less confusing if the page remembers its scroll position regardless of how the user arrived on the page. The modified code does that.

Posted by: tom on November 21, 2005 07:20 PM

Not only is it less confusing, it is obviously the right behavior.

Posted by: ben wolfson on November 21, 2005 08:36 PM

I disagree. Consider: high volume comment thread A is started, in which I'm keen to save my place. Shortly thereafter metathread B is started, which contains lots of self-referential links to A (mostly to make cock jokes). I'd like to be able to follow those links without losing my place in A's main discussion.

More generally, links to specific comments are usually used to get the reader to consider that particular comment -- not to get them to start participating in the conversation again as it existed at that particular comment.

Posted by: tom on November 21, 2005 09:44 PM

Use case: You tend to open threads from the "recent comments" sidebar. After an absence of some hours, or while a different thread is highly active, you open the thread from its own "comments" link, without anchors. As a result, under the ancien regime, you're taken either to the bottom or the top of the thread, and not to your last-read comment. Clearly this is the wrong behavior.

Posted by: ben wolfson on November 21, 2005 09:45 PM

I'd like to be able to follow those links without losing my place in A's main discussion.

Tabbed browsing, tommy. It's the wave of the future.

Anyway, if A is so active, when you follow the link from B to a specific A-comment, won't you want to scroll down and see what's new in A? My thesis: yes, you will. But then if you open A again, you'll be at comments you've already seen, not at "your place" at all.

Posted by: ben wolfson on November 21, 2005 09:48 PM

Okay, I'm convinced. I don't click on the "recent comments" links all that often myself, but you're right: users who do will want the placeholding functionality to work.

We could of course add another querystring parameter to the recent comments links, and use that to override the ignore-on-anchor behavior that I was arguing for... but that's probably more trouble than it's worth.

Posted by: tom on November 22, 2005 10:39 AM

Post A Comment

Name


Email Address


URL


Comments


Remember info?



Google Analytics