Twitter style text counter in jQuery

By Ali Karbassi | October 27th, 2008 | Javascript |
Punch Chart on Raphaƫl

I. Love. jQuery. I can’t say how much I love jQuery because some people might get jealous because jQuery might out-rank them in the scale of 0 to jAWESOME!

Enough drooling and leg humping. In a recent project, we needed a counter to display the number of characters the user had left in a text area. Nothing to hard or interesting. This sort of thing has been out there for years. The problem is, all the scripts I’ve found would automatically truncate the text. That is, if the user has 100 characters and they enter 105 characters, the 101 to 105th characters are gone. This is very annoying!

Rather than control the user and annoy them, we wanted to take the method Twitter does; Warn the user, don’t allow them to submit until the warning is fixed. That is, if the text counter is negative, they cannot submit, but once it’s 0 or greater, it’s fair game.

To add to the fun, we needed visual cues, i.e. colours! After some search and no luck, I sat down and wrote this little beauty. It’s version 1 so be nice.

You can always grab a copy here: http://karbassi.com/scripts/javascript/twitterCounter.js or http://plugins.jquery.com/project/twittercounter

/*
 * twitterCounter
 *
 * Displays a counter with the remaining text.
 *
 * Example:
 *   $('#description').twitterCounter(
 *   {
 *     limit: 140,
 *     counter: '#textcounter',
 *
 *     okSize: 140,
 *     okStyle: '.ok',
 *
 *     watchSize: 20,
 *     watchStyle: '.watch',
 *
 *     warningSize: 10,
 *     warningStyle: '.warning',
 *
 *     errorSize: 0,
 *     errorStyle: '.error',
 *   });
 *
 * $Version: 2008-10-24
 * Copyright (c) 2008 Ali Karbassi
 * ali.karbassi@gmail.com
 */
jQuery.fn.twitterCounter = function(options) {
   var curSize = $(this).val().length;
   var charsLeft = options['limit'] - curSize;
   var types = ['ok', 'watch', 'warning', 'error'];
   var x = {};
 
   $.each(types, function(){
      var el = this.toString();
      x[el] = {'Max' : options[el + 'Size'],
      'Style' : options[el + 'Style'].substring(0, 1) == '.' || options[el + 'Style'].substring(0, 1) == '#' ? options[el + 'Style'].substring(1, options[el + 'Style'].length) : options[el + 'Style'],
      'Type' : options[el + 'Style'].substring(0, 1) == '.' ? 'class' : 'id'}
   });
 
   for( var i=0; i < types.length; i++)
   {
      var el = types[i].toString();
 
      // Last Element check
      if( i+1 < types.length ) {
         var nextEl = types[i+1].toString();
         // console.debug(charsLeft, el, x[el]['Max'], x[nextEl]['Max']+1, charsLeft > x[nextEl]['Max'] && charsLeft < x[el]['Max'] + 1);
         if( charsLeft > x[nextEl]['Max'] && charsLeft < x[el]['Max'] + 1) {
            clean();
         }
      } else {
         // console.debug(charsLeft, el, x[el]['Max'], x[nextEl]['Max']+1, charsLeft < x[el]['Max'] + 1);
         if( charsLeft < x[el]['Max']  ) {
            clean();
         }
      }
   }
 
   $(options['counter']).text(charsLeft);
 
   // Add an event so the counter updates when the user types.
   $(this).one('keyup', function(){
      $(this).twitterCounter(options);
   });
 
   function clean() {
      if( x[el]['Type'] == 'class' ) {
         $.each(types, function(){
            var temp = this.toString();
            if( $(options['counter']).hasClass(temp) ) {
               $(options['counter']).removeClass(temp);
            }
         });
         $(options['counter']).addClass(x[el]['Style']);
      } else {
         $(options['counter']).id(x[el]['Style']);
      }
   }
};

Photo credit: Dmitry Baranovskiy

Programming Child Names or “What not to name your children”

By Ali Karbassi | October 8th, 2007 | General | 3 comments

