Rails pattern: trim spaces on input

May 8th, 2009 by Scott Moonen

Problem: Your Rails application accepts user input for a number of models. For many or most of these fields, leading and trailing spaces are a significant inconvenience — they cause problems for your validators (email address, phone number, etc.) and they cause normalization and uniqueness problems in your database.

Solution: Just as the Rails ActiveRecord class uses methods like belongs_to and validates_format_of to define model relationships and behaviors, create a new class method to express trimming behavior. There are a number of ways to do this; I will present one possibility that I have used in my own code. I created a file lib/trimmer.rb with the following contents:

module Trimmer
  # Make a class method available to define space-trimming behavior.
  def self.included base
    base.extend(ClassMethods)
  end

  module ClassMethods
    # Register a before-validation handler for the given fields to
    # trim leading and trailing spaces.
    def trimmed_fields *field_list
      before_validation do |model|
        field_list.each do |n|
          model[n] = model[n].strip if model[n].respond_to?('strip')
        end
      end
    end
  end
end

Then I write the following in my models:

require 'trimmer'
class MyModel < ActiveRecord::Base
  include Trimmer
  . . .
  trimmed_fields :first_name, :last_name, :email, :phone
  . . .
end

While this makes the behavior available to particular models explicitly, you may prefer to make this behavior available to all of your models implicitly. In that case, you can extend the ActiveRecord::Base class behavior by adding the following to config/environment.rb:

require 'trimmer'
class ActiveRecord::Base
  include Trimmer
end

If you do this, the trimmed_fields class method will be available to all of your models.

Tags: , , , ,

Everything you need to know about website design

January 30th, 2009 by Scott Moonen

HT: Jon Barlow

Tags:

My experience with Django and Rails

January 9th, 2009 by Scott Moonen

I’ve had the opportunity to work on both Django and Rails frameworks recently as part of one project.  The core application for the church administrative tools that I am working on is written in Rails, while the church guest follow-up application that I am responsible for is written in Django.  Why two separate stacks?  GuestView began its life independently from Gospel Software, and I chose Django there because of my familiarity with Python.  Three developers are sharing responsibility for the core of Gospel Software, however, and we chose Rails as the most reasonable lingua franca.

What follows are my personal opinions and observations.  These are mostly aesthetic or other value judgments, and I offer them simply for your consideration.

Language

I’ve used the Python programming language for a number of years and like it a lot.  I particularly enjoy its functional aspects, although lately I’ve become more of a fan of using list comprehensions and generator expressions wherever possible compared to map() and filter() with lambdas.  Compared to Python, Ruby has much more powerful functional capabilities, although some things don’t feel natural to me (Ruby’s design choice to not require parentheses to denote function invocation means that you must use .call to call a lambda, which feels clunky).  There are also some cases in Ruby where choosing one of several alternative forms of an expression can have a significant impact on your performance.  Lambdas seem particularly costly in Ruby as of version 1.8.

Overall I think the languages are fairly on par.  Right now I prefer Python for aesthetic rather than technical reasons.  As I grow in familiarity with Ruby, and as it matures and its performance improves I think I may eventually grow to prefer it.

Object-Relational Mapping (ORM)

The Django ORM is very powerful and you can express complicated queries very efficiently using it.  Django queries are not executed until they are actually used, so you can construct your queries piecemeal, which helps in writing readable code.  Django also allows you some flexibility with adding custom SQL to your queries, but for anything complicated I’ve found that I have to break down and write my own SQL.

Rails 2.1 introduced the ActiveRecord named_scope functionality.  Prior to this Rails was significantly lacking compared to Django’s expressive power for query construction, but named_scope pretty much evens the playing field.  And for complicated queries, which you will surely face in any real-world project as you seek to tweak performance, ActiveRecord gives you a degree of control over your SQL that really puts Django to shame.

Both Django and Rails seem to have adequate support for PostgreSQL, my database of choice.

URLs

