I saw an interesting post on reddit yesterday showing how user "iFargle" had customized the start page of Google Chrome to display his most commonly-used links. I had to have it! After spending some time customizing, here is what I came up with:

New tab page

"iFargle" was kind enough to share the HTML he used to construct this table of links, so I was able to get started pretty quickly. The thing is, though, I like to keep a bunch of tabs open so customizing Chrome's start page wasn't that ideal. It would be much more useful for me to customize my "New tab" page, however Chrome doesn't expose this as a setting. You can, however, customize the new tab page with a chrome extension.

As I started putting my chrome extension together I thought it would be really neat to add some "quick search" boxes to the table. I commonly find myself entering URLs of the same pattern -- for example jumping directly to a sub-reddit or going to an open ticket on my company's ticket tracker. So I decided to add some input widgets where I could just enter, for example, the ticket number or the zipcode for the weather forecast I was interested in.

Of course maintaining a hard-coded HTML table of what are, essentially, bookmarks is going to be a pain in the ass. I already had been annoyed by having to go in and manually edit the HTML table when I wanted to change up the links. Then it hit me: I could use chrome's bookmarks facilities to store the bookmarks and just read them into a nice table format! Chrome's bookmarks are automatically synced between devices and tied to my google account, which is also a big plus.

This should hopefully illustrate how it works:

Bookmarks folder

