April 19, 2012

Swapping to Reverse Post Order on Blogger


Sometimes an oldest-to-newest order of blog posts would be better than Blogger's standard newest-to-oldest arrangement. A blog about a project is an example. The posts would proceed from oldest to newest so a visitor to the blog could start reading at the project introduction and proceed from there. Unfortunately, Blogger doesn't provide this as an option.

There are a number of existing approaches to this problem but, for various reasons, none of those exactly fit my needs. So I decided to roll my own.

David Merriman's script served as the starting point in locating post container nodes in Blogger's template. From there, the idea was to create a script that locates the blog's post container and then searches concurrently for posts from both the top and bottom of that container. When a post is reached at each end, those posts would be swapped. The concurrent search would then continue on toward the center of the container. The search would end once the center is reached, at which point the contained posts would have been reversed by the preceding swaps. The process is then repeated for each day of posts to reorder multiple posts within days.

The resulting drop-in hack is shown below. To use it, copy and paste the entire script into your Blogger template just before the </body> tag and then save the template. View your blog, reloading if needed, and your posts should be displayed in reverse order. Take a look at http://diyreader.blogspot.com to see it in use.

<!-- Start Post Reversal Code -->
<script type='text/javascript'>
//<![CDATA[
  // -----------------------------------------------------------------------------------------
  // Name   : PRS - Post Reversal Script for Blogger - Version 1.0
  // Author : David Yockey
  // URL    : http://techsquirrels.blogspot.com/2012/04/swapping-to-reverse-post-order-on.html
  // -----------------------------------------------------------------------------------------

  // Temp variable used to shorten classname references
  var cn;

  // This function is called as needed in the main program below.
  function ReversePosts(BlogPostContainer,PostClass) {

    // Arguments:
    //    BlogPostContainer -- The node containing the posts to be reversed.
    //    PostClass -- The className of each of the posts in the container to be reversed.
    //                 (may be a single name from among names in the class attribute of the posts)

    // Flag for checking whether any posts are found
    var found=false;

    var BlogPosts = BlogPostContainer.childNodes;  // May include text-nodes containing
                                                   // whitespace in addition to post-nodes

    // Set index variables to top and bottom of BlogPosts list
    var i=0;
    var j=BlogPosts.length-1;

    for( ; ; ) {     // Start Endless Loop

      // Find next Post from the top
      while( (i < j) && (!(cn=BlogPosts[i].className) || !(cn.match(PostClass))) )
        ++i;

      // Find next Post from the bottom
      while( (i < j) && (!(cn=BlogPosts[j].className) || !(found=cn.match(PostClass))) ) // (see Footnote 1)
        --j;

      if( found && i < j ) {
        // Swap Posts (see Footnote 2)
        var tempi = BlogPosts[i].cloneNode(true);           // Store a copy of Post i in tempi
        var tempj = BlogPosts[j].cloneNode(true);           // Store a copy of Post j in tempj
        BlogPostContainer.replaceChild(tempi,BlogPosts[j]); // Replace Post j with Post i in tempi
        BlogPostContainer.replaceChild(tempj,BlogPosts[i]); // Replace Post i with Post j in tempj
      } else {
        // Done
        break;        // Break out of Endless Loop
      }

      ++i; --j;
    }
  }
  // Footnote 1:
  //   If a post is found from one end, then a post must necessarily be found from the other.
  //   So, recording and later checking for a post from one end is sufficient to ensure that
  //   one was found from both.
  //
  // Footnote 2:
  //   At least in Firefox 11.0 on Fedora Linux, replacing a child directly with another child
  //   causes some text-nodes containing whitespace to be deleted. That node deletion messes up
  //   the positions of the posts in the BlogPosts list. This is avoided by cloning both posts
  //   rather than just one and replacing both posts from the cloned copies.


  // *** MAIN POST REVERSAL PROGRAM ***

  // Magic Words
  var BlogWidget             = 'Blog1';
  var BlogPostContainerClass = 'blog-posts';
  var BlogPostClass          = 'date-outer';
  var DatePostContainerClass = 'date-posts';
  var DatePostClass          = 'post-outer';

  var Blog1 = document.getElementById(BlogWidget);

  // Find the node containing the blog posts
  var BlogPostContainer;
  var x=0;
  do {
    BlogPostContainer = Blog1.childNodes[x++];
  } while ( !(cn=BlogPostContainer.className) || !(cn.match(BlogPostContainerClass)) );

  // Reverse different day posts
  ReversePosts(BlogPostContainer,BlogPostClass);

  // Reverse same day posts - Loop thru contents of BlogPostContainer to find each day's posts
  var BlogPosts = BlogPostContainer.childNodes;
  for ( i = 0; i < BlogPosts.length; ++i ) {

    // Check for an actual post-node rather than a text-node or such
    if ( (cn=BlogPosts[i].className) && cn.match(BlogPostClass) ) {
      var DatePostContainer;
      x=0;

      // Find the node containing the posts to be reversed for the current day being processed
      do {
        DatePostContainer = BlogPosts[i].childNodes[x++];
      } while ( !(cn=DatePostContainer.className) || !(cn.match(DatePostContainerClass)) );

      ReversePosts(DatePostContainer,DatePostClass);
    }
  }
