Welcome to Code Couch

How to enable resizing of the left-hand labels column in Gmail

Posted by at 10:40pm on November 23, 2011.


Update 3 (10 May 2012): I’ve added a new post that has all the various bug fixes to date as well as new code showing how to get the code working as a user script in Chrome as well as Greasemonkey.

Update 2 (13 Feb 2012): I’ve fixed the bug where selecting content on the page was disabled. You’ll find the new code in this post

Update 1 (Nov 2011): I’ve fixed the bug where resizing the browser window caused things to break. You’ll find the new code in this post


You can still go directly to the original code if you want to – it’s still at the bottom of this article.

I like Gmail, and I like it a lot, even though I was a very “late starter”, only really starting to use it at the start of this year. I was the social outcast of my geek friends, and as known as “the luddite” for my refusal to upgrade from Windows XP to Windows 7, or move away from Outlook and my beloved 1.3GB .PST file.

However, I’m far from a luddite: I’m a control freak, and my reasons for sticking with XP & Outlook were simply because I knew the software very well, and if something went wrong, I knew how to fix it. I’d also tried Vista for some weeks at work, and didn’t exactly find it was aiding my productivity (to put it nicely).

It was a similar story with Outlook – I knew that I had my mail locally, and could make my own backups, for free, and quickly. Gmail seemed to be a mystical entity that people talked about, but no-one really knew how safe their data was. I had to have faith that my data was safe, and that I could access it just as quickly, and not be slowed down by an interface less powerful than a native application (as a software developer / power user, I’m also a keyboard whore. I like shortcut keys, and I like intuitive interfaces).

I’m happy to say that since the start of the year, my I.T. environment has changed significantly – and for the better, I believe:

  • I sold my Windows Mobile 6.5 phone (an HTC HD2), and purchased an iPhone 4S. Technically, the HD2 was – and still is, a damn good phone. With Windows Mobile 6.5 I could record calls, edit the registry, whatever – I was in control of my phone. However, the OS was rapidly losing supporters. For example, Moxier who for a long time had their WM6.5 Wallet software “coming soon” removed these statements from their blog.
  • I deleted my Windows BootCamp partition and started booting into OSX[1]. I’ve owned this iMac for 3+ years, and it has served me very well, as a Windows PC. As you can imagine, I didn’t buy it for the Apple logo; the purchasing decision was made with my head, not my heart: At the time, it was the best computer I could get with a small footprint, and I have a very small desk. It also ran Windows, and I’ve been a Windows user since starting on v2.x at school. I still remember many happy hours typesetting on Aldus PageMaker on the school’s first 386, playing Sopwith Camel and The Game With No Name at CGA resolution, only a lot faster than the 286 machines. Wow – I feel old, and I’m not even 40!
  • While I still have my 1.3GB PST file, I very rarely go near it. In fact, I very rarely kick open my Windows VM (it was odd that I used to run OSX in a VM on my iMac under Windows. It’s certainly easier to get Windows running in a VM on OSX!). I’ve made it read-only, and keep it only to reference client emails when I need to. This switch from Outlook coincided with the deletion of Windows and starting to use Gmail.

Gmail isn’t perfect

… well, what did you expect me to say? No software is bug-free (this I know: I seem to be a bug magnet). I’ve got issues with Gmail, but none of them are bad enough to stop me using it. My two biggest gripes with it are, in no particular order:

  • The searching is nowhere near as good as I would expect, and this is not something that Google are shouting from the rooftops. A lot of the blurb tells you that it’s the “same powerful technology” that’s behind their search engine. Really? Give me substring matching, then I’ll believe you. My typical search on Google involves brackets, quotes, ANDs and ORs. While I can use these, not having substring / partial matching is a very big negative point.
  • The left-hand column is not resizable. It was not resizable on the old interface, nor the old new look, nor the latest new look. As you can imagine, my label structure is quite specific. Don’t get me wrong – I know they’re not folders, I know they’re much better than folders, and my label structure is not even approaching a tenth of the size of my Outlook folder structure, as a lot of the good features in Gmail make it a lot easier to keep things simpler. The conversation view is a fantastic boost to productivity, yet it’s such a simple concept.

