How to create sticky table headers using jQuery

Welcome those big, sticky, complicated problems. In them are your most powerful opportunities.
-Ralph Marston

 

 

 

 

 

 

Here s a nice way to use jQuery and make table headers sticky when a page is scrolled down and the table headers reach the top. This is a feature in the new look that Google is sporting, in Google documents, Gmail etc. Obviously Google is not using jQuery to accomplish this and they are probably using some fancy code to do it. This is just a quick way to get it working on table headers.. <th> elements. In this setup we calculate the distance of the table from the top, check if it reaches 0 while scrolling and apply the CSS property position:fixed to it. If it falls back under the distance it had, then we revert the position to normal.

Pass in the table’s id to the function that follows it. For example if you have a table that had an id = “my_table”, then pass this in the document.ready function:

$(document).ready(function(){
makeTableHeadersSticky("#my_table");
});

function makeTableHeadersSticky(tableId)
{
//collect widths of all the th elements
var thArr = $(tableId + " th");
var thWidthsArr = []; //an array to hold the auto calculated widths of each <th> element
$(tableId + " th").each(function(){
thWidthsArr.push($(this).css("width"));
});
var pos = $(tableId).offset();
var thTop = pos.top + "px";   //this is the distance of the table from the top, we ll need to make the headers sticky when this distance is 0

//set the widths of the first and last tr's ths/tds... this is done coz in some cases, the widths will get messed up if the data was generated dynamically
var count = 0;
$(tableId + " tr:first-child>th").each(function(){
$(this).css("width", thWidthsArr[count]);
count++;
});

 

count = 0;
$(tableId + " tr:last-child>td").each(function(){
$(this).css("width", thWidthsArr[count]);
count++;
});

$(window).scroll(function(){
if($(window).scrollTop() > pos.top)
{
$(
tableId + " tr:first-child").css("position", "fixed");
$(
tableId + " tr:first-child").css("top", "0px");
}
else
{
$(
tableId + " tr:first-child").css("position", "relative");
$(
tableId + " tr:first-child").css("top", thTop);
}
});
}

Posted in How To, jQuery, Tips | Leave a comment

How to upgrade firefox in Ubuntu

A good fox does not eat his neighbor’s fowl!
-French proverb

I tried 11.04 along with Unity and went back to the fallback mode. Then I tried 11.10 where I couldnt go back to fallback mode. Like many people even I m dissatisfied with the ‘interface’ level development on Ubuntu with Gnome 3. I felt the same dissatisfaction with Fedora as well. I am fond of minimalistic layouts when it comes to GUI and anything that’s added just to prep the user experience visually, generally turns me off. Mac OS is the only exception though I have a list of pet peeves when it comes to the Mac OS as well.

Anyway, so I decided to go back to Ubuntu 10.04 coz its definitely going to be supported till 2013 and I m hoping by then the Linux distros will stop trying to match up with the Mac in terms of visual layout and instead focus on its own intrinsic beauty which can be felt even through a classic Clearlooks theme on any distribution using Gnome 2.

Anyway, so I ve digressed enough. This post is supposed to be just a reminder for me on how to upgrade the default Firefox on Ubuntu. 10.04 uses Firefox 3.6.23 when Firefox has released version 5, 6, 7 and very recently 8 in 2011 itself. Mozilla had announced this development plan so its okay I suppose but overall I m not too happy with a company making so many major version changes in the same year!

To upgrade the Firefox version to the most recent one, you ll need to run the usual update and upgrade commands on apt-get and then add the following ppa to the Ubuntu repository list:

sudo add-apt-repository ppa:mozillateam/firefox-next

After that again

sudo apt-get update
sudo apt-get upgrade

And Firefox should be at its most recent offering which is 8 as of today.

Posted in How To, Linux | Leave a comment

Solution: How to get a svn log by author name

I am in the habit of maintaining a daily work log. I do this in a Google spreadsheet and maintain each month on an individual sheet. This not only lets me share with the team what I ve been up but it also gives me a good idea about how a particular week or month was and then based on that I can make some changes to my daily schedule to improve my productivity. The only issue is, sometimes I forget to maintain the work log and then if that happens for a number of days, then the spreadsheet has this unbearable ‘void’ suddenly. To deal with this, I want to naturally turn to my recent project’s git or svn log for filling up the missing days. But svn log will not give me a log by author. So here s a XML + XSL based solution that I m using currently.

I export the svn log to a xml file