Am I being too much of a geek to even consider this? I always thought it would be super cute (and nerdy) to name your child after something you love. Okay, maybe not for all loves, but it works for some loves. People name their children after their parents, grandparents, celebrities, and even pets; so why not name a child after programming languages. Maybe it’s too much of a commitment to name your child after a programming language, but maybe a pet.

Here’s a short list of programming languages that could be names also. Bare with me.

Perl, Ruby
“Pearl” and “Ruby”; Both could be said to be named after jewels.
C, C++
Alright, you shouldn’t name your child just one letter, but you can name him or her which starts with the character C. Examples: Chris, Chad, Christy, Caroline, etc. Now, if you could make your child name their child with a C
PHP/ASP/JSP
You have to have a last name that starts with P. So, let’s say you’re last name is Perkins. You can name your children, Phillip Hurburt Perkins, Allison Susan Perkins, or Jenny Sandra Perkins.

On the other hand, you could always name a new programming language after your child. That would be incredibly sweet also. You decide: too geeky or reasonable?

Automatically Block Facebook Applications

By Ali Karbassi | September 19th, 2007 | Greasemonkey, Javascript, Web Programming | 36 comments

Facebook Blocked Applications Header

While working on the next version of my Facebook Profile Cleaner, I noticed something that I was doing. Every time I would log into Facebook, I would have 3-5 new application invites. Personally, I don’t care too much about them (if you didn’t know already). I set out to see if I could come up with a way to automatically block them upon sign on/request.

That task seemed pretty easy, but it didn’t turn out to be. First of all, Facebook hides their “Block Application” button on you. The first place you see it is on the application’s page itself. Second, on the user’s request page it only shows an add and ignore. If you click ignore, it ignores that specific request, not any future ones. This gets real annoying when a ton of your friends decide to add (and send you requests) of the same application. And third, I was worried that maybe I would want to remove a block later. However Facebook was kind enough to provide a page to “remove” blocked applications. By going to http://facebook.com/privacy.php?view=platform&tab=all, the second half of the page will list applications you have blocked. Notice they are listed by the order they were blocked; most recently blocked will be on the bottom.

Facebook Blocked Applications

That being said, I set out to actually block each application invite I get. After a few hours here and there, I finally got it fully working. The code should be clean enough for anyone interested enough to walk though. But note that if you just want the application and don’t care for the actual code, then just install it and be on your merry way :).

If you have any suggestions, comments, or concerns, be sure to comment below.

To use this script, you need Greasemonkey addon. Once you have it, just go here and click install: http://userscripts.org/scripts/show/12393 or http://karbassi.com/scripts/greasemonkey/autoblockfacebookapps10.user.js.

Here’s the code:

// Auto-Block Facebook Apps
//
// Version 1.0
//
// Date Written: 2007-09-18
// Last Modified: 2007-09-19 12:51 PM (12:51)
//
// (c) Copyright 2007 Ali Karbassi.
// Released under the GPL license
// http://www.gnu.org/copyleft/gpl.html
//
// --------------------------------------------------------------------
//
// This is a Greasemonkey user script.
//
// To install, you need Greasemonkey: http://greasemonkey.mozdev.org/
// Then restart Firefox and revisit this script.
// Under Tools, there will be a new menu item to "Install User Script".
// Accept the default configuration and install.
//
// To uninstall, go to Tools/Manage User Scripts,
// select "Auto-Block Facebook Apps", and click Uninstall.
//
// --------------------------------------------------------------------
//
// WHAT IT DOES:
// After the facebook profile page is loaded, it finds all the
// applications that your friends have invited you to and blocks them.
// Do not worry though, you can go to
// http://facebook.com/privacy.php?view=platform&tab=all and unblock
// them
//
// NOTE: This does not alter, delete, edit, add, or anything else to
//       your facebook profile. Just remove or disable this script and
//       everything will be displayed the same as it used to
// --------------------------------------------------------------------
//
// ==UserScript==
 
// @name        Auto-Block Facebook Apps 1.0
// @author      Ali Karbassi
// @namespace   http://www.karbassi.com
// @description This script will block app invites sent to you by friends. After the facebook profile page is loaded, it finds all the applications that your friends have invited you to and blocks them. Do not worry though, you can go to http://facebook.com/privacy.php?view=platform&tab=all and unblock them.
// @include     http://facebook.com/home.php*
// @include     http://*.facebook.com/home.php*
// @include     http://facebook.com/reqs.php*
// @include     http://*.facebook.com/reqs.php*
// ==/UserScript==
 
 
 