I wouldn’t mind if the left-hand column could resize within limits… anything more than the 176 pixels I’m currently allowed would be a bonus. At full-screen with 1920 pixels to fill, it looks very sad and lonely.

I cannot do anything about the search engine, other than report bugs if I find them. If I find bugs in Gmail, Google Docs, or any software from any company, I report them. I normally give very detailed information – after all, it’s in my best interests that the software I use gets better. I also read the help forums and see that many users share my frustrations of many pieces of software, Gmail being no exception.

Stop moaning and do something about it then!

Today I thought I’d do something about the left-hand labels column being a fixed size. Why? Because as a web developer, I could. That’s what I like about web applications – you can modify them as much as you like. And, after all, there’s no point in moaning about a problem that you are able to do something about.

I started out this morning with no real idea of where I was going, and finished an hour or so ago with a good first cut. It’s not perfect, but I’m very happy with what I’ve created – and without too much effort, which does make me wonder why Google have not implemented it already.

To say I had no real idea of where I was going isn’t strictly true. I did have a list of ideals that the code should adhere to:

  • It had to run without any extra JavaScript framework. I like jQuery, and I use it often. However, the main reasons I use it are pretty much obsolete. All modern browsers support .querySelector() / .querySelectorAll(), and IE 9 works with addEventListener. No more testing for global event objects (yippee!). Anyway, I felt that this was such a simple task, it didn’t need a library weighing it down
  • It had to run without Greasemonkey being installed. I know that Chrome will run user scripts without any extra extensions, but not everyone has Chrome, and I don’t believe that people should have to install an add-on to get behaviour than can be provided natively. I don’t run Greasemonkey scripts at all. I may, one day, but I’ve never yet had the need to.
  • The code had to be small enough to use in a bookmarklet. I didn’t have an ideal size in mind, but needless to say, I’m very happy with how it turned out :-)
  • It had to run on modern browsers. Admittedly, I didn’t include IE in that list, but I’m slowly realising that IE 9 isn’t so bad (although I run OSX, so I don’t see it that often)
  • It had to support at very least the new new look, and possibly the old new look Anything other than that was a bonus (the old old look, or any look with themes)
  • It had to be as future-proof as possible. Google change their code frequently, and IDs and classes come and go. I wanted code that weathered these changes. Incidentally, I don’t follow the belief that Google go out of their way to make their code as hard to follow as possible. Why would they provide vast amounts of API documentation, scripting facilities with a visual IDE, etc, if they wanted to keep people from tinkering? Perhaps short class names have something to do with keeping the byte count down? Network traffic doesn’t come for free, and nor does storage space. If you believe Google want to stop you tinkering, you’d best stop reading now, lest your blood pressure raise too high ;-)

Compatibility

I can honestly say I was surprised by the outcome – and it’s not often I’m surprised by my own code. I tested it on the following browsers:

  • IE 9 (Windows 7 VM)
  • Chrome 17 dev stream (OSX)
  • Fx 8 (OSX)
  • Fx 3.6.24 (OSX)
  • Opera 11.52 (OSX)

In all cases, I tested the “new new look” (‘new look’), the “old new look” (‘preview’), and the “old old look” (‘classic’). In all cases, the code “just worked”: I could resize and everything reflowed nicely. I could even resize the settings pages.

When I started coding this morning, I did not think that I would get it working in all the different UIs, let alone IE 9. Now you see why I was surprised with the results – and also with Google for not implementing this much asked-for feature.

The code

Earlier, I said I wanted to keep it small enough to use as a bookmarklet. I must admit, I’ve not actually tried it as a bookmarklet in any browser, as I’ve been using the various consoles to paste the JS code into. However, I think that 899 bytes would count as acceptable, wouldn’t you?