svn log --xml -v > mylog.xml

And then I add a XSL stylesheet to the log file that got created on its second line (right after the XML version declaration)

<?xml-stylesheet type="text/xsl" href="myxsl.xsl"?>

And finally I use the following XSL to filter out other authors and only include my commits. If you are copying this from here, then make sure you substitute my name ‘walmik’ with your name.

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<h2>My SVN log</h2>
<table border="1">
<xsl:for-each select="log/logentry">
<xsl:if test="author='walmik'">
<tr>
<td><xsl:value-of select="@revision"/></td>
<td><xsl:value-of select="author"/></td>
<td><xsl:value-of select="substring(date,1,10)"/></td>
<td><xsl:value-of select="msg"/></td>
<td>
<xsl:for-each select="paths/path">
<table>
<tr>
<td></td>
<td><xsl:value-of select="@action"/></td>
<td><xsl:value-of select="."/></td>
</tr>
</table>
</xsl:for-each>
</td>
</tr>
</xsl:if>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

As you can notice I m using a substring to format the date to show just the year, month and day.

Now when I open the XML in a browser, I can copy the work log entries from missing dates and paste it inside the Google spreadsheet. Of course, this whole exercise would be pointless if you are not in the habit of adding a message to your commits!

Posted in How To | Leave a comment

Renaming multiple files in a folder to a numbered format from the terminal

This is just for my reference. I needed to rename a whole lot of png files in a folder from filename.png, some-other-filename.png to 0.png, 1.png etc. It took a little bit of experimenting and it lead me to:

count=0; for file in *; do mv $file $count.png; let count=$count+1; done;

Posted in Tips, Useful | Tagged , | Leave a comment

Toggle TinyMCE rich text editor effectively

Using TinyMCE effectively can take a bit of practice and time. Especially if you have multiple TinyMCE instances on the same page pulling dynamic data. Two common problems are to display the data itself and the other is to toggle the rich text editor on a TinyMCE enabled textarea to display rich text or not on the click of a button.

The first case can be tackled by pulling data after a small delay so that TinyMCE assets are loaded. The second case can be handled as follows:

To remove rich text capability from a textarea with the id ‘tmce-id’:

tinymce.get("tmce-id").save();
tinymce.execCommand('mceRemoveControl', true, "tmce-id");

In the above code, we saved the contents before removing the control so that the most recent edited text is available in plain view. You may also want to strip the tags that the editor had added to the text. You can just use a regular expression to do so and put in a function so you can reuse it quickly:

function stripHtml(str){
return str.replace(/<\S[^><]*>/gi, "");
}

So now the code would look like:

tinymce.get("tmce-id").save();
tinymce.execCommand('mceRemoveControl', true, "tmce-id");
var str = $("#tmce-id").val();
$("#tmce-id").val(stripHtml(str));

To add rich text again,

tinymce.execCommand('mceAddControl', true, "tmce-id");

In case of multiple TinyMCE textarea instances on the same page, you can pass a custom HTML attribute to the buttons that toggle TinyMCE. So if you are looping from 0 to 10 while adding textareas then the buttons that you are drawing for toggling can have a custom html attribute such as

<a class='enable-rte-btn' ref='tmce-id-0'>Enable Rich Text</a>
<a class='disable-rte-btn' ref='tmce-id-0'>Remove Rich Text</a>
<textarea id='tmce-id-0' class='tinymce'></textarea>

You can draw out multiple textareas like this incrementing 0 to 10 or whatever the number and then enable TinyMCE on textareas with the class ‘tinymce’. If there are too many textareas then pull the data after a small delay (based on the number of textareas you have) and load it in the textareas. After that add a click function to enable or disable rich text on all tags with the class ‘enable-rte-btn’ and ‘disable-rte-btn’ respectively.

Posted in Tips | Leave a comment

Goals4Me

Goals are the fuel in the furnace of achievement.
-Brian Tracy, Eat that Frog


I m happy to announce that I ve just launched the BETA version of my first independent app Goals4Me. There are still a lot of things to add to it though one can objectively identify what his or her primary goal in life is and get some ideas on getting started. It is based on whatever I ve read or heard from Brian Tracy, Zig Ziglar and Tony Robbins about setting goals, which boils down to identifying a bunch of goals, selecting one of them, setting a deadline on it, identifying the obstacles, listing the people/groups/organisations that can be of help, noting the skills required and listing down the benefits.

