Welcome to Code Couch

Resizing the left-hand labels column in Gmail – an update to save the column width

Posted by at 1:56pm on April 7, 2013.

Since writing the first version of my Gmail label column resizer back in November 2011, one feature I’ve been meaning to add is the ability to remember the width of the column, so that it is automatically set when loading Gmail. This was also the feature most requested by people who use the script.

Well, it’s good news time: I’ve finally got around to adding this. When the resize operation is finished, the width is saved to a cookie. When the script is loaded, if a valid numerical value is present in the cookie, it is used to set the width of the label column.

To use the updated code, I’d advise using the combined Chrome/Greasemonky wrapper from my previous post.

Here’s the code, I hope you enjoy!

// @version        1.3
// @history        1.3 Store label column width in a cookie (and set on load), update Greasemonkey API check frequency
// @history        1.2 Allow 10 seconds for the Gmail Greasemonkey API to load, Chrome & GM userscripts now share same code
// @history        1.1 Stopped duplicate grab bars and added more URL matching
// @history        1.0 Initial version
 
// Use the Gmail Greasemonkey API to reliably find the 2 main elements (the left- and right-hand columns). You do not need Greasemonkey installed 
// to use this API. See http://code.google.com/p/gmail-greasemonkey/wiki/GmailGreasemonkey10API for details (note: the 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, some are re-used. There should be no global namespace pollution
 
		i		initially points to the parent element of the left-hand nav, ultimately points to the parent element of the grab bar
		l		initially used as a loop counter, ultimately points to the element that is resized to change the left-hand column width
		r		initially used as a temporary loop variable, ultimately points to the style object of the element that is resized in the right-hand column
		c		initially points to the parent element of the active view, then parent element of all columns, then used to hold the width of columns 3-n (if present)
		d		this points to the document in the frame we use
		b		this points to the body
		t		this is used to calculate the top coordinate of the grab bar
		x		this holds the initial x delta between mouse click and left-hand column width
		w		initially used to point to the left-hand and main column elements. During dragging, holds the new width of the left-hand column. On load, holds the saved width (if any)
		n		initially holds pointers to all the columns elements, then the left-hand nav, then holds the string 'addEventListener'
		g		this points to the grab bar element
		Q		this holds the string 'querySelector'
		W		this holds the string 'width'
		U		used for many things, most notably holding the strings 'parentNode', 'childNodes', and 'cssText'
		P		this holds the string 'px'
		S		this holds the string 'style'
		k		this is the function that sets the width of the right-hand column
	*/		
 
	var i=o.getNavPaneElement(), l, r, c=o.getActiveViewElement(), d=c.ownerDocument, b=d.body, t=0, x, w, n, g, Q='querySelector', W='width', U='parentNode', P='px', S='style', k=function() { r[W]=b[o]-l[o]-c+P; };
 
	// Update c and i to point to their intended elements
	while(c.compareDocumentPosition(i)&2) c=c[U];
	while(i[U]!=b) i=i[U];
 
	// Update n to hold pointers to all the column elements (even if more than 2 are present), and w to point to just the first 2
	n=c[U='childNodes'], w=[n[0], n[1]];
 
	// Detect if a table has been used for layout (this happens with some of the Gmail labs, e.g. Right-side chat). If present, find the first
	// element that is controlling the cell's width by finding the first element that has an explicit non-zero width style set. This isn't a
	// perfect detection method (working with all the child nodes might be better), but it's better than nothing, and works at the moment :-)
	if(c.cells)
		for(o in w) {						// Loop over the first two table cells
			for(l in r=w[o][U])				// Find all of the cell's child elements and loop over them
				if(parseInt(r[l][S][W])) {		// If the current child element has a non-zero style width explicitly set...
					w[o]=r[l];			// ... then assume it is the width-controlling element, and store in in the current item in w
					break;				// There's no point in continuing to check the children (doing a "When a stranger calls")
				}
		}
 
	// Update l and r to point to their intended elements, and determine how much space is taken up
	// by any other columns (if present) by subtracting the label & main columns widths from the body width
	l=w[0], r=w[1][S], c=b[o='offsetWidth']-l[o]-w[1][o];
 
	// Create the grab bar, and insert it into the page
	g=i.appendChild(d.createElement('div'));
 
	// Copy the inline style from the "Compose" button. At present, the only inline style is a browser-specific user-select style used to prevent text selection.
	// This is applied to the right-hand column while dragging is underway to stop the text being selected. It is removed afterwards so that text can be copied.
	// This approach keeps the code size down, as the Gmail code handles the browser detection so I don't have to deal with vendor prefixes.
	// Store the inline style in a property called 'cssText2' of the right-hand column's style object
	n=l[Q]('[role^=n]');
	r[(U='cssText')+2]=n[Q]('[role]')[S][U];
 
	// Calculate the top position for the grab bar
	while(t+=n.offsetTop, n=n.offsetParent);
 
	// Style the grab bar
	g[S][U] = W + ':4px;position:absolute;z-index:1;left:' + (l[o]-5) + 'px;top:' + t + 'px;bottom:0;cursor:ew-resize;cursor:col-resize;background:url(data:image/gif;base64,R0lGODlhAwAEAIAAAL+/v////yH5BAAAAAAALAAAAAADAAQAAAIERGKnVwA7)';
 
	// Add a resize event to the window to update the size of the right-hand column when the window is resized
	// While Gmail does this anyway, it doesn't take into account any size change to the left-hand column
	top[n='addEventListener']('resize', k, 0);
 
	// Add mouse event listeners. mousedown is added to the grab bar, mousemove and mouseup to the document
	g[n]('mousedown', function(e) {
		// Only trigger with the LMB on grab bar. Stores initial x coord and width of left-hand column
		// Save a copy of the existing right-hand column style so we can restore it later, then disable text selection
		// Call e.preventDefault() to stop a native drag operation from starting (this happens a lot in Fx)
		e.which==1 && (x=l[o]-e.pageX, r[U+3]=r[U], r[U]+=r[U+2], e.preventDefault());
	}, 0);
 
	d[n]('mousemove', function(e) {
		// If we have the mouse button pressed, work out the x delta then update the column widths and the grab bar position
		x && (w=e.pageX+x, l[S][W]=w+P, g[S].left=w-5+P, k());
	}, 0);
 
	d[n]('mouseup', function(e) {
		// If the LMB is released, stop the mousemove code from running and restore the right-hand column style
		// k() needs to be called again, as restoring the style could alter the width
		// Also save the label column width into a cookie
		e.which==1 && (x=0, r[U]=r[U+3], d.cookie='labelWidth='+w+'; expires=Fri, 31 Dec 9999 23:59:59 GMT"', k());
	}, 0);
 
	// If the label column width has been previously saved, use it to set the initial width
	w = parseInt(d.cookie.replace(/(?:(?:^|.*;\s*)labelWidth\s*\=\s*((?:[^;](?!;))*[^;]?).*)|.*/, '$1'), 10);
	if (!isNaN(w)) l[S][W]=w+P, g[S].left=w-5+P, k();
});

