h1

Disabling the “enter key” on forms using JavaScript

November 16, 2007

In this post, I will discuss how to disable using the “enter key” to submit a a form. There are many subtle nuances in form behavior that many people don’t think about when using them. On most browsers, hitting the enter key while the focus is set to one of the form elements (text areas not included) the form will be submitted. If you have a submit button for the form (not required) the enter key actually simulates a click on the first submit button for the form.

In many cases, this behavior is beneficial and natural for form processing. Take for example the main google search page.

google.gif

When you type text in the search field and then hit the enter key, the form is submitted and google does it’s search magic. There is no need to click the “google search” button to submit the form. People typically don’t think twice about this behavior… its quite natural. For most small forms (less than 4 form elements) this works quite well.

On the other hand, If you have a form with a lot of form elements, or needs to behave differently, this behavior can be quite frustrating. Also forms with complex JavaScript form verification may want to force submission through a single source (pushing a button)

Think about entering a sales order form, form let’s say phpBMS.

salesorder.gif

There is a lot of information you need to enter before saving the record properly. When adding information, or new product line items, you might accidentally or instinctively hit the enter key. The default form submission would then immediately try to save the sales order record. This can be huge source of frustration for your users.

The Solution

First, this solution requires JavaScript. However, in most cases with complex forms, you might already be doing some sort of form verification.

Before going further, I will be discussing how to implement this using simple javascript. In phpBMS we use a modified MochiKit setup to implement JavaScript “listeners” on loading rather than putting the trigger code inside the HTML (but that’s an item I will discuss in a future post.)

1. Set the form’s onsubmit

We are going to set the form’s on submit to return false – i.e. it wont submit the form.

<form id="theform" action="myaction.php" method="post" onsubmit="return false">

This is going to make sure that hitting enter will never submit the form. Unfortunately, it also prohibits submit buttons from submitting the form (which actually is a good thing.) So the next thing we need to do is enable the user to actually submit the form.

2. Create a submit function/button

Because submit buttons are now not working, I tend to add a BUTTON tag and a corresponding JavaScript function that actually submits the form. The HTML looks like this:

<button onclick="submitForm()">Submit Form</button>

and for the JavaScript function, we grab the form element, and run the submit function directly. Make sure that the form element has an Id attribute set, or you cannot manipulate it in JavaScript

function submitForm(){
theform = document.getElementByID("theform");
theform.submit();
}

This now gives us a single point for form submission. If we wanted to do form verification, we could do it right form inside this function. What’s more, the stoopid enter key no longer holds sway over us.

Conclusions

Having the enter key submit a form is not always bad, but in certain circumstances, is not always good. Using some simple JavaScript tricks you can consolidate you exit points for the form and disable it from potentially ruining all the data a user has entered.

h1

Disabled vs Readonly Form Fields

November 8, 2007

I sometimes keep forgetting the important difference between a form field input that has the disabled attribute set and the read only attribute set. From a end-user stand point, both do similar things – prohibit the user form changing values of the form element. Unfortunately, that is where a lot of the similarity ends. From a purely academic stand point, you can read how the W3c explains the two attributes. While the differences may appear minor, it can raise some serious pitfalls when programming.

Implementing the Attributes

Let me preface this comparison with the way in which these attributes should be implemented in a typical XHTML compatible file. HTML syntax allows you to set an attribute without setting a value:

<input type="text" disabled>

But in XHTML, attributes must be have a value:

<input type="text" disabled="disabled" />

As in the example above, the disabled attribute gets the value of “disabled”. The read only attribute gets the value of “readonly”.

It is important to note that these values do not transport directly into the JavaScript DOM. If you were setting disabled or readonly via JavaScript, you would do it like so:

myInput.disabled = true; // or false
myInput.readOnly = true; // or false

Note also that in JavaScript attributes are case sensitive and that the readonly attribute is spelled “readOnly”.

Key Differences

The Disabled attribute

  • Values for disabled form elements are not passed to the processor method. The W3C calls this a successful element.(This works similar to form check boxes that are not checked.)
  • Some browsers may override or provide default styling for disabled form elements. (Gray out or emboss text) Internet Explorer 5.5 is particularly nasty about this.
  • Disabled form elements do not receive focus.
  • Disabled form elements are skipped in tabbing navigation.