In my personal experience, I never found a tool that would let me do all that (in a free application). I d have to create document and put the headers etc to make such a sheet to get started with a goal. So I finally created the first basic version of such an application and put it online. Each time I use it, I realise that my overall inclination toward achieving a goal becomes refined and I am able to take things forward in a particular desired outcome. So much so that I use it for smaller goals and objectives as well. I hope it benefits others too. I will be adding more features along the way. The immediate one is to email the user’s current session. At the moment it only lets you download a PDF of the session.

So here’s the link again: Goals4Me!

Posted in Useful | Leave a comment

CSS max-width to the rescue

You can’t do anything about the length of your life, but you can do something about its width and depth
-Henry Louis Mencken

Recently I discovered a wonderful CSS2 property: max-width. This property lets you fit your images inside the width of its container perfectly. It uniformly scales it as well. So if you have an image that is overflowing out of its container, just set its max-width property to 100%. Most people either set the div’s overflow property to hidden or they simply open up a graphics application and resize it. No need to do that if the image is just a little bigger than its parent.

#containerDiv
{
width: 200px;
height: 200px;
border: 3px solid #000;
}
#containerDiv img
{
max-width: 100%;
}

Posted in CSS, Tips | Leave a comment

Solution for jQuery Cycle’s scrollHorz property hiding slides

There are two ways to slide easily through life: to believe everything or to doubt everything. Both ways save us from thinking.
-Alfred Korzybski

This is more of a reminder for me than anything else. If it helps you then thats an added advantage ;)

I ve been building the Instant Customer system for some time now and it has a lot of z-index’s all over the page for the various overlapping effects we have in there. The last z-index I set had me look up for the max z-index that you can possibly set and it happens to be unlimited but most browsers will limit it to signed 32 bit values, so 2147483647 is the max you should reach. Obviously I m not using that many indices on Instant Customer, but there are at least a 100s of em set arbitrarily from tens to tens of thousands. So anyway, all this messes up the z-index that jQuery Cycle plugin sets for slideshows. The most noticeable (to me) was the slide type ‘scrollHorz’ not displaying any of the slides at all but functioning nevertheless. I switched the one’s using ‘scrollHorz’ to ‘fade’ and they worked! But then some slideshows necessarily required the scrolling feature, especially in the Tips section of Instant Customer on the bottom.

The solution that popped up after experimenting a bit inside Firebug was to set a fixed height on the parent div/html element of the slideshow holders. It can even be a min-height.

Posted in jQuery, Tips | Leave a comment

Javascript equivalent for PHP’s array_map()

To map out a course of action and follow it to an end requires courage
Ralph Waldo Emerson

I was looking for an equivalent of the PHP array_map() function or the Python map() function in Javascript.  Turns out that Javascript doesnt have this natively but sure enough jQuery has one!

function sq(x) { console.log(x*x); }
//call the following in document.ready
$.map([1,2,3,4,5], sq)
;

This returns:
1
4
9
16
25

Another way for doing this without jQuery is to use the following function. It is based on a function I found in a wonderful book on Javascript  called Eloquent JavaScript: A Modern Introduction to Programming that I am currently reading (a free online version is available on the book’s site),

function map(func, array) {
var len = array.length, result = new Array(len);
for (var i = 0; i < len; i++)
result[i] = eval(func + "(" + array[i] + ")");
return result;
}

In the book, the author uses the function argument(func) without eval() like this,

result[i] = func(array[i]);

I changed that bit.

Posted in Javascript, jQuery, Tips | 1 Comment

How to split an array into smaller arrays

“The soul can split the sky in two and let the face of God shine through.”
-Edna St. Vincent Millay

Some days ago I need to split an array into multiple smaller arrays. I m not sure if this is the perfect way to do it, but here is anyway. If you know a better way by maybe using Array.splice() or something then please lemme know via comments.

var arrToSplit = ["won", "to", "tree", "foe", "five"];
var itemsPerSmallerArr = 3;
var distributedArr = [];
var count = 0;
var tmpArr = [];
for(i=0; i < arrToSplit.length; i++){
if(count < itemsPerSmallerArr)
{
tmpArr.push(arrToSplit[i]);
}
else
{
distributedArr.push(tmpArr);
count = 0;
tmpArr = [];
tmpArr.push(arrToSplit[i]);
}
count++;
};
distributedArr.push(tmpArr);
console.log(distributedArr);

Posted in How To, Javascript | Tagged | Leave a comment