Please note: I’ve not created a bookmarklet version of this code. I don’t know if anyone actually uses the bookmarklet version or not. If you do use the bookmarklet version and would like me to update it to have this new functionality, please leave me a comment using the form below.

Post to Twitter

Comments

There are 22 responses to this post.

  1. Awesome!!!
  2. Thanks!
  3. Wow!! I have literally hundreds of labels at work and I used to name them with silly abbreviations because I can't stand the fact that I'm jsut not able to see how many unread mails I have in each label without opening them if the name is "too" long. You've just made my life so much easier. Thanks a lot bro.
  4. Need help with this. Please contact me. Thank you.
  5. @Phil Spiegel: What is the problem you are having?
  6. Good afternoon, I am definitely not a programmer but I am using Firefox and need to know how to resize the labels column in my online gmail account as my labels are longer than the 8-10 characters that show. Can you please let me know exactly what I need to do? From a layman's perspective? Thanks! Larry
  7. Very good work. Thanks! A bug report. I am using latest Chrome version v33. When I turn on its preview function in Gmail Labs and then enable the horizontal setting. Then, for example, when I drag the whole windows to right/left to become half. And double click the header to maximize it. All central area of Gmail become BLANK.
  8. A bug report. If I turn on the Preview Window addon in Gmail lab, and then enable it in Gmail (e.g. Horizontal). Then after I change the column size, drag the windows title bar to left or right to become half size windows, and then double click its head to maximize the window, I will find all central gmail area become bank.
  9. hi, tried to apply your script through the extensions, but when I drag/drop the .js file I get a message yellow bar 'your script must be UTF8 encoded (OK)'. then I can only click (OK), and it all ends, no further steps described by you (i.e. 'add'...). my coding in chrome/tools is set to UTF8, but doesn't work, neither when other codings are set. or is it due to wrong saving the .js file in the notepad? but I can't see any option of saving with a specific coding..
  10. sorry, made a mistake, and copied 2 'full monty' scripts instead of the 'first' one and then 'full monty'. it works on my private computer. let's see if my corporate computer will allow me add it to chrome ;) thanks!
  11. yeah... blocked by the admin... ;-\
  12. Hey, I use your script and it is very helpful. I have many gmail accounts and mainly use them for my gaming as I review games. Would it be possible for you to adjust the code so that it can save locations for multiple Gmail Accounts opened in chrome? The save position code throws an error (see below). Also if possible can you let me know how to add the relevant permissions to the script as per https://developer.chrome.com/extensions/content_scripts? Would be great if you can do this and I would like to buy you a beer! :) Thanks!
  13. I would love an updated version of your bookmarklet please. Thx!
  14. @Fred Lacoste: Is there any functionality in particular that you'd like to see added?
  15. @Dan: After enabling current bookmarklet version in Gmail under Chrome (normal updated stable edition), make the windows smaller and then maximize the windows again, whole Gmail window will become blank! So a bug-fix version of bookmarklet is needed. Thanks!
  16. @Pat, I've tried repeating these steps in both Chrome and Firefox but can't reproduce the issue. I have seen the blank window problem once before, but couldn't find a guaranteed way to recreate the problem. I found that when the issue occurred for me, I simply entered 'gmail.com' in the URL bar again and the problem went away.
  17. @Pat: Sorry - I forgot to enable the 'preview' lab before my previous reply. I can see the problem now... It seems to occur at certain steps of the resize. If I see the problem while I'm shrinking the window, I can keep shrinking it and the window will appear. I'll look into it for you... but it probably won't be until early June I get a chance.
  18. @dot77: It's a shame it's blocked by your admin. Did you try the bookmarklet version at all?
  19. Hi Larry, You'd need to install the "Greasemonkey" extension / add-on for Firefox, then restart Firefox. Once this is done, you need to make a complete script. To do this, copy the wrapper code from my previous post into a text editor (it's linked to in the paragraph preceding the code). Then copy the code from this post, and paste it into the wrapper where indicated, saving the file with a name like "gmaillabelresizer.user.js" (the ".user.js" bit is important). Then open a new tab in Firefox, drag the file into it, and you should be prompted for the rest. Restart Firefox and you should be sorted.
  20. @Bandon: I've no plans to add support for multiple accounts just yet, sorry.
  21. This has stopped working now for me, chrome has taken it out, any new code?
  22. I've been having this same problem Pat wrote about in May of 2014. I was just about to write a detailed description of it and suddenly tried something new so thought I'd post it in case others have the same problem. The problem goes away if I move the Windows task bar from the bottom to the side or if I change the browser window out of 'maximize.' Not sure why this is, but hopefully it will help others. Jennifer

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