The Read Only Attribute

  • Not all form elements have a readonly attribute. Most notable, the <SELECT> , <OPTION> , and <BUTTON> elements do not have readonly attributes (although thy both have disabled attributes)
  • Browsers provide no default overridden visual feedback that the form element is read only. (This can be a problem… see below.)
  • Form elements with the readonly attribute set will get passed to the form processor.
  • Read only form elements can receive the focus
  • Read only form elements are included in tabbed navigation.

Overcoming Shortcomings

Using the Disabled Attribute

If you really need the form element, and value passed to the processor and need to use the disabled attribute, try using a corresponding sister hidden form element to store the value that will be displayed:

<select name="typeDisplay" disabled="disabled">
<option value="SCH">Search</option>
<option value="SRT">Sort</option>
</select>

<input type="hidden" name="type" value="SCH" />

Just remember that if you are going to use JavaScript to disable/enable the form element, that you may want to provide additional code to move the current value of the disabled field to the hidden field companion.

Styling of disabled form elements can be a problem, as some browsers will simply override your styling. Thankfully most modern browsers (including IE 7) handle this well. However, this with the sometimes tricky hidden form element companion implementation guides me away from using this attribute as much as I would/should otherwise. If only there was a way to mark a disabled form element as successful, I would probably use the attribute more often.

Using the Read Only Attribute

This is the attribute I use more often as the changes I need make in order for them to function well is minimal. About the only thing I do is add a CSS class to the element so that it appears to the user as visually different from normal elements (hopefully implying that is not editable)

<input type="text" readonly="readonly" class="uneditable" />

If you turn the form element’s border from normal to a lighter version, along with accompanying text it works just fine. The fact that users can tab to the element usually has little or no impact on the user.

Unfortunately, because some elements cannot use the readonly attribute (like select boxes) You can’t always use the readonly attribute, and may have to use the disabled attribute.

Conclusions

The winner? The real answer is neither. There are really good reasons the smart people at the W3C implemented two distinct attributes, each with its own different behaviors. The key is to know when and how to use each of them.

h1

Pushing Different File Formats Using PHP to Internet Explorer

October 25, 2007

Recently, during phpBMS development, a common problem came out again in our code. Apparently, Internet Explorer has problems when feeding different file types (e.g. .pdf, .gif, and .jpg) to an IE browsers via php. We have several potential problems, and I wanted to document how we handled them:

Mime Type – Shmime Type

Older versions of IE (5.5 for example) had a hard time interpreting file types, sometimes ignoring the mime-type sent in the headers. If I had a php file titled PDFinvoice.php which sent a PDF file, along with appropriate headers identifying it as such, IE seemed to ignore them and look only at the extension in the URL. The result was PDF being displayed inline in the browser, in all it’s binary goodness – Ulk!

IE incorrectly displaying a PDF

The Solution

We added a URL variable to trick IE into thinking it was a PDF. The URL would look something like this:

PDFinvoice.php?ext=.pdf

And had some success in IE properly displaying the pdf. If you have other URL variables, make sure that ext variable is always on the end so that the total URL ends with the extension of the desired file type.

Caching

Caching is the bane of my web-application existence. I cannot tell you how many times I have made a change to phpBMS only to have my web browser not load the latest JavaScript file, or CSS in conjunction with the page itself. The problem is compounded when users set weird caching options (always use cache) that some browsers provide. I hope to assemble a separate post on the dangers and pitfalls of working with different browsing cache problems in the future.

This particular caching problem was not limited to IE, but it certainly was most prevalent in Internet Explorer. Depending on how caching was setup and what “zone” IE thought the site was in, generated PDFs were being cached so that a PDF for one invoice displayed an older cached version.

The Solution

We added another URL variable that was unique by just including a time stamp. The PHP code looks something like this:

echo 'PDFinvoice.php?t='.mktime().'&ext=.pdf';

so that the result URL looks a little like this:

PDFinvoice.php?t=1193314923 &ext.pdf

This seemed to throw all but the most stubborn caching options so that each invoice PDF is generated and displayed properly.

Session headers

That’s right, sending session cookie (or other cookie) information followed by content-type headers can throw off IE. What’s more, it’s resulting output is inconsistent at best. Sometimes we would get no output (blank page) other times it would spit out the raw file, and still other times it would work, or work with weird caching problems.