OK – it’s 899 bytes with all whitespace removed, and no comments. However, this is not a lesson in obfuscation, I simply wanted to keep the code size down for bookmarklets. I’ll also post a commented version (still pretty small, just over 3.5kB).

Before I post the code, let me paste in a quote that you read recently:

No software is bug-free

Here’s a list of all the issues I’m currently aware of (whether bugs or things I’d like to add):

  • When switching between pages / themes, the grab bar may end up in the wrong place
  • Sometimes content will become selected during a drag.
  • The bar doesn’t come back after a page reload
  • If you resize the browser window, the calculations do not update so you may well see the right-hand column drop underneath the left-hand column
  • No minimum size is enforced. If you drag too small, don’t expect things to look good :-)

The good news is that if you see any visual glitches you can simply refresh the page and re-run the code. Or, edit the code and fix any bugs you find. Then share the fixes. That, ladies and gentlemen, is why I adore web development: it’s impossible to hide your code, and with the tools at our disposal getting better by the minute, there’s never been a better time to be a front-end developer (incidentally, if you are a front-end developer and you haven’t watched the Re-introduction to Chrome Developer Tools video on Paul Irish’s blog, I strongly suggest you spend 30 minutes watching it. You will learn something; probably lots of somethings ;-)

Here’s the no-whitespace version for those of you wanting to run it as a bookmarklet:

gmonkey.load(2,function(o){var l=i=o.getNavPaneElement(),c=r=o.getActiveViewElement(),d=c.ownerDocument,p='px',t=sx=0,dx,lw,rw,n,s,q,g;while(c.compareDocumentPosition(l)&2)c=c[u='parentNode'];while(i[u]!=d.body)i=i[u];l=(n=c.childNodes)[0],r=n[1],n=l[q='querySelector']('[role=navigation]'),b=n[q]('[role]'),g=i.appendChild(d.createElement('div'));r[s='style'][u='cssText']+=b[s][u];while(t+=n.offsetTop,n=n.offsetParent);g[s][u]='position:absolute;z-index:9;left:'+(l[o='offsetWidth']-5)+'px;top:'+t+'px;bottom:0;width:4px;cursor:ew-resize;cursor:col-resize;background:url(data:image/gif;base64,R0lGODlhAwAEAIAAAL+/v////yH5BAAAAAAALAAAAAADAAQAAAIERGKnVwA7)';g[n='addEventListener']('mousedown',function(e){e.which==1&&(sx=e.pageX,lw=l[o],rw=r[o])},0);d[n]('mousemove',function(e){sx&&(dx=e.pageX-sx,g[s].left=lw+dx-5+p,l[s].width=lw+dx+p,r[s].width=rw-dx+p)},0);d[n]('mouseup',function(){sx=0},0)})

Note: If you are going to use this as a bookmarklet, you need to prefix the code with javascript: when adding it to the URL field.

The same code, with a small amount of whitespace:

gmonkey.load(2,function(o){
	var l=i=o.getNavPaneElement(),c=r=o.getActiveViewElement(),d=c.ownerDocument,p='px',t=sx=0,dx,lw,rw,n,s,q,g;
	while(c.compareDocumentPosition(l)&2)c=c[u='parentNode'];while(i[u]!=d.body)i=i[u];
	l=(n=c.childNodes)[0],r=n[1],n=l[q='querySelector']('[role=navigation]'),b=n[q]('[role]'),g=i.appendChild(d.createElement('div'));
	r[s='style'][u='cssText']+=b[s][u];
	while(t+=n.offsetTop,n=n.offsetParent);
 
g[s][u]='position:absolute;z-index:9;left:'+(l[o='offsetWidth']-5)+'px;top:'+t+'px;bottom:0;width:4px;cursor:ew-resize;cursor:col-resize;background:url(data:image/gif;base64,R0lGODlhAwAEAIAAAL+/v////yH5BAAAAAAALAAAAAADAAQAAAIERGKnVwA7)';
	g[n='addEventListener']('mousedown',function(e){e.which==1&&(sx=e.pageX,lw=l[o],rw=r[o])},0);
	d[n]('mousemove',function(e){sx&&(dx=e.pageX-sx,g[s].left=lw+dx-5+p,l[s].width=lw+dx+p,r[s].width=rw-dx+p)},0);
	d[n]('mouseup',function(){sx=0},0)
})

