while I'm at it
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> <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.
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.
If you've got tweaked code, I want tweaked code.
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.
Not only is it less confusing, it is obviously the right behavior.
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.
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.
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.
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.
Post A Comment