Rory's Blog
Home
Blog
Projects
Facebook
Google+
Github
RSS

Every Post Gets a Link

04/10/15

So, when I first started this blog, I was just adding on top of an index.html file. So, a lot of my first posts are only contained in there, not their own file.

I figure that fixing this with cheerio might actually be pretty easy. First, I need to find all the posts that don't have a link.

Let's start from scratch. It's a good learning experience. First, let's count all my blogposts again.

/*jslint node: true */
(function () {
    "use strict";
    var fs = require('fs'),
        $ = require('cheerio');

    fs.readFile('public/blog/index.html', 'utf-8', function (err, data) {
        if (err) {
            console.log(err);
        }
        console.log($('.blogpost', data).length);
    });
}());

Output is:

$ node scripts/createLinks.js
247

From here, let's count all posts that don't have an tile link.

/*jslint node: true */
(function () {
    "use strict";
    var fs = require('fs'),
        $ = require('cheerio');

    fs.readFile('public/blog/index.html', 'utf-8', function (err, data) {
        var noLinks;
        if (err) {
            console.log(err);
        }
        noLinks = $('.blogpost', data).not(function () {
            if ($(this).find('h1 a').html()) {
                return true;
            }
            return false;
        });
        console.log(noLinks.length);
    });
}());

This gives me an output of:

$ node scripts/createLinks.js
21

I'm actually surprised it took more than 21 posts to start making individual links (I've manually made some links to some of the posts before when I started linking things).

