iOS Monospace Font Bug – A JavaScript Fix

December 20, 2010

After struggling through trying to find solutions for the iOS monospace font problem, I was able to cobble together a JavaScript fix.

To summarize the problem: in fixed-width fonts on iOS, spaces, question marks, and hyphens/dashes all display wider than letters, numbers, and other symbols. Replacing the dashes with –es fixed them, but there was no HTML entity fix for question marks or spaces (all the special spaces display either wider or narrower than regular characters).

I was experimenting with different ways to try to get the characters the same width, and I was going to try wrapping the “bad” characters in a span so I could style them differently. What I found was that characters wrapped in a span display at a different width than either the “normal” or “bad” characters not in a span, so it didn’t serve my purpose. But, I also noticed that (almost) all characters (both “normal” and “bad”) displayed at the same width when they were placed into spans!

Incidentally, spaces still didn’t display at the right width, nor did any of the special space HTML entities. (It seemed inconsistent–spaces seemed OK on iPad, but not on iPhone.) The best solution I’ve found so far (and it’s not a good one for the sake of copy-pasting text) is to replace the spaces with an underscore, and style the spaces to be non-visible.

So a solution would go through my code to output, take all the text (non-HTML) characters, and wrap each of them in a span. This was easier on the client-side than the server-side, because the browser has already parsed my document into DOM objects, so it’s easy to tell what’s plain text characters.

The JavaScript function I wrote takes a node, and iterates through its child hierarchy. Whenever it finds a text node, it splits it into characters, wraps each in a span, performs the extra steps I described above for spaces, and then inserts these spans into the DOM in place of the original text node.

Another limitation of this setup is that it can’t be used for editing text in textareas–it can only be used for displaying text.

Note: this has been tested very little! No warranty it won’t erase all your data. If you find cases where it doesn’t work, and you can make it better, let me know and I’ll post the updated version here.

Download the source, or check out an example of it in action, which allows you to see the text before and after the fix is applied.


iPhone Development Options

March 9, 2010

Either I’m behind the times, or Apple isn’t great about communicating all the options out there for iPhone development. I just found out about Dashcode, an iPhone SDK for creating web apps with all the standard awesome iPhone widgets. It even lets your web app run offline! This being the case, I thought I’d put together a summary of the options you have for creating iPhone web sites/apps. Please comment if I’ve gotten anything incorrect, and help me out by providing better links =]

Web Site iPhone Site Offline Site App Store
Accessible y y y y
Other Mobile y y ? n
Offline n n y y
Zooming y n n n
App Store Approval n n n y
App Store Sales n n n y
iPhone Data n n n y
Push n n n y
  • Web Site – This refers to a regular web site, without any adjustments for the iPhone.
  • iPhone Site – This refers to a web site with some changes for the iPhone. It might be as simple as a few meta tags and CSS styles, or you might have to rewrite your views to be iPhone targeted. Either way, though, it’s not much effort. More Info
  • Offline Site – This refers to a webapp that’s set up to be able to run offline. If your users save your app to the home screen, everything on that page is saved as well, including JavaScript. If the app is set up to use a JavaScript-accessible local storage library, that data will be accessible as well. Apple has created an SDK called Dashcode that offers not only offline storage, but also easy drag-and-drop usage of regular iPhone UI widgets as well. More Info
  • App Store – This is what most people think of when they think of iPhone apps. These are written in Objective C using the iPhone SDK. They require App Store approval to be sold. More Info

IE Performance Issues Adding Dom Nodes

October 12, 2009

My app has a search screen that fetches the results via Ajax and displays them in a table. Worked fine in Firefox, but in IE there’s a slight processor jump for a second or so. Strange, but not a problem. The users of this app, however, use a remote desktop app to run IE to access it. And when they did the search, their CPU would hit 100% for 1-5 minutes, making the entire terminal completely unusable.

I agonized over different JavaScript fixes: removed a table JS widget, switched off of tables altogether, switched to innerHTML, used DocumentFragments. Nothing worked.

Then, on a whim, I disabled all the CSS files on the app, and it worked like a charm. As I narrowed it down, I discovered that some CSS I was using to emulate frames (non-scrolling header, footer, and sidebar) was the offending code.

Let’s step back and think about that one again. What caused the processor to hit 100% for 5 minutes was not JavaScript, but CSS.

Sigh. So, if you have an issue with IE hitting 100% processor load for any reason, don’t assume that JS is necessarily the problem. Try disabling your CSS and see if that fixes it.


Disable Form Field, Preserving Submit

August 25, 2009

The “disabled” attribute on an HTML form element prevents the field from being edited. Unfortunately, it also prevents the field from being submitted in the form. If you do need to submit the field even though it’s disabled, use the following instead of the disabled attribute:

this.event.addListener( field, “click”, function(e)
{
var targ;
if (e.target) targ = e.target;
else if (e.srcElement) targ = e.srcElement;
if (targ.nodeType == 3) // defeat Safari bug
targ = targ.parentNode;
targ.blur();
});

YAHOO.util.Event.addListener( field, “click”, function(e)

{

var targ;

if (e.target) targ = e.target;

else if (e.srcElement) targ = e.srcElement;

if (targ.nodeType == 3) // defeat Safari bug

targ = targ.parentNode;

targ.blur();

});

This will blur (deselect) the field as soon as you select it. Combine it with some gray styling and you’ve got a great form disabler.


JS Auto-Tab That Doesn’t Suck

July 7, 2009

Here’s a JavaScript auto-tab implementation that doesn’t have that most annoying of bugs: when you click or tab into a field that is already populated, it tabs to the next field, disallowing you from deleting or changing. This one only auto-tabs on keyup.

UPDATE: dag nabbit, I was wrong. Shift-tabbing back to the previous field doesn’t work right in Firefox. On the “var filter” line, add a 16 into the [0,8,9] list, making it [0,8,9,16], and you should be set.


Top Reasons Your YUI Widget Looks Messed Up

June 12, 2009
  1. You created the widget but didn’t call its render() method. When you create it, that seems to update some styles and DOM elements, but not all. Calling render() updates the rest.
  2. You tried to apply the widget to multiple elements, but, since they have the same ID, it was applied to the same element multiple times. This is like the Ghostbusters crossing the streams, and is very bad.

IE6 JavaScript error: “Expected identifier, string, or number”

May 20, 2009

Note to self: if your code works in FF, but ¬†you get the “Expected identifier, string, or number” error in IE6, this is probably caused by having a list with a comma after the last item. Remove the extraneous comma, and it should work.