Django lets you express your URLs using regular expressions; Rails accomplishes this using routes.   I personally prefer Django’s method, but both work well enough.

Templates

While Rails’ Embedded Ruby allows you to include arbitrary code in your templates, Django’s template engine is much more spartan.  It provides ways of getting at variables passed to the template, including objects, dictionaries, lists, and even methods.  And it has some simle control structures, but not covering the full expressive power of Python.  I yearned for a more powerful template language in Django at first.  But I found over time that the discipline of  a simple template language was helpful to me, forcing me to move any complicated behaviors to the controller (or “view” as Django calls it) which was in most cases the right thing to do anyway.

There are still some areas where I think the Django template language is lacking.  However, there is an open-source alternative to the Django template engine that is similar but sufficiently more powerful to meet my needs: Jinja2.

For me it is a toss-up between Embedded Ruby and Jinja2.

Performance

I suspect it’s common knowledge that Rails has a little ways to go in performance.  For our own purposes, I didn’t find too much difference in time measurements between Django and Rails.  However, Rails clearly has a much larger memory footprint than Django.

I was surprised to learn that even with a FastCGI or WSGI model, Django still opens and closes a database connection for each request.  While there may be technical reasons that the Django architecture requires this, it was still a surprise to me.  Django performance still seems on par with Rails in spite of this.  Interestingly, having Django use pgpool to connect to PostgreSQL didn’t improve my performance at all, perhaps because my application and database are currently located on the same host.

Console

Both Django and Rails allow you to run a REPL session for your application.  The Rails script/console command beats out Django hands-down, because Rails’ internal magic automatically imports pretty much everything you need.  In Django you still need to import any models or framework modules before you can use them.

Debugging

The Rails built-in log is enabled out of the box and is very handy.  Django provides logging functionality but you have to do a little extra work to enable it.  Rails wins out on logging.  Django is better at in-browser rendering of exception tracebacks.  Overall the handiness its logging means a slight win for Rails here for me.

Admin Application

Django’s admin application is truly its crown jewel.  If you need a private admin interface to your web application, Django will give you a very attractive and powerful interface almost entirely for free.  I’m not aware of any equivalent for Rails that even comes close to this.

Deployment

I’ve deployed Django using FastCGI and Rails using Mongrel.  Right now I am using Nginx to proxy to Mongrel, and to connect directly to the Django FastCGI instance.  Neither Django nor Rails seems to have a unique advantage or disadvantage in deployment.

Summary

I’ve spent more cumulative time with Django than with Rails, so I feel subjectively more at home with Django.  If I were going to write a small toy project, I’d choose Django mainly for ease and efficiency.  In fact, I took this route for the meal and potluck scheduler application that I recently wrote for Google App Engine.  GAE has many similarities with Django, and even allows you to run much of the Django stack on it.

However, for larger projects my current framework of choice is Rails.  With the named_scope functionality in Rails 2.1, ActiveRecord is finally on par with Django’s ORM.   And for any complicated queries ActiveRecord is superior to Django’s ORM.  While Django’s admin application is handy, I don’t make much use of it.  And while Rails falls slightly behind in performance and storage characteristics, I believe that Ruby and Rails will both continue to improve in this regard.

Tags: , , , , , , ,

PostgreSQL foreign keys and indexes

December 19th, 2008 by Scott Moonen

[PostgreSQL]If you’re a frequent user of MySQL, you may be familiar with the fact that all MySQL table constraints automatically create indexes for you.  This is true of the InnoDB foreign key constraints, for which “an index is created on the referencing table automatically if it does not exist.”

If you’re switching or considering a switch to PostgreSQL, you should be aware that not all PostgreSQL table constraints will automatically create indexes for for you.  In PostgreSQL, a UNIQUE or PRIMARY KEY constraint on one or more fields will implicitly create an index for you.  However, in PostgreSQL a FOREIGN KEY constraint will not automatically create an index for you.

For each of your foreign key constraints, you should evaluate whether you want to create an index.  You may want to do this for optimizing your own queries, but be aware that it can also help to speed up DELETE queries on the referenced table and UPDATE queries on the referenced field.  This is because any foreign key reference must be located to enforce whatever ON DELETE and ON UPDATE behavior is in effect for the constraint.

Tags: , , , , , , ,

SmugMug uploader

December 1st, 2008 by Scott Moonen

[SmugMug]I’ve written a small Python script to upload pictures to a SmugMug gallery. I love SmugMug and use it extensively for family photos. I’m using this script for my personal use because it’s much simpler and much less of a resource hog than a browser-based uploader, and also because it was a fun exercise to try out the SmugMug API. You can run this script as follows to upload one or more files:

python upload.py gallery-name picture-file-name . . .

On Windows I’ve set up a desktop shortcut pointing to the script, and I can drag and drop a pile of picture files onto the icon and it will upload away. I’ve tested it using both Python 2.5 using simplejson, and also using Python 2.6 which has simplejson built in. Earlier versions of Python may require you to change the import of hashlib to md5, and change the hashlib.md5() invocation to a md5.new() invocation. You’ll also need to modify the script to contain your email address and SmugMug password, and obtain a SmugMug API key for your own development use, but this is a very painless process. Here is the script:

#!/usr/bin/python

##########
# Requirements: Python 2.6 or
#               simplejson from http://pypi.python.org/pypi/simplejson
##########

EMAIL=’...’
PASSWORD=’...’

##########
APIKEY=’...’
API_VERSION=’1.2.0’
API_URL=’https://api.smugmug.com/hack/json/1.2.0/’
UPLOAD_URL=’http://upload.smugmug.com/photos/xmlrawadd.mg’

import sys, urllib, urllib2, urlparse, hashlib, traceback
try    : import json
except : import simplejson as json

if len(sys.argv) < 3 :
  print "Usage:"
  print "  upload.py  album  picture1  [picture2  [...]]"
  print
  sys.exit(0)

album_name = sys.argv[1]

def safe_geturl(request) :
  try :
    response = urllib2.urlopen(request).read()
    result = json.loads(response)
    if result[’stat’] != ’ok’ : raise Exception(’Bad result code’)
  except :
    print "Error issuing request"
    print "Request was:"
    print "  " + str(request)
    try :
      print "Response was:"
      print response
    except :
      pass
    traceback.print_exc()
    sys.exit(1)
  return result

def smugmug_request(method, params) :
  paramstrings = [urllib.quote(key)+’=’+urllib.quote(params[key]) for key in params]
  paramstrings += [’method=’ + method]
  url = urlparse.urljoin(API_URL, ’?’ + ’&’.join(paramstrings))
  return safe_geturl(url)

result = smugmug_request(’smugmug.login.withPassword’,
                         {’APIKey’       : APIKEY,
                          ’EmailAddress’ : EMAIL,
                          ’Password’     : PASSWORD})
session = result[’Login’][’Session’][’id’]

result = smugmug_request(’smugmug.albums.get’, {’SessionID’ : session})
album_id = None
for album in result[’Albums’] :
  if album[’Title’] == album_name :
    album_id = album[’id’]
    break
if album_id is None :
  print "That album does not exist"
  sys.exit(1)

for filename in sys.argv[2:] :
  data = open(filename, ’rb’).read()
  print "Uploading " + filename
  upload_request = urllib2.Request(UPLOAD_URL,
                                   data,
                                   {’Content-Length’  : len(data),
                                    ’Content-MD5’     : hashlib.md5(data).hexdigest(),
                                    ’X-Smug-SessionID’: session,
                                    ’X-Smug-Version’  : API_VERSION,
				    ’X-Smug-ResponseType’ : ’JSON’,
				    ’X-Smug-AlbumID’  : album_id,
				    ’X-Smug-FileName’ : filename })
  safe_geturl(upload_request)

print "Done"

I am donating this script to the public domain. You are welcome to use and modify it as you please without conditions. I’d appreciate hearing about your experience with this script or any changes and improvements you’ve made; please leave a comment. Thanks!

Tags:

Automatically minify your Javascript and CSS

August 17th, 2008 by Scott Moonen

For best performance, it is recommended that you minify the Javascript and CSS that your web application uses.  What this involves is removing all unnecessary whitespace and comments.  So, for example, the following CSS:

body
{
  margin: 5px 10px 10px 10px;
  font-family: arial;
}

would look like this after being minified:

body{margin:5px 10px 10px 10px;font-family:arial;}

And similarly for Javascript. It is common to configure your server to perform GZip compression on files that it serves, including Javascript and CSS, and this can significantly reduce the time that it takes for browsers to load your pages. But minification when used with GZip usually helps to compress the files just a little bit further. And unlike GZip, which only compresses the file only as it is sent over the internet, minification compresses the file as it is seen by a browser. This allows the browser to parse it faster; additionally, smaller files are more likely to be cached by the browser.

It is common to manually minify your Javascript and CSS as part of deploying your application, saving a minified copy on your server either manually or as part of an automatic deployment script. But it is also possible to create custom Apache output filters to perform the minification for you. This gives you the best of both worlds — you can edit your files directly without their being minified, but you don’t have to engineer a minification process for when you deploy your application. Here’s how to do it, first for Javascript and then for CSS.

Javascript

  1. Ensure you have the Apache mod_ext_filter extension installed.

  2. Download the jsmin.py Python script from Douglas Crockford’s website. (There are also other languages available.)  Save it in your Python installation’s site-packages folder (possibly /usr/lib/python2.x/site-packages/).

  3. Add the following lines to your main Apache config file (httpd.conf, apache2.conf, etc.):

    <IfModule mod_ext_filter.c>
      ExtFilterDefine jsmin \
                      mode=output \
                      intype=application/x-javascript \
                      outtype=application/x-javascript \
                      cmd="/usr/bin/python /usr/lib/python2.4/site-packages/jsmin.py"
    </IfModule>
  4. Add the following statement to the context where you would like to minify your Javascript files (you can place this in your server config, but also within a virtual host configuration, a directory directive, or even a .htaccess file if FileInfo overrides are allowed):

    AddOutputFilter jsmin js

    This will cause all files with extensions ending in .js to be run through the Javascript minify filter before being sent to a browser. If you have some Javascript without the .js extension, you can add additional extensions, or you can use the AddOutputFilterByType directive instead to apply the filter to any content with the application/javascript MIME type. With appropriate mod_expires directives you can cause these files to be cached for a long time by browsers, thereby ensuring that the minify filter is not run more than necessary.

For debugging purposes you should ensure that the minify filter is applied only to your production server and not to your development server. Until you have verified the correctness of your Javascript it will be harder to locate Javascript errors within minified code!

CSS

  1. Ensure you have the Apache mod_ext_filter extension installed, as above.

  2. Install the cssmin Ruby gem:

    gem install cssmin
  3. Add the following lines to your main Apache config file (httpd.conf, apache2.conf, etc.):

    <IfModule mod_ext_filter.c>
      ExtFilterDefine cssmin \
                      mode=output \
                      intype=text/css \
                      outtype=text/css \
                      cmd="/usr/bin/ruby -e 'require \"rubygems\"; require \"cssmin\"; puts CSSMin.minify(STDIN)'"
    </IfModule>
  4. Add the following statement to the context where you would like to minify your CSS files (you can place this in your server config, but also within a virtual host configuration, a directory directive, or even a .htaccess file if FileInfo overrides are allowed):

    AddOutputFilter cssmin css

    This will cause all files with extensions ending in .css to be run through the CSS minify filter before being sent to a browser. If you have some CSS without the .css extension, you can add additional extensions, or you can use the AddOutputFilterByType directive instead to apply the filter to any content with the text/css MIME type. With appropriate mod_expires directives you can cause these files to be cached for a long time by browsers, thereby ensuring that the minify filter is not run more than necessary.

Tags: , , , , ,

Unobtrusive Javascript: Self-labeling text inputs

July 18th, 2008 by Scott Moonen

Some web sites have self-labeling text input boxes; for example, see the text box at the top right of the page on memberhub. When these self-labeling form fields are empty, they contain helpful text that labels or further explains their purpose, such as “Search” or “Enter your favorite color.” As soon as you click on these fields, the help text vanishes and you can type in a value.

Using unobtrusive Javascript (see our earlier introduction), we can add behavior to a text input element to automatically label it with this sort of help text contained within the element. We will take advantage of the title attribute of input elements to do this. The title element is already widely used in many browsers to provide help text in a tool-tip when you hover over an element with your mouse, and we will steal this title text from any input text field to use for self-labeling purposes. Here is a script that accomplishes that:

autolabel.js:
Event.onReady(function() {
  $$('input[type="text"][title]').each(function(inputElement) {
    var e = inputElement;
    var color = e.getStyle('color');
    var fontStyle = e.getStyle('fontStyle');

    if(e.value == e.title) {            // FF reload behavior.
      e.value = '';
    }

    var blank = !$F(e);

    var blurHandler = function(ev) {
      blank = !$F(e);
      if(blank) {
        e.setStyle({ 'color'     : 'darkgray',
                     'fontStyle' : 'italic' });
        e.value = e.title;
      }
    }
    e.observe('focus', function(ev) {
      if(blank) {
        if($F(e) == e.title) {
          e.value = '';
        }
        e.setStyle({ 'color'     : color,
                     'fontStyle' : fontStyle });
      }
    });
    e.observe('blur', blurHandler);
    blurHandler(null);

    Event.observe(e.form, 'submit', function(ev) {
      if(blank) {
        e.value = '';
      }
    });
  });
});

Here’s how to use it. Note that you need to include the Prototype and Low Pro Javascript libraries:

example.html:
<script src="/js/prototype.js" type="text/javascript"></script>
<script src="/js/lowpro.js" type="text/javascript"></script>
<script src="/js/autolabel.js" type="text/javascript"></script>
. . .
<input type="text" name="color" title="Enter your favorite color" />

How it works