//]]>
</script>
<!-- End Post Reversal Code -->
Code highlighting (if your browser displays it...) powered by google-code-prettify.

The script doesn't include an option to select whether or not to reverse the order. If you need this option, you might want to try MS-potilas's script, although I haven't tried it myself.

My thanks go to David Merriman and MS-potilas for their prior work on this problem and the guidance it provided.
09/25/2012 -- You may also be interested in: Hiding Blog Post Manipulation

April 2, 2012

Sideblog: DIY Reader

A place for details on modding an old laptop into a stationary tablet-like reader. Post questions and comments about aspects of interest to you. http://diyreader.blogspot.com

March 18, 2012

Controlled Rotation when PDF File is Opened

There are online services that provide books viewed through a browser with a PDF viewer plugin. Wholesale copying is hindered by serving each page as a separate PDF file, where the plugin closes and reopens each time a new page is viewed. While a bit of a kludge, it works fairly well, except when a reader wants to rotate all of the pages and their device doesn't support display rotation.

I wanted to view all of the pages of such a book rotated 90° on a laptop display held sideways, thereby to reduce scrolling. Unfortunately, the particular laptop was an older model that didn't support display rotation.* Rotating the PDF in the plugin worked for a page, but the rotation didn't hold between pages since the plugin was loaded with each turn of the page. Consequently, annoying keypresses or mouse clicks were needed to rotate each new page.

Searching for a PDF viewer with any option to set the initial rotation when opening a file was fruitless. But I did find an open source PDF viewer called Xpdf that had just about every startup option you'd want except rotation. Finding nothing better to serve the purpose, I decided to add the option myself.

Having ran across others looking in vain for the same functionality during my search, I decided to put up a patch in hopes of helping at least somebody out there. My Rotation Control Patch to add rotation options to Xpdf is freely available at http://sourceforge.net/projects/xpdf-rcpatch/, and updated manpages are also available in the files section. The latest version of the source code for Xpdf itself is freely available from http://www.foolabs.com/xpdf/. Note that Xpdf can be compiled to run on a number of other operating systems than Linux, including Windows.

There was one significant problem I ran into when building Xpdf. A note in the INSTALL file accompanying the Xpdf source reads:
(The include path is the directory which contains the freetype2 directory, i.e., do NOT include "freetype2" in the --with-freetype2-includes path. For example, with the default installation, the library path is /usr/local/lib and the include path is /usr/local/include/freetype2.)
This doesn't seem to make sense. After stating, with EMPHASIS, that freetype2 shouldn't be included in the include path, it goes on to show an example where the include path includes freetype2. To complicate matters, my distro didn't install freetype2 in /usr/local, a fact I didn't realize until after a bit of head banging. In the end, the configure line that worked for me was:
./configure --with-freetype2-library=/usr/lib --with-freetype2-includes=/usr/include/freetype2 --with-Xm-library=/usr/lib --with-Xm-includes=/usr/include/Xm
Your mileage may vary.

* It may instead have been the display driver I had to use, since no Linux driver was available from the manufacturer, but I'm not reloading Win98 on it to find out. :)

March 13, 2012

Suppress diff Missing File Messages

To suppress the missing file messages diff generates when creating a patch for multiple files, just filter them out with grep.  For example:
diff -rc olddir newdir | grep -v -e "^Only in" > diffs.patch

March 11, 2012

Solved: XP Repair Install Hanging at Installing Network

A Repair Install is required to get a hard drive with XP to boot after being moved to a new computer. However, it's apparently not uncommon for the Repair Install to hang somewhere in the process.

In my case of moving a hard drive with a retail version of XP installed from one computer to another, the Repair Install hung upon reaching "Installing Network" at about 31 minutes left in the install. To get around this problem, I did the following:
  • Hit Shift + F10 to open a command prompt.
  • Ran taskmgr.exe to bring up the Task Manager.
  • Examined the Processes and found spoolsv.exe, the "Print Spooler" service, to be consuming practically all of the CPU time.
  • Returned to the command prompt and ran services.msc to get to the Services window.
  • Clicked the Standard tab.
  • Located Print Spooler and right-clicked on it.
  • Selected Stop in the popup menu.
...and the Repair Install resumed immediately after the Print Spooler service was stopped.

The Repair Install hung once again later in the process around 9 minutes left. Task Manager showed that the spoolsv.exe was again hogging all of the CPU time. Repeating the Print Spooler stop again got the Repair Install to immediately resume, and it then continued to completion uninterrupted.

This solution was the result of a lot of searching and followed many unsuccessful attempts involving hardware changes, BIOS configuration changes, and software removal. Kudos to the people who posted the content on the following pages, from which my solution was pieced together:

Changing a Motherboard or Moving a Hard Drive with XP Installed

xp repair reinstall hangs at Installing Network (Microsoft XP)

What is the Windows spoolsv.exe file / process?

Run Command Shortcuts for Administrative Tools