2010-10-28

How to make jQuery UI buttons shorter

I have been using jQuery and jQuery UI for a while now and they make it really easy to add fancy features and layout to a web app. However, one thing I didn't like was that the default appearance jQuery UI buttons is too tall for my taste. The jQuery buttons have lots of space above and below the button text, making them look square and blocky to me.

After playing around with it for a while I figured out how to adjust the height of jQuery UI buttons. Simply add the following to your CSS style sheet:

.ui-button-text-only .ui-button-text
{ padding-top: .1em;
padding-left: 1em;
padding-right: 1em;
padding-bottom: .2em; }

Just tweak the top and bottom padding until you like the way the buttons look. I had to make my bottom padding bigger than my top padding to make the button text look vertically centered.

I also had some buttons with little GIF images instead of text. jQuery had the images jammed up against the top of the button by default. To center the images I added this to my CSS stylesheet:

img {margin-bottom: -.25em;}

I could get away with just changing my img tag styles because these little GIFs were the only img tags on the whole page. If you have other img tags on your page you would need to give the button img tags their own class and apply this style to just that class.

2010-10-26

Google Chrome is particular about syntax of script tags

I was tearing my hair out because my jQuery UI code was working properly with Firefox and Safari but not with Google Chrome. When I looked at the Javascript console in Google Chrome I was getting an error like this:

Uncaught TypeError: Object # has no method 'datepicker'

Because it was working in Safari and Firefox, but not in Google Chrome, and because the error message sounded like some problem in the jQuery code and/or my other Javascript I spent hours trying to troubleshoot the problem. However, in the end the problem turned out to be with my script tags to reference the jQuery libraries:

<script src="/jquery-ui-1.8.5.custom/js/jquery-1.4.2.min.js" type="text/javascript"</script>

<script src="/jquery-ui-1.8.5.custom/js/jquery-ui-1.8.5.custom.min.js" type="text/javascript"</script>


Do you see the error in my syntax? I left off the right angle bracket after the type="text/javascript". For some reason Firefox and Safari don't care about that, but Google Chrome does. To make it even odder, Google Chrome didn't give me an error about problems loading a script, but instead an error about the execution of the script.

2010-10-22

Resources about designing web content for iOS devices (iPhone, iPod, iPad)

Apple has a thorough guide to developing web content for Safari on the iPhone, presumably most of it also applies to the iPad:

[iOS] Safari Web Content Guide

I haven't read all of this article yet but the title is promising:

The iPad Web Design and Development Toolbox

How to turn off php magic quotes on nearlyfreespeech.net

I recently set up a web app hosted on nearlyfreespeech.net that uses mysql_real_escape_string to to escape user input. I noticed the other day that an entry in that web app displayed an escaped single quote, which led me to suspect that nearlyfreespeech.net has PHP magic quotes turned on and my user input was being double escaped, which turned out to be correct. Here is how I turned off magic quotes for web app on nearlyfreespeech.net:

  • I connected to my nearlyfreespeech.net account via SSH.
  • I navigated to the public directory of my account (where the html and php files are).
  • At the command prompt I ran nano .htaccess to create a .htaccess file and open it in nano for editing
  • I put this in the .htaccess file: php_flag magic_quotes_gpc off
  • I saved the file, and voila, magic quotes were off!

2010-10-21

How to specify different CSS rules based on device screen size (i.e. for the iPad)

I was working on a web app where I wanted the appearance to be very different on my iPad than it was on my laptop. After some research I found this article:

Detecting device size & orientation in CSS

That describes how you can include code in a CSS stylesheet that will apply designated rules only if the device screen (or browser viewing area) meets certain criteria. For example (from the article):

@media only screen and (max-width: 999px) { /* rules that only apply for canvases narrower than 1000px */}

@media only screen and (device-width: 768px) and (orientation: landscape) { /* rules for iPad in landscape orientation */}

@media only screen and (min-device-width: 320px) and (max-device-width: 480px) { /* iPhone, Android rules here */}


CSS put inside the brackets in these examples would only apply if the specified criteria are met. Also, the CSS rules apparently work on the fly, so if the user resizes their browser screen the appropriate rules will be applied without refreshing.

I also found a reference article on these "media queries" for Firefox. Much of what is in this article applies to other browsers since I believe it is derived from the CSS 3 specification.

Media Queries

Note that this article only uses these media queries to select an alternate style sheet but as far as I can tell you can also use them to apply a block of rules enclosed in curly brackets after the query as shown in the example above and the first article.

There is also an Apple article that includes a section on conditional CSS:

Optimizing Web Content

After doing some experimenting, it appears that once a CSS property is specified the only way to remove it using a media query is to specifically specify a new value for the property. In other words, if you specify a bunch of properties for the ".main" class in your style sheet, and then in your media query block just specify:

@media only screen and (max-width: 999px) { .main {;}}

Then all the rules you specified for .main are still going to apply even when the media criteria is met because they were not individually countermanded.

I experimented around with different media queries to distinguish between my iPad and my laptop and in the end this seemed to work so that the rules were only applied on my iPad, and the rules were applied regardless of my iPads orientation:

@media only screen and (max-device-width: 1024px)
{/*max-device-width: 1024px seems to only select the iPad*/}

2010-10-20

Escaping square brackets in SQL Server queries from PHP

I have a PHP web app that pulls data from an SQL Server database using the ODBC functions. Earlier I come up with a PHP function to escape single quotes in user input by adding a single quote to each single quote (a single quote is the character you use to escape a single quote) as defense against (inadvertent) SQL injection (the web app is behind a firewall).

The other day I accidentally discovered that including text inside a pair of square brackets [like this] in user input that was added to a LIKE clause of a WHERE clause resulted in a huge data dump being returned by SQL Server. I did some Googling and discovered that characters enclosed in square brackets have some special meaning in SQL Server (I don't remember what it was). I first tried updating my PHP function to escape square brackets with single quotes, but that didn't work for some reason. Then I did some more research and discovered that the way to escape a square bracket in SQL Server is to enclose it in square brackets like this [[]. So I updated my PHP function to do this on user input and it worked to stop the data dumps when a user included something like [fred] in their input.

Writing the PHP to do this was tricky because if you just do a straight str_replace on each square bracket the second replace replaces some of the square brackets you added with the first replace and messes it all up. The way I solved this was to write my function to:

  • first replace the left square bracket with an arbitrary three character string that is unlikely to be in user input,
  • then replace on the right square bracket with []],
  • then do a third replace of my arbitrary three character string with [[].
And yes, I know I should be using stored procedures etc, and hackers can get past any escaping routine, etc, but this app is behind a firewall and I am only concerned about accidental SQL injection.

2010-10-03

SQL and sequences

I am working on an application that uses a sequence field to keep records in a specific order.

The first challenge was how to fill in a numbered sequence in the new sequence field without using auto-increment (the data table will contain a number of independent sequences for different sub-sets of records so I need to be able to multiple sequences in the same table).  I found the answer on this blog post:

How to Sequence each Sub-set of Records by David Soussan

I won't repeat that post here, but here is the SQL that I ended up with based on Mr. Soussan's technique.

This first SQL query creates a Temp table with Prov_ID and sequence number.

CREATE TABLE Temp
SELECT
    t1.Prov_ID, COUNT(t1.Prov_Sort_Num) AS sequence,
    t1.Prov_Sort_Num >= t2.Prov_Sort_Num AS flg
FROM
    tbl_Provisions AS t1
INNER JOIN
    tbl_Provisions AS t2 ON t1.Doc_ID = t2.Doc_ID
WHERE
    t1.Doc_ID = 1
GROUP BY
    t1.Doc_ID,
    t1.Prov_Sort_Num, flg
HAVING
    flg = TRUE
ORDER BY
    t1.Prov_Sort_Num

Then this second SQL query updates tbl_Provision using the sequence numbers from the newly created Temp table.
UPDATE
    tbl_Provisions AS t1
JOIN
    Temp AS t2 ON t1.Prov_ID = t2.Prov_ID
SET t1.Prov_Sequence = t2.sequence

The next issue was how to make sure that gaps and duplicates didn't end up in the sequence for each sub-set of records?  I found the solution to the issue of detecting gaps in this blog post:

Sequence gaps in MySQL by Sameer

I still don't fully understand how Sameer's SQL works, but it does indeed work reliably.  Here is the SQL I ended up with based on Sameer's technique:

SELECT
    a.Prov_Sequence + 1 AS start,
    MIN(b.Prov_Sequence) - 1 AS end
FROM
    tbl_Provisions AS a,
    tbl_Provisions AS b
WHERE
    a.Prov_Sequence < b.Prov_Sequence
   AND
      a.Doc_ID=$Doc_ID
   AND
      b.DOC_ID=$Doc_ID
GROUP BY
   a.Prov_Sequence
HAVING
   start < MIN(b.Prov_Sequence)
This returns a two column table with each row giving the beginning of a gap in the Start column and the end of that gap listed in the End column.