If you're interested in creating something similar to this for your browser, I've included the code below (update, I've moved the code to a GitHub repo):

manifest.json

This file is used to store metadata for the chrome extension.

{
  "name": "Custom new tab page",
    "description": "Display bookmarks on the new tab page",
    "version": "0.1",
    "incognito": "split",
    "chrome_url_overrides": {
      "newtab": "start-page.html"
    },
    "permissions": [
      "bookmarks"
    ],
    "manifest_version": 2
}

start-page.html

This page contains the actual HTML used to display the bookmarks table. Thanks for the awesome design, iFargle:

<html>
<head>
<title>start</title>
<link rel="shortcut icon" type="image/gif" href="<!--INSERT IMG URL HERE>-->" />
<link href='http://fonts.googleapis.com/css?family=Roboto:400,100,300' rel='stylesheet' type='text/css'>
<style type="text/css">
body {
  background : #ffffff;
  background : radial-gradient(ellipse at center, #ffffff 0%, #eee 100%);
  background : -moz-radial-gradient(#eee, #fff);
}
.keepcentered {
  width : 640px;
  height : 300px;
  margin-left : auto;
  margin-right : auto;
  margin-top: 200px;
  font-weight : 100;
}
body {
  font-family: 'Roboto', sans-serif;
  font-style : normal;
  color : #d64937; // Change this to change the color of the colored font on the page.
  margin : 5px;
}
td, tr {
  width: 20%;
  text-align: center;
}
table input {
  width: 100%;
  border: 1px solid #d64937;
  padding: 10px;
}
a {
  font-weight: 100;
  color : #999;
}
a:hover{
  color: #eee;
}
a:link {
  text-decoration : none;
  text-shadow: 0px 0px 0px #000;
}
input#search {
  width: 100%;
  color:#d64937;
  border: 1px solid #d64937;
  padding: 10px;
  font-size: 18px;
}
div#time { font-size: 72px; }
</style>
</head>

<body>
<div class="keepcentered">
  <center><div id="time"></div></center>
  <p>
    <table id="bookmarks" width="100%" border="0px">
    </table>
    <br>
    <input id="search" placeholder="search" type="text" />
    <br>
    <table width="100%" border="0px">
      <tr>
        <td><input id="subreddit" placeholder="subreddit" type="text" /></td>
        <td><input id="issue" placeholder="issue #" type="text" /></td>
        <td><input id="testp" placeholder="testp name" type="text" /></td>
        <td><input id="djangome" placeholder="django me..." type="text" /></td>
        <td><input id="weather" placeholder="weather zip" type="text" /></td>
      </tr>
    </table>
  </p>
</div>
</body>
<script src="tab.js"></script>
</html>

tab.js

This is where the magic happens! Below is the code which reads the bookmarks from the "Favorites" folder and automatically populates the table:

// display and update the clock on the new tab page.
function updateClock() {
  Date.getMinutesTwoDigits = function() {
    var retval = now.getMinutes();
    if (retval < 10) return ("0" + retval.toString());
    else return retval.toString();
  }
  Date.getHoursModTwelve = function() {
    var retval = now.getHours();
    retval = retval%12;
    if (retval == 0) retval = 12;
    return retval;
  }
  var now = new Date(),
      time = Date.getHoursModTwelve() + ':' + Date.getMinutesTwoDigits();
  document.getElementById('time').innerHTML = ["", time].join('');
  setTimeout(updateClock, 1000);
}

// add "search" capabilities to an input box.
function addSearch(elementId, callback) {
  var elem = document.getElementById(elementId);
  elem.addEventListener('keypress', function(evt) {
    if (evt.keyCode == 13) {
      callback(elem.value);
    }
  });
}

// load the bookmarks and find the "Favorites" folder.
function loadBookmarks(foldername) {
  function search(nodes) {
    for (var i = 0; i < nodes.length; i++) {
      if (nodes[i].title == foldername) {
        _processFavorites(nodes[i].children);
        return;
      } else if (nodes[i].children && nodes[i].children.length > 0) {
          search(nodes[i].children);
      }
    }
  }
  chrome.bookmarks.getTree(function(nodes) { search(nodes); });
}

function _processFavorites(favorites) {
  var header = [];
      accum = [];

  for (var i = 0; i < favorites.length; i++) {
    header.push(favorites[i].title);
    accum.push(favorites[i].children);
  }
  _displayFavorites(header, accum);
}

function _displayFavorites(header, bookmarks) {
  var table = document.getElementById('bookmarks');
  // Create header row.
  var headerRow = document.createElement('tr');
  for (var i = 0; i < header.length; i++) {
    var th = document.createElement('td');
    th.appendChild(document.createTextNode(header[i]));
    headerRow.appendChild(th);
  }
  table.appendChild(headerRow);

  var zipped = _zip(bookmarks);
  for (var i = 0; i < zipped.length; i++) {
    table.appendChild(createRow(zipped[i]));
  }
}

function _zip() {
  var list_of_lists = arguments[0];
  var argLength = list_of_lists[0].length;
  var zipped = [];
  for (var i = 0; i < argLength; i++) {
    var row = [];
    for (var j = 0; j < list_of_lists.length; j++) {
      row.push(list_of_lists[j][i]);
    }
    zipped.push(row);
  }
  return zipped;
}

function createRow(bookmarks) {
  var row = document.createElement('tr');
  for (var i = 0, l = bookmarks.length; i < l; i++) {
    var td = document.createElement('td');
    var link = document.createElement('a');
    link.appendChild(document.createTextNode(bookmarks[i].title));
    link.href = bookmarks[i].url;
    td.appendChild(link);
    row.appendChild(td);
  }
  return row;
}

// Bind search handlers.
addSearch('search', function(s) {
  window.location.href = 'https://www.google.com/#q=' + s;
});
addSearch('subreddit', function(s) {
  window.location.href = 'http://www.reddit.com/r/' + s;
});
addSearch('issue', function(s) {
  window.location.href = 'https://github.counsyl.com/dev/website/issues/' + s;
});
addSearch('weather', function(s) {
  window.location.href = 'http://www.wunderground.com/cgi-bin/findweather/getForecast?query=' + s;
});
addSearch('testp', function(s) {
  window.location.href = 'https://testp-' + s + '.counsyl.com/helpdesk/';
});
addSearch('djangome', function(s) {
  window.location.href = 'http://django.me/' + s;
});
// Display the clock and load the bookmarks table.
updateClock();
loadBookmarks('Favorites');

Installing a custom chrome extension

If you drop these three files into a folder, you can load them up in chrome pretty easily. Just follow the instructions on Google's "Getting started" page:

http://developer.chrome.com/extensions/getstarted.html#unpacked

Thanks for reading, hope you found this interesting!

Updates

I've created a GitHub repo for this extension so I can track and share any improvements or features I add. I'd love to hear your ideas on improving this so please feel free to fork or leave a comment below!

Comments (0)

Commenting has been closed, but please feel free to contact me