To solve this problem, we used the following PHP command before we started the session:

session_cache_limiter(‘private’);

The cache limiter defines which cache control HTTP headers are sent to the client. These headers determine the rules by which the page content may be cached by the client and intermediate proxies. For some reason IE needs to have the cache set to private in order to correctly read the content-type headers pushed by PHP.

At first I thought that a cache limiter set to ‘nocache’ was the ideal solution, but alas, that throws IE for an even worse loop.

Always remember to test web applications on as many prominent browsers as you can – it’s good practice. When doing so remember, that you will probably get the most wonky behavior out of IE.

h1

Backing Up MySQL dumps

October 23, 2007

On the heals of my un-deletion catastrophe, I thought It would be a good idea to automate a backup routine that would insure that I always have good MySQL dumps. Using logrotate, I crafted a config that will keep 30 days worth of compressed dump files. I made one for each MySQL schema (database) that I deemed critical.

I create two files in the /etc/logrotate.d, one fore each database, and it looked something like this

/var/backup/mysql/schema.sql {
rotate 30
daily
compress
create 644 mysql adm
dateext
maxage 30
prerotate
/usr/bin/mysqldump -u user -ppassword schema > /var/backup/mysql/schema.sql
endscript
}

It is interesting to note that since the DUMP files are just SQL Text, and repeatable data, they compress quite nicely (18 MB dump shrinks to 2.5MB) and since I have over 30 gigs on this 32 gig drive, I think I will be fine.

I use MySQLDump instead of backing up the actual files themselves because they are a bit more portable, and can always be manually checked, tweaked, or repaired if needed.

h1

Undeleting files from an ext3 partition

October 22, 2007

Recently, through a series of dumb – dumber – dumbest moves, I had accidentally deleted a MySQLDump backup file of a database on one of our Ubuntu servers. The sorted details of how and why my brain did such an idiotic move at this point are moot, but the solution isn’t. In a panic, I started researching how to undelete files from an ext3 file system.

Short Answer

Unless conditions are near-perfect, you can’t .

Long Answer

Ext3 uses journaling – which is, for the most part, good. It makes sure that if your system crashes the possibility for stability is high – much higher than with ext2. The problem is when you unintentionally issue commands, it makes sure it does them. In the case of deletion, it zeros the inodes – completely and forever breaking the link between the file pointer and the blocks the data resides in.

Tools You May Need

A live CD with lots of utilities

This is where Trinity Rescue Kit comes in. It’s a great distro that with tons of boot options including boot from the CD, Boot To Ram drive, and boot with extra SCSI support. It has a relatively small footprint with all sorts of tools including an NTFS undelete tool and…

Data Recovery Software

If the files are small-ish in size, of a common type, and not a lot of new data has been written after the deletion, there is a chance you can recover the files in their entirety. I suggest using this handy little application called PhotoRec. It does a nice job of trying to identify files by looking at the raw drive contents. It can even help with bad or damaged partitions

You may also want to look at the sourceforge project foremost, although I did not get a chance to evaluate it.

Tools don’t always help

In my case, my file was relatively large (18 MB) and segmented. My disk was not really damaged, so photorec was finding literally thousands of “files” (Since it looks only at the direct data, it could not tell the difference between good files currently on the system, and unlinked files.)

Also, I didn’t actually delete (rm) the file, I had overwritten it with a much smaller (3k) version of the file. This made finding the beginning of the file much harder.

To compound things, the data was on a Raid 0 SCSI partition, which even Trinity Rescue Kit could not Mount with the enhanced SCSI boot (although it could “see” it)

The Manual Search For Data Begins

About the only thing I had going for me was that my file was text. This allowed me to manually search the raw data for key phrases using grep, finding there byte position, and then using dd to grab chunks of the hard drive and sift through them piecing as much of the file as a I could back together again.

