24 November 2007

greasemonkey pagination

when the front page gets really large, my long-suffering Titanium Powerbook develops significant responsiveness issues when viewing Anchorbutt in FireFox 2.

Here's a greasemonkey script I wrote this morning that adds a (particularly unbeautiful) sort of poor-man's DOM paginator. with this script in place, initial load and general mousing around is a lot faster:

// ==UserScript==
// @name Anchorbutt Pager
// @namespace anchorbutt
// @description Adds DHTML pagination to the entries on anchorbutt
// @include http://anchorbutt.blogspot.com/*
// ==/UserScript==

/**
* Constructor function, which destructively modifies the provided DOM element
* 'container'. 'container' is subdivided into pages, each containing 'pageSize'
* blog entries. The currently displayed page can be changed using a list of
* anchor elements added to the top of 'container'.
*/
function Paginator(container, pageSize) {

//'selector' contains links to select the currently displayed page.
var selector = document.createElement('div');
selector.setAttribute('class', 'page-selector');
selector.setAttribute('style', 'margin-bottom: 1em;');

selector.appendChild(document.createTextNode('Page '));
container.appendChild(selector);

var pageCount = 0;
var currentPage = null;

/** private function to create a new empty page in the paginator */
function addPage() {
++pageCount;

//the page container
var page = document.createElement('div');
page.setAttribute('class', 'page-container');

//add a title for the page to keep users oriented
var title = document.createElement('h2');
title.appendChild(document.createTextNode('Page ' + pageCount));
page.appendChild(title);

//create a new anchor to select this page.
var toggle = document.createElement('a');
toggle.setAttribute('style',
'margin-right: 1ex; cursor: pointer;');
toggle.appendChild(document.createTextNode(pageCount));

//when clicked, the anchor removes the previous page from the DOM,
//replacing it with this one.
toggle.addEventListener('click',
function() {
if (currentPage != page) {
if (currentPage) {
container.removeChild(currentPage);
}
currentPage = page;
container.appendChild(page);
}
return false;
},
false
);
selector.appendChild(toggle);

//if this is the first page, display it immediately.
if (!currentPage) {
currentPage = page;
container.appendChild(page);
}

return page;
}

//main constructor logic. we simply iterate container's children,
//partitioning them out into page elements we build using addPage()
//calls.
var entryCount = 0;
var page = addPage();

for (var child = container.firstChild;
child && child.className != 'page-selector'; ) {

//move element out of the original container and into
//the current page accumulator.
var next = child.nextSibling;
page.appendChild(child);


if (child.className && child.className.match(/post/)) {
if (++entryCount == pageSize) {
entryCount = 0;
//rollover to the next page.
if (next)
page = addPage();
}
}
child = next;
}
}

/**
* recursively search for the blog entry container in the DOM, starting at
* parent node 'root'.
*/
function findPostContainer(root) {

//base case: we take the parent for 'date-header' elements as
//our root element.
for (var child = root.firstChild; child; child = child.nextSibling) {
if (child.className && child.className.match(/date-header/))
return root;
}
//recursive case: descend on each child.
for (var child = root.firstChild; child; child = child.nextSibling) {
var ret = findPostContainer(child);
if (ret)
return ret;
}
return null;
}

//begin MAIN procedure.

//drive down to 'main', which is the center area of the main layout.
var main = document.getElementById('main');
if (main) {
//drill down further by finding the first date header, and
//selecting its parent
main = findPostContainer(main);
}

if (main) {
//we've found the main entry container. apply pagination to it.
new Paginator(main, 10);
} else {
//the DOM structure does not match our expectations. complain.
alert('GreaseMonkey / Anchorbutt script unable to find top-level ' +
'post container. ' +
'Maybe some clever person has changed the layout?');
}

5 comments:

Drew said...

Although I admire your impulse to solve problems with code, maybe it would be better if we throttled back the maximum number of front-page posts to a smaller size?

We're currently at 64 posts. This is because we thought it would be good if you never had to read past the first page to catch up on all the posts since your last visit. We figured that people would visit at least once a week, and for the first five (full) months of anchorbutt, we were doing several posts per day (80+ posts/month).

So we went fairly high on the number of posts retained on the front page, although 64 may be a bit overboard.

Now that we've settled down to about one post every other day, should we consider keeping only 16 posts on the front page? That'll cover a month's worth of posts (for most months in 2007), which ought to be plenty. (We could also keep 30 days worth of posts on the front page.)

Or, now that there's a greasemonkey solution, should we make the number of posts on the front page even higher? 999 is the limit imposed by blogger.

Comments?

tormp said...

it had occurred to me to try and solve the problem in the template and/or settings. on the other hand, i might be the only one having performance problems with the large render (or at least in the minority), so i thought i'd just throw the script out there for shits.

also i had recently suggested that frank turn all the images upside down (wasn't that it?) with greasemonkey.

anyway, i think throttling down to 16 would be great, but i didn't want to alienate anybody. i'd rather stick to more direct methods of alienating people.

either way, i'm prepared. when google forces the front page to 999 and demands subscription money to turn it back down, you can all come read on my computer for almost free.

dcass said...

BALLS!

tormp said...

yes doug, balls. balls indeed.

ChiliCon said...

The images already are upside down! Zing!