From here, I need to create some files where I can save the html to make each post its own page. Let's make it in a test directory while I'm figuring stuff out (don't want to pollute the blog area with poorly constructed filenames or anything).

noLinks.each(function () {
    var blogpost = $(this),
        titleToFilename,
        title,
        filename;

    titleToFilename = function (title) {
        return 'test/'
            + title
            .replace(/\ /g, '_')
            .replace(/[()?:\.]/g, '')
            .toLowerCase()
            + '.html';
    };
    title = blogpost.children('h1').text().trim();
    console.log(title);
    filename = titleToFilename(title);
    console.log(filename);
    console.log();

    fs.writeFile(filename, '', 'utf-8', function (err) {
        if (err) {
            return console.log(err);
        }
    });
});

This code outputs:

$ node scripts/createLinks.js
Goal for Today: RSS Feed
test/goal_for_today_rss_feed.html

Things Looking Much Less Horrible
test/things_looking_much_less_horrible.html

Project of Focus: Making This Blog Look Better
test/project_of_focus_making_this_blog_look_better.html

What is Consciousness?
test/what_is_consciousness.html

Sick
test/sick.html

The Free Will Debate
test/the_free_will_debate.html

First Try At a Never-Ending Github Streak
test/first_try_at_a_never-ending_github_streak.html

Things Looking a Bit Better Around Here
test/things_looking_a_bit_better_around_here.html

Some More Specific Goals for This Blog
test/some_more_specific_goals_for_this_blog.html

Let's Try Making Things Prettier
test/let's_try_making_things_prettier.html

What is Your Job?
test/what_is_your_job.html

Parallel Growth
test/parallel_growth.html

Random Fiction: Which is the Dream?
test/random_fiction_which_is_the_dream.html

Site Change: Adding Dates (Manually)
test/site_change_adding_dates_manually.html

Sick Day
test/sick_day.html

The Walking Dead
test/the_walking_dead.html

Disruption
test/disruption.html

Everyday
test/everyday.html

Exercise PID Control
test/exercise_pid_control.html

Eventually....
test/eventually.html

The First Stone
test/the_first_stone.html

And if I check the test directory:

$ ls test/
disruption.html
eventually.html
everyday.html
exercise_pid_control.html
first_try_at_a_never-ending_github_streak.html
goal_for_today_rss_feed.html
let's_try_making_things_prettier.html
parallel_growth.html
project_of_focus_making_this_blog_look_better.html
random_fiction_which_is_the_dream.html
sick_day.html
sick.html
site_change_adding_dates_manually.html
some_more_specific_goals_for_this_blog.html
the_first_stone.html
the_free_will_debate.html
the_walking_dead.html
things_looking_a_bit_better_around_here.html
things_looking_much_less_horrible.html
what_is_consciousness.html
what_is_your_job.html

Yay! We'd be done now if those files weren't empty and if they were in the blog area and the index.html file html was updated to link to those files..

Let's make it so those files aren't empty and are in the blog area and that index.html links to those files.

Non-empty:

noLinks.each(function () {
    var blogpost = $(this),
        titleToFilename,
        title,
        filename,
        blogData;

    titleToFilename = function (title) {
        return 'test/'
            + title
            .replace(/\ /g, '_')
            .replace(/[()?:\.]/g, '')
            .toLowerCase()
            + '.html';
    };
    title = blogpost.children('h1').text().trim();
    filename = titleToFilename(title);

    blogData = '<html>\n'
        + '  <head>\n'
        + '    <title>\n'
        + '      ' + title + '\n'
        + '    </title>\n'
        + '    <link rel="stylesheet" href="/style.css">\n'
        + '    <link rel="stylesheet" href="style.css">\n'
        + '  </head>\n'
        + '  <body>\n'
        + '    <div id="browse_bar">'
        + browseBar.html()
        + '</div>\n'
        + '    <div id="content">\n'
        + '      <div class="blogpost">'
        + blogpost.html()
        + '</div>\n'
        + '    </div>\n'
        + '  </body>\n';

    fs.writeFile(filename, blogData, 'utf-8', function (err) {
        if (err) {
            return console.log(err);
        }
    });
});

The files come out reading mostly like I wrote it by hand (except for the characters that are escaped for me that I didn't realize needed to be escaped). I had no idea that &apos; was a thing.

Updating the index file.... Actually, I realize while trying to do this that I need to restructure my code a bit to make it ridiculously easy to do this. And from there it's just a little change to make it so it's all saved to my blog area proper.

The final code:

/*jslint node: true */
(function () {
    "use strict";
    var fs = require('fs'),
        cheerio = require('cheerio'),
        indexPath = 'public/blog/index.html';

    fs.readFile(indexPath, 'utf-8', function (err, data) {
        var noLinks,
            browseBar,
            title,
            filename,
            $ = cheerio.load(data);

        if (err) {
            console.log(err);
        }

        title = function (blogpost) {
            return blogpost.children('h1').text().trim();
        };

        filename = function (blogpost) {
            return title(blogpost)
                .replace(/\ /g, '_')
                .replace(/[()?:\.]/g, '')
                .toLowerCase()
                + '.html';
        };

        browseBar = $('#browse_bar');

        noLinks = $('.blogpost').not(function () {
            var blogpost = $(this);
            if (blogpost.find('h1 a').html()) {
                return true;
            }
            return false;
        });

        noLinks.each(function () {
            var blogpost = $(this),
                blogData,
                path = require('path'),
                blogpath;

            blogData = '<html>\n'
                + '  <head>\n'
                + '    <title>\n'
                + '      ' + title + '\n'
                + '    </title>\n'
                + '    <link rel="stylesheet" href="/style.css">\n'
                + '    <link rel="stylesheet" href="style.css">\n'
                + '  </head>\n'
                + '  <body>\n'
                + '    <div id="browse_bar">'
                + browseBar.html()
                + '</div>\n'
                + '    <div id="content">\n'
                + '      <div class="blogpost">'
                + blogpost.html()
                + '</div>\n'
                + '    </div>\n'
                + '  </body>\n';

            blogpost.children('h1').html(
                '\n          <a href="' + filename(blogpost) + '">\n'
                    + '            ' + title(blogpost) + '</a>\n'
                    + '        '
            );

            blogpath = path.join('public/blog', filename(blogpost));
            fs.writeFile(blogpath, blogData, 'utf-8', function (e) {
                if (e) {
                    return console.log(err);
                }
            });

        });

        fs.writeFile(indexPath, $.html(), 'utf-8', function (err) {
            if (err) {
                return console.log(err);
            }
        });
    });
}());

So, after I've constructed the single blogpost html into blogData, I alter the html loaded into $ such that there's a link pointing to the file I'm about to create as the title of the post within the loaded index html. After all blogpost files are created, the index.html path is rewritten with the modified html. This rewrite also has the additional niceties of correcting any incorrect html I wrote the best cheerio knows how.

And just like that I've managed to make a script that makes working links to all the blogposts I had originally written within my blog's index.html.

Awesome.

Next time: save the order of my blog and diary posts into some sort of json file? From there, I can construct index.html from the files I have and said json file. Yeah, I think that sounds like a plan.

Also, I think this diary post is good enough to be a proper blogpost.