And the full monty:

// Use the Gmail Greasemonkey API to reliably find the 2 main elements (left- and right-hand columns). You do not need Greasemonkey installed to use the API.
// See http://code.google.com/p/gmail-greasemonkey/wiki/GmailGreasemonkey10API for more details (note: documentation is out of date)
 
// Load the API. It will run our callback function when loaded, passing a GmailAPI object
gmonkey.load(2, function(o) {
 
	/*
		Set up variables. To keep the code size down, I re-use some of these until they hold their final value.
 
		l		this will end up pointing to the element that is resized to change the left-hand column width
		i		this will end up pointing to the element that the grab bar is inserted into
		c		this will end up pointing to the container that holds the left- and right- hand column elements l & r
		r		this will end up pointing to the element that is resized to change the right-hand column width
		d		this points to the document in the frame we use
		b		this points to the 'Compose' button
		p		this holds the string 'px'
		t		this is used to calculate the top coordinate of the grab bar
		sx		this holds the x coordinate of the mouse when dragging starts
		dx		when dragging, this holds the difference between the start x coordinate and the current one
		lw		this holds the initial width of the left-hand column (updated at the start of each drag)
		rw		this holds the initial width of the right-hand column (updated at the start of each drag)
		n		used for many things, most notably holding the string 'addEventListener'
		s		this holds the string 'style'
		q		this holds the string 'querySelector'
		g		this points to the grab bar element
		u		used for many things, most notably holding the strings 'parentNode' and 'cssText'
	*/		
	var l=i=o.getNavPaneElement(), c=r=o.getActiveViewElement(), d=c.ownerDocument, p='px', t=sx=0, dx, lw, rw, n, s, q, g;
 
	// Update c and i to point to their intended elements
	while(c.compareDocumentPosition(l)&2) c=c[u='parentNode'];
	while(i[u]!=d.body) i=i[u];
 
	// Update l, r, and b to point to their intended elements. Create grab bar, and insert into DOM
	l=(n=c.childNodes)[0], r=n[1], n=l[q='querySelector']('[role=navigation]'), b=n[q]('[role]'), g=i.appendChild(d.createElement('div'));
 
	// Copy whatever x-user-select style is on the Compose button and add it to the RH column to minimise text selection while dragging.
	// Copying the existing style seemed easier than adding from scratch... but as I didn't try, I can't say this with 100% certainty :-)
	r[s='style'][u='cssText'] += b[s][u];
 
	// Calculate the cumulative offsetTop of for the top of the grab bar
	while(t+=n.offsetTop,n=n.offsetParent);
 
	// Style the grab bar
	g[s][u] = 'position:absolute;z-index:9;left:' + (l[o='offsetWidth']-5) + 'px;top:' + t + 'px;bottom:0;width:4px;cursor:ew-resize;cursor:col-resize;background:url(data:image/gif;base64,R0lGODlhAwAEAIAAAL+/v////yH5BAAAAAAALAAAAAADAAQAAAIERGKnVwA7)';
 
	// Add event listeners. mousedown is added to the grab bar, mousemove and mouseup to the document
	g[n='addEventListener']('mousedown', function(e) {
		// Only trigger with LMB on grab bar. Stores initial x coord, and widths of left- and right- hand columns
		e.which==1 && (sx=e.pageX, lw=l[o], rw=r[o])
	}, 0);
 
	d[n]('mousemove', function(e) {
		// If we have the mouse button pressed, work out the x delta, update the column widths and the grab bar position
		sx && (dx=e.pageX-sx, g[s].left=lw+dx-5+p, l[s].width=lw+dx+p, r[s].width=rw-dx+p)
	}, 0);
 
	d[n]('mouseup', function() {
		// Stop the mousemove code from running when LMB is released
		sx=0
	}, 0)
})