Use ‘grep’ To Search the Partition
  • Boot to the Live CD
  • grep the raw device (e.g. /dev/sdb1) .
  • Make sure to use the –binary-files=text options so that it will accurately give results.
  • Make sure to use the -b to show the byte position where it is located. In my case, I also wanted to see the context of the grep result to see if this was a chunk worth pulling so I used the -A, and -B options to show lines before
  • Send grep results to a file. My final grep command looked a little something like this:
    grep --binary-files=text -A 20 -b 'INSERT INTO `attachments`' /dev/sdb1 > results.txt
  • My results.txt file was saved to another external USB drive. Never use or continue writing to the partition you are searching.
  • If your partition is large, this search may take a while.
  • Note the byte position of any results. I was searching for text at the beginning of the file, so the byte position tells us where to start pulling from.
  • Be careful when viewing the results. You will most likely see a mix of text and binary data. Depending on how the binary data may be displayed, it might shoot your terminal window intto graphics mode, which makes everything (including the prompt and text you enter after into gibberish) If this happens, you can reset the mode, but it can be a pain as you might not always know what you are typing

Once you get the result of where the file starts, you can use dd to copy that chunk to another file on a different drive. If you remember files sizes, you can just guestimate how much data to pull. If you know the text at the end of the file, you can run a second grep to tell you the position at the end of the file.

Depending on the data you are looking for, you may also be able to use the strings command to find where your file is.

Use ‘dd’ To Extract the Information

First off, be CAREFUL when running dd. If you mix up your input and outputs you could end up overwriting or worse yet totally hoozling your partitions. dd parameters you will use are:

  • if=FILE — the source file (or in this case device) to pull from
  • of=FILE — the destination to write to
  • ibs=BYTE — The byte size of one block from the source (I set it to 512)
  • skip=BLOCK — The BLOCK number skipped to to start reading from. In this case this will be the byte offset provided by our grep results above divided by the ibs (512)
  • count=BLOCK — The number of blocks to read (file size of file you want to retrieve divided by the ibs (512)

My dd command looked something like this:

dd if=/dev/sdb1 of=/mnt0/homres/recover.sql ibs=512 skip=337452145 count=360000

But wait!, I’m not done. Once I had the file, I had to sift through it using a text editor and cut out any pieces that were left from other files (my SQL Dump was segmented – so there was disbursed binary data form other files in there), find out what was missing, and do a series of additional greps to try and find those missing parts.

In addition to being lucky that the file I was looking for was text, I had a good idea of the structure of the data, and what record counts for the tables should look like after reincorporating the dump file.

Using this method, and a not so recent backup, I was able to manually piece together about 98% of the data I had inadvertently hoozled. – It was no easy task, and there was still some data lost the alternative — well I still shutter just thinking about it.

I would like to also thank my father for helping me out with this. His knowledge is always invaluable and for me – calmed my nerves a bit.

Inadvertent Knowledge

  • grep searches using regular expressions – many might say “Dur… General Regular Expression Processor” But I thought it was a straight string search utility. COOL! Now if I could just find a dramatic use for it…
  • Not zeroing out your drive before formatting a partition leaves data on the drive. – I had parts of a windows installation left by DELL before they shipped the computer to me “unformatted.” This was over four years ago. It also made it harder for me to sift through the raw data.

How to avoid this in the future

Many of these following point might seem obvious, but for my benefit, I had to write them down to get them into my thick, stubborn skull.

  • Try not to code when your punchy-tired.
  • Make backups, and backups of backups, before handling sensitive data.
  • If you run the ext3 file system, you may want to install giis as a fail-safe. It will make backup of inodes with block positions of recently deleted files.
h1

Mac-ify My XP Box

October 19, 2007

Ok, so time got away from me today. In the last week, I found out how to unlock XP Themes. I had searched for a theme that was a little easier on my eyes than the blue candy XP, when I realized I really liked the MacOSX graphite look. I had always run my task bar at the top of my window (as opposed to the default bottom)

So here is what I did:

The Result

My XP Box

My desktop is not cluttered at all and I get a more consistent interface between my Mac Mini and My Dell XP box and no more bright candy blues and green (wheh.)

h1

And this blog starts… now!

October 18, 2007

Welcome to the Kreotek Developer’s Journal!

Basically I am going to fill this blog with web development findings for archiving and sharing purposes. This blog will focus on (but not be limited to) topics on:

  • LAMP (Linux, Apache, MySQL, and PHP)
  • Web Development (Browser Problems, CSS & Design tricks, etc…)
  • Python & XULRunner (I am reasearching creating a desktop APP)
  • Trials and Tribulations of Open Source projects

End of Line

Follow

Get every new post delivered to your Inbox.