// Find Subdomain
var subDomain = getSubDomain();
 
// Get links on the front page/request page
var anchors = document.getElementsByTagName('a');
var appReqExp = /reqs\.php#confirm_(\d*)_(.*)/;
 
for( var i = 0; i < anchors.length; i++ )
{
  if( appReqExp.exec( anchors[i].href ) )
  {
    prep(RegExp.$1, anchors[i]);
  }
}
 
// Remove any notifications about apps.
removeNotifications();
 
 
// Functions
// PLEASE DO NOT TOUCH IF YOU HAVE NO IDEA WHAT YOU'RE DOING. YOU MIGHT BREAK IT.
 
// Prepares everything. When things are correct, it calls BlockApp.
function prep(appID, appNode)
{
  var postformMatch = /name="post_form_id" value="(\w+)"/;
  var post_form_id = 0;
 
  GM_xmlhttpRequest(
    {
      method: 'GET',
      url: 'http://www.facebook.com/apps/block.php?id=' + appID + '&action=block',
      headers:
      {
        'User-Agent': window.navigator.userAgent,
        'Accept': 'text/html',
      },
      onload: function(responseDetails)
      {
        if( (responseDetails.status == 200) && (responseDetails.responseText.indexOf('This will not prevent you from seeing') != -1) )
        {
          // Show that we are working on it.
          appNode.removeAttribute('href');
          appNode.innerHTML = 'Reading confirmation page...';
 
          postformMatch.exec( responseDetails.responseText );
 
          // Calls function to block the app
          BlockApp(RegExp.$1, appID, appNode);
        }
      }
    }
  );
}
 
function BlockApp(post_form_id, appID, appNode)
{
  GM_xmlhttpRequest(
    {
      method: 'POST',
      url: 'http://' + subDomain + 'facebook.com/apps/block.php?id=' + appID + '&action=block',
      headers:
      {
        'User-Agent': window.navigator.userAgent,
        'Accept': 'text/xml',
        'Content-Type': 'application/x-www-form-urlencoded',
      },
      data:'post_form_id=' + post_form_id + '&save=1',
      onload: function (responseDetails)
      {
        if( (responseDetails.status == 200) && (responseDetails.responseText.indexOf('You have blocked this application') != -1) )
        {
          appNode.innerHTML = 'App Blocked!'
          appNode.href = 'http://facebook.com/reqs.php';
        }
      },
      onerror: function (responseDetails)
      {
        appNode.removeAttribute('href');
        appNode.innerHTML = 'App Block failed!';
      }
    }
  );
}
 
function removeNotifications()
{
  var inputs = document.getElementsByTagName('input');
  for (var i = 0; i < inputs.length; i++)
  {
    if( inputs[i].value == 'Ignore' )
    {
      for( var j = 0; j < inputs[i].attributes.length; j++)
      {
        if( (inputs[i].attributes[j].nodeName == 'onclick') && (inputs[i].attributes[j].nodeValue.indexOf('click_add_platform_app') != -1) )
        {
          var js = (inputs[i].attributes[j].nodeValue).split(' ');
          js.shift();
          js = js.join(' ');
          location.href = 'javascript:' + js;
        }
      }
    }
  }
}
 
function getSubDomain()
{
  var subDomainRegExp = /http:\/\/(.*\.)facebook\.com/;
  var subDomain = '';
  if (subDomainRegExp.exec(document.location) != 0)
  {
    subDomain = RegExp.$1;
  }
  return subDomain;
}

Facebook Profile Cleaner

By Ali Karbassi | August 27th, 2007 | Greasemonkey, Javascript, Web Programming | 29 comments

I use Facebook the way you should; for keeping track of my friends, their information, planning events, discussing things, etc. I don’t believe that Facebook should be another MySpace (a popularity contest).