How do I run it?

I’m going to follow the advice of a very good friend of mine, as much as it hurts my aesthetes to do so:

There’s no noun you can’t verb

The short answer: Google it.

The long answer: Google for ‘bookmarklet’ :-)

If you find bugs, make improvements, or whatever, do let me know. Other than that, use the code as you like, but please follow the terms of use and acknowledge where the code came from. I don’t expect you to fit the license into the bookmarklet, obviously :-)

Enjoy!

Post to Twitter

Comments

There are 14 responses to this post.

  1. I'm not that familiar with Greasemonkey. I'm trying to get this to run inside of Google Chrome. I Googled around and found something called Chrome Monkey (http://blogote.com/ideas/browser-ideas/how-to-install-greasemonkeys-script-on-google-chrome/687/), but I can't seem to figure out how to install your code as a bookmarklet. Can it be done?
  2. Adding myself to the email thread...
  3. Hi Steven, I've added a note to both posts stating that for the bookmarklet to work, the code needs to be prefixed with "javascript:" (without the quotes). I've tested this in Chrome, and it works a treat. For Greasemonkey user scripts, I believe there's a header that needs to be added to the file, and it also needs to have a specific file extension. However, I don't use Greasemonkey, so you might find asking at http://userscripts.org/ gets you further towards your goal. If you do get it working, or have any more suggestions for improvement, etc., post away!
  4. This worked! Totally awesome. Not being able to resize the side panel has been driving me crazy ever since I started using gmail. Thanks so much!
  5. Dan, Thank you, adding a bookmarklet with your code generally works; however, there are some glitches, especially if the browser window is resized (all panels except the left one seem to be lost and are not very easy to restore: involves refreshig the page and re-executing the boormarklet). I would be content with a simpler static solution of increasing the width of the label panel to some fixed (pixels) or %-based width. A search online seems to indicate that it is possible (e.g. http://forum.userstyles.org/discussion/1480/gmail-wider-labels-panel/p1), however I cannot make sense of where to put this code (e.g. from the above URI). Do you have a sense of how to do it? Thank you for the nice work -- your resizing generally works and is a lot better than not being able to resize at all. Regards, Aleksey
  6. Hi Aleksey, The code in this post was my first attempt and was more buggy than I'd hoped. I've posted several updates since then to fix the the worst of the bugs. Check out the latest code at http://www.codecouch.com/2012/02/resizing-the-left-hand-labels-column-in-gmail-support-for-extra-columns/ and let me know if you're still having issues.
  7. I've added a new post dated 10 May 2012 that shows how to get this working as a user script in Chrome as well as Greasemonkey. See the update at the top of this post for details.
  8. Hello Dan! I'm sorry, but I do not understand how to insert the javascript code in Chrome for example. I have to edit the code of the page? Maybe my question is silly, but this is all new to me! Thank you! Wanderson
  9. Hi Wanderson, If you go to our homepage, then scroll down to the "Latest posts" section, the first post listed (dated September 5th) has up-to-date instructions for installing this in Chrome. Let me know if you need any more help with this!
  10. All: For anyone finding that this code no longer works since late March 2013, please read my latest post dated 31st March 2013. It offers an updated wrapper that works with the latest Gmail changes.
  11. I believe this has stopped working. It was working up until yesterday and I tried setting it up on multiple computers with the same results, not working any longer. If someone could update this that would be awesome. I have not found another way to get the column to resize like this. I miss it and it has only been two days. Thanks in advance.
  12. @Dan McGovern: Try using the code from my latest post.... the code in this post is now outdated, and did stop working until I issued an update.
  13. Could this solution be repurposed for google drive? I'm having the same problem with drive's folder column and would love to be able to resize it.
  14. @nate: a Google Drive version is next on my list :-)

Leave a reply

You must either log in or enter your name and email address to post a comment.

Your email address will not be published.

  • You do not need to log in to comment, but you can if you wish.
  • Log in