The script first searches for all input elements in the document that are of type “text” and also have the title attribute. For each of these, it executes a function to add the self-labeling behavior to the element.  This function does a number of things:

  1. When you refresh a page in Firefox, as long as you don’t do a full reload, Firefox preserves whatever values were previously in form fields.  The function tests if the current value of the form field is equal to the title attribute (meaning that someone refreshed the page while the self-labeling description was present in the field, and if so, the function clears the form field.
  2. For all other purposes, the function uses the variable blank to track whether the field is blank and should have the label inserted.  We do this rather than comparing the field’s content to the title tag, in case the user actually types in the value of the title tag (for something like “Search”).
  3. The function adds a handler for the focus event (cursor enters field).  If the field is blank, it clears the label text so the user can enter their own text, and restores the field’s color and font style to their original values.  Otherwise, the field contains user text so it is left unchanged.
  4. The function adds a handler for the blur event (cursor leaves field).  If the field is blank, it remembers the fact that it is blank, sets the style of the field so that the text is italic and dark gray (you may modify this as you wish), and then inserts the title text.
  5. The function adds a handler for the submit event on the field’s form.  If the form is submitted and the field is blank, it will be cleared so that the correct value is submitted for the form contents.
Tags: , , , , , , , , , ,

Improving Firefox session restore

July 15th, 2008 by Scott Moonen

I use Firefox session restore regularly.  This saves all my open tabs whenever Firefox closes (or crashes) and restores them when it reopens.  Unfortunately, there are still cases where Firefox will forget my open tabs.  This happens, for example, when I close my main window, thinking that I’m closing Firefox, but then I realize that there is still a pop-up window open.  When I restart Firefox, that popup will be restored instead of my old tab list!

I have not yet found a way to recover the tabs.  What a sinking feeling this leaves you with!  My open tabs are sometimes the result of several weeks’ worth of browsing.  I’ve grown better at saving links using del.icio.us rather than holding them in open tags, and obviously I need to work harder at this.  But I often still have up to 20 tabs open at any given time, waiting to be read.

This happened to me again today.  So I resolved one more time to try to find a solution.  And I did!  I found and installed Tab Mix Plus (I installed the latest TMP development build).  This Firefox plugin remembers your sessions from more than just the most recently closed window.  So if you close your main window first but find a popup lingering, you can close the popup without worrying that you have lost the tabs from your main window.  What a relief!

Here are the settings that I chose in TMP:

  1. When you first enable Tab Mix Plus, it asks you whether you want to use the Firefox session restore feature.  The TMP session restore is much better than Firefox’s, so choose No.
  2. Go to Tools|Tab Mix Plus Options to choose other options.
    1. Click the “Events” icon.  On the “Tab Features” tab, un-check “Ctrl-Tab navigates tabs in the most recently used order.”  This will set Ctrl+Tab to behave the way it usually does in Firefox.
    2. Click the “Session” icon.
      1. Make sure that “Use Firefox’s built-in Session Restore feature” is not checked.
      2. Under “When Browser Starts”, select “Restore”.
      3. Under “When Browser Exits”, make sure “Save Session” is selected.

Tab Mix Plus provides additional control over your browser sessions.  Using the Tools|Session Manager menu, you can manually save sessions, and also restore older sessions.

Tags: , , , , , , , ,

Unobtrusive Javascript: Expandable textareas

July 8th, 2008 by Scott Moonen

Using unobtrusive Javascript (see our earlier introduction), we can add behavior to textareas to make them automatically expand or contract as text is entered into them. Here is a script that accomplishes that:

autosize.js:
Event.onReady(function() {
  $$('textarea').each(function(inputElement) {
    var textarea = inputElement;
    var initialHeight = textarea.getHeight();
    var currentHeight = -1;
    var currentTimer = false;
    var div = $div({id: textarea.id + '_hidden'});

    textarea.insert({'after': div});
    div.setStyle({'display'       : 'none',
                  'width'         : textarea.getWidth() ?
                                      (textarea.getWidth() + "px") :
                                      textarea.getStyle('width'),
                  'whiteSpace'    : 'pre-wrap',
                  'fontFamily'    : textarea.getStyle('fontFamily'),
                  'fontSize'      : textarea.getStyle('fontSize'),
                  'lineHeight'    : textarea.getStyle('lineHeight'),
                  'paddingTop'    : textarea.getStyle('paddingTop'),
                  'paddingLeft'   : textarea.getStyle('paddingLeft'),
                  'paddingRight'  : textarea.getStyle('paddingRight'),
                  'paddingBottom' : textarea.getStyle('paddingBottom'),
                  'marginTop'     : textarea.getStyle('marginTop'),
                  'marginLeft'    : textarea.getStyle('marginLeft'),
                  'marginRight'   : textarea.getStyle('marginRight'),
                  'marginBottom'  : textarea.getStyle('marginBottom'),
                  'borderTop'     : textarea.getStyle('borderTop'),
                  'borderLeft'    : textarea.getStyle('borderLeft'),
                  'borderRight'   : textarea.getStyle('borderRight'),
                  'borderBottom'  : textarea.getStyle('borderBottom')
                 });

    var timerHandler = function() {
      currentTimer = false;
      if(initialHeight == 0) {
        initialHeight = textarea.getHeight();
      }
      div.innerHTML = $F(textarea).replace(/&/g, '&amp;')
                                  .replace(/</g, '&lt;')
                                  .replace(/\n/g, '<br />') +
                      '<br />z';
      var newHeight = Math.max(initialHeight, div.getHeight());
      if(newHeight != currentHeight && newHeight != 0) {
        textarea.setStyle({ 'height': newHeight + 'px' });
        currentHeight = newHeight;
      }
    }
    var eventHandler = function(ev) {
      if(!currentTimer) {
        setTimeout(timerHandler, 250);
      }
    }
    textarea.observe('change', eventHandler);
    textarea.observe('keyup', eventHandler);
    timerHandler();
  });
});

Here’s how you would use it. You don’t need to include any explicit Javascript or even styling within your document; the script automatically locates all textareas and adds the stretch behavior to them. Note that you need to include the Prototype and Low Pro Javascript libraries:

example.html:
<script src="/js/prototype.js" type="text/javascript"></script>
<script src="/js/lowpro.js" type="text/javascript"></script>
<script src="/js/autosize.js" type="text/javascript"></script>
. . .
<textarea name="comment">blah blah . . .</textarea>

How it works

The script first searches for all textareas in the document, and then executes a function for each textarea to add the stretch behavior to the element. This function creates a hidden div element associated with the textarea, and copies much of the style information from the textarea to the div. Then, it associates a function with the onkeyup and onchange events for the textarea. This event handler function copies the textarea text into the hidden div, measures the size of the div, and adjusts the size of the textarea to fit the size of the div. This means that the textarea grows or shrinks (never smaller than its original size) based on the size of the text contained within it.

Additional notes

The onchange and onkeyup handlers don’t directly copy the text into the div and resize the textarea. I found that doing that immediately on every key press slowed typing down considerably. Instead, the event handlers set a timer to expire 1/4s after the textarea is changed, and this timer handler itself does the resizing. I do not notice any lags in typing responsiveness with this approach.

The timer handler remembers the last measured size of the div so that it doesn’t need to resize the textarea if the div hasn’t changed in size. There are also some places where we check to be sure that a measured height is not zero — I found that IE6 sometimes reports a height of zero even though the DOM has loaded at the point that these functions are called.

If you have any unobtrusive Javascript code that hides your textareas, you should make sure that the autosize.js code runs before your textareas are hidden, so that it can measure their size while they are still visible. We’ll consider something like this in a later post, where you can have some text on your page with an edit link that automatically reveals a textarea to edit the text’s content.

Limitations

For unknown reasons, IE6 doesn’t seem to correctly report the fontFamily for an unstyled textarea. In cases where the textarea is clearly a monospace font, IE6 will report the body’s fontFamily (e.g., ‘arial’) instead of ‘monospace’ when retrieving the textarea’s fontFamily style. The result of this is that the div’s styling doesn’t match the textarea’s styling, and so the textarea will not necessarily be sized properly if it holds a lot of text. The workaround for this problem is to explicitly style your textareas using ‘font-family: monospace’; IE6 correctly reports the fontFamily in this case.

As indicated above, in some cases IE6 incorrectly reports a height of 0 for the textarea or div. The result of this is that in IE6 the textarea’s initial size may not stretch to fit its contents, but as soon as a character is typed into it it will expand to the correct size. I’m not aware of any universal workarounds for this. However, if you have textareas that are not auto-hidden on page load then you may be able to modify the code above so that instead of calling timerHandler() directly at DOM load time, it is scheduled to be called by a timer shortly thereafter.

Tags: , , , , , , , ,

Editor Color Scheme

July 7th, 2008 by Scott Moonen

Recently Slashdot featured a discussion of the best color scheme for programming. From that discussion I’ve discovered the zenburn color scheme, and have switched to it. I like the fact that the background is not stark black; the reduced contrast feels easier on my eyes.

Here are some resources I found from that discussion for color schemes:

What color scheme do you prefer for programming? There are several others at the vim color scheme test, above, that I’m also interested in trying out.

See also: Programming Fonts

Tags: , , , , , , ,