That being aside, I didn’t enjoy the fact that Facebook now allows “apps” (applications/widgets) to be added to profiles. Sure, some applications are useful, but like MySpace, it gets annoying. So, with that I created a Greasemonkey script to remove, per se, all those apps. You can also specify others, such as “Mini-Feed”, “Education”, etc.

To use this script, you need Greasemonkey addon. Once you have it, just go here and click install: http://userscripts.org/scripts/show/11747.

I spent around 1 hour and whipped it up and it works better wonders. To me, it loads the page faster. Here’s the code:

// Facebook Profile Cleaner
//
// Version 1.0
//
// Date Written: 2007-08-26
//
// Copyright (c) 2007, Ali Karbassi
// Released under the GPL license
// http://www.gnu.org/copyleft/gpl.html
//
// --------------------------------------------------------------------
//
// This is a Greasemonkey user script.
//
// To install, you need Greasemonkey: http://greasemonkey.mozdev.org/
// Then restart Firefox and revisit this script.
// Under Tools, there will be a new menu item to "Install User Script".
// Accept the default configuration and install.
//
// To uninstall, go to Tools/Manage User Scripts,
// select "Facebook Profile Cleaner", and click Uninstall.
//
// --------------------------------------------------------------------
//
// WHAT IT DOES:
// After the facebook profile page is loaded, it finds all the
// applications that are not in the list below and 'removes' them. By
// remove, I mean, not display them.
//
// NOTE: This does not alter, delete, edit, add, or anything else to
//       your facebook profile. Just remove or disable this script and
//       everything will be displayed the same as it used to
// --------------------------------------------------------------------
//
// ==UserScript==
// @name           Facebook Profile Cleaner
// @namespace      http://tech.karbassi.com/
// @description    Removes applications from all profiles. Clean out
//                 all those annoying applications people add. This
//                 script will remove all the applications (plus
//                 others if specified) from any facebook profile
//                 you view.
// @include        http://*.facebook.com/*
// ==/UserScript==
 
// Comment out the ones you don't want displayed
// Note: This list is the 'original' apps
var AppsToKeep =
	[
		'box_app_2407511955',	// Mutual Friends
		'box_app_2356318349',	// Local Network Friends
		//'box_app_2503140832',	// Friends in Other Networks
		'box_app_2305272732',	// Photos
		//'box_app_2347471856',	// Notes
		//'box_app_2361831622',	// Groups
		//'box_app_2341989679',	// Mini-Feed
		'box_app_2327158227',	// Information
		'box_app_2297529396',	// Education and Work
		//'box_app_2386512837',	// Gifts
		'box_app_2719290516',	// The Wall
	];
 
 
 
// DO NOT EDIT
// Well, unless you know what you're doing
 
Array.prototype.inArray = function (value)
{
	var i = this.length;
	while( i-- )
	{
		if( this[i] === value )
		{
			return true;
		}
	}
	return false;
};
 
pageDivs = document.getElementsByTagName('div');
 
// Delete application divs
for(var i = 0; i < pageDivs.length; i++)
{
	if( ( pageDivs[i].id.indexOf( 'box_app_' ) === 0 ) && ( !AppsToKeep.inArray( pageDivs[i].id ) ) )
	{
		pageDivs[i].style.display = 'none';
	}
}

Cols and Colgroups

By Ali Karbassi | August 16th, 2007 | Web Programming | 1 comment

Who loves working with tables in HTML or XHTML? <sarcasm> I know I do! </sarcasm> Recently I’ve been working with trying to get a column in a table to format correctly. It’s something very simple; I have 3 columns and X rows. I want the first column to be aligned left while the other columns to aligned right. Also, I want to style each column differently. Going through W3C’s HTML 4.01 Specification, I found column groups. After a few minutes of reading, it looked like exactly what I needed.

I grabbed W3C’s sample table to test with. Wow, that didn’t work. I dumped their code into a page (and fixed it so it validates with XHTML 1.0 Strict) so you can see it’s not what they say it should be. Surprisingly it doesn’t work the way they say it does.

I went looking for some answers and Mark J. Reed said it best:

First, you should know that due to the CSS rendering model, <col> and <colgroup> are both severely limited in what styling they support (at least outside of IE, which violates the CSS rendering model to provide them more power, breaking other things in the process). To be precise, there are only four things you’re allowed to do with a table-column (individual or group) style:

- set the background color
- set the width
- set up a border
- control visibility

That’s it. You can’t make a column bold or in a different font or give it centered text or any of the other things that seem perfectly reasonable before you dive into the detailed requirements of the CSS spec.

So what now? Will HTML 5.0 fix this? I rather not use some hack to do something that should work already.

Mac Tip #2 - Automatic iTunes Podcast Playlist

By Ali Karbassi | July 20th, 2007 | How To, OS X, Screencast, Windows |

I show you how to listen to your podcasts continuously. I hope you like it.

Mac Tip #1: Setting Two Sound Settings

By Ali Karbassi | July 11th, 2007 | How To, OS X, Screencast | 1 comment

Mac Tip #1: A very simple how to on how to set two different sound settings.

Presentations coming to Google Docs & Spreadsheets.

By Ali Karbassi | June 27th, 2007 | Google, Javascript | 5 comments

Taking a snoop into the new (mentioned everywhere) Google Doc & Spreadsheets javascript, I found an the icon for Presentation. Presentation is basically Keynote on Mac or Powerpoint on Windows.

The Presentation icon Presentation Icon might join the already implemented are the Google Document icon Document and Google Spreadsheet icon Spreadsheet.

It seems Google is pushing towards the Office App that has been rumored.

What is detroit.app.Application?

By Ali Karbassi | June 27th, 2007 | Google, Javascript | 1 comment

Recently Google Docs & Spreadsheets released a new version of their wonderful application. It’s a wonderful new interface and foreshadows what Google Docs is going to turn into.

Like always, I went snooping around to see what I could find. It’s usually fun to see what they didn’t implement yet. Taking a look at the javascript source (notice the link might change) I found something very interesting.

ac[_P].Ca = function()
{
   throw Error("[detroit.app.Application] Not implemented");
};

Apart from it being “Google Code” (no useful variable names), it shows that their is an application called “detroit.app” being developed. There is a Google Sales office in Detroit, but apart from that, I could not find anything related.

Most applications will have a codename before it’s final release. So now our part is to figure out what “detroit.app.Application” is.

Update: There seems to be many calls to “detroit.ui.” however. One of them is “detroit.ui.Pager”. The name “detroit” could be the codename for the next release.

Conky

By Ali Karbassi | March 6th, 2007 | How To, Linux, Ubuntu | 2 comments

I’ve been asked several times about how I set up my Conky. First a little about Conky. It is a light-weight system monitor, according to their website, but you can do much more. You can show basic system stats to grab RSS Feeds to show your Media Player (Amarok for me) status.

Now onto my configurations. Rather than explain each thing, I will show you how mine is set up (without the RSS, weather, and Amarok).

# UBUNTU-CONKY
# A comprehensive conky script, configured for use on
# Ubuntu / Debian Gnome, without the need for any external scripts.
#
# Based on conky-jc and the default .conkyrc.
# INCLUDES:
# - tail of /var/log/messages
# - netstat connections to your computer
#
# -- Pengo (conky@pengo.us)
#
 
# set to yes if you want tormo to be forked in the background
background no
cpu_avg_samples 2
net_avg_samples 2
 
out_to_console no
 
# Create own window instead of using desktop (required in nautilus)
own_window yes
own_window_type override
own_window_transparent yes
own_window_hints undecorated,below,sticky,skip_taskbar,skip_pager
own_window_colour brown
 
# Use double buffering (reduces flicker, may not work for everyone)
double_buffer yes
 
# Subtract file system buffers from used memory?
no_buffers yes
 
# fiddle with window
use_spacer yes
use_xft no
 
# Update interval in seconds
update_interval 2
 
# Minimum size of text area
# minimum_size 250 5
 
# Draw shades?
draw_shades no
draw_borders no
 
# Text stuff
draw_outline no # amplifies text if yes
draw_borders no
xftfont Monospace:size=9
xftalpha 0.8
uppercase no # set to yes if you want all text to be in uppercase
 
# Stippled borders?
stippled_borders 3
 
# border margins
border_margin 9
 
# border width
border_width 10
 
# Default colors and also border colors, grey90 == #e5e5e5
default_color gray
 
# Text alignment, other possible values are commented
#alignment top_left
alignment top_right
#alignment bottom_left
#alignment bottom_right
 
# Gap between borders of screen and text
gap_x 10
gap_y 10
 
# stuff after 'TEXT' will be formatted on screen
 
TEXT
${color white}$alignc$sysname $kernel on $machine
${color white}$alignc${exec whoami} @ $nodename
${color orange}INFORMATION ${hr 2}${color 000000}
${color 000000}Date: ${color white}${time %A,%d %B}
${color 000000}Time: ${color white}${time %k:%M:%S}${alignr}${color 000000}Uptime: ${color white}$uptime
 
${color orange}CPU ${hr 2}${color 000000}
Freq:${color white} ${freq}MHz ${alignr}${color 000000}Load:${color white} ${loadavg}${color 000000}
${color white}$cpubar
${cpugraph 000000 FCD116}
${color 000000}NAME             PID       CPU%      MEM%${color white}
${top name 1} ${top pid 1}   ${top cpu 1}    ${top mem 1}
${top name 2} ${top pid 2}   ${top cpu 2}    ${top mem 2}
${top name 3} ${top pid 3}   ${top cpu 3}    ${top mem 3}
${top name 4} ${top pid 4}   ${top cpu 4}    ${top mem 4}
${top name 5} ${top pid 5}   ${top cpu 5}    ${top mem 5}
${top name 6} ${top pid 6}   ${top cpu 6}    ${top mem 6}
${top name 7} ${top pid 7}   ${top cpu 7}    ${top mem 7}
${top name 8} ${top pid 8}   ${top cpu 8}    ${top mem 8}
${top name 9} ${top pid 9}   ${top cpu 9}    ${top mem 9}
${top name 10} ${top pid 10}   ${top cpu 10}    ${top mem 10}
 
${color orange}MEMORY ${hr 2}${color 000000}
RAM:${color white}   $memperc%   ${color white}${membar 6}${color 000000}
Swap:${color white}  $swapperc%   ${color white}${swapbar 6}${color 000000}
 
${color orange}DISK ${hr 2}${color 000000}
Linux   (${fs_size /})${color white} ${fs_bar 6 /}${color 000000}
Windows (${fs_size /media/windows})${color white}  ${fs_bar 6 /media/windows}${color 000000}
Storage (${fs_size /media/storage})${color white} ${fs_bar 6 /media/storage}${color 000000}
Web     (${fs_size /media/web})${color white}  ${fs_bar 6 /media/web}${color 000000}
 
${color orange}NETWORK (${addr eth0}) ${hr 2}${color 000000}
Down:${color white} ${downspeed eth0} k/s ${alignr}${color 000000}Up:${color white} ${upspeed eth0} k/s${color 000000}
${downspeedgraph eth0 25,140 000000 ff0000} ${alignr}${upspeedgraph eth0 25,140 000000 00ff00}${color 000000}
Total:${color white} ${totaldown eth0} ${alignr}${color 000000}Total:${color white} ${totalup eth0}${color 000000}
Inbound:${color white} ${tcp_portmon 1 32767 count} ${color 000000}Outbound:${color white} ${tcp_portmon 32768 61000 count}${alignr}${color 000000}Total:${color white} ${tcp_portmon 1 65535 count}${color 000000}

Create a list of installed packages

By Ali Karbassi | January 21st, 2007 | How To, Ubuntu |

Ever wanted to know what applications are actually installed on your system? Sure you can view the applications via the applications bar, but there are so many other applications not shown there.

Also, what if you have your system with all the applications you want and want to install them again on another pc (or after a reinstall)? Cynical shows us how to do that with a few simple steps.

To output this information to a file in your home directory you would use:

dpkg --get-selections > installed-software

Note: installed-software is actually just a text file. You can open it to view it, but don’t modify it if you don’t know what you’re doing. It might screw up the next step.

If you wanted to use the list to reinstall this software on a fresh Ubuntu setup or on another computer, just do the following steps:

dpkg --set-selections < installed-software
dselect
sudo apt-get autoremove
sudo apt-get autoclean