9
votes

Let's say I'm developing an iPhone app that is a catalogue of cars. The user will choose a car from a list, and I will present a detail view for the car, which will describe things like top speed. The detail view will essentially be a UIWebView that is loading an existing HTML file.

Different users will live in different parts of the world, so they will like to see the top speed for the car in whatever units are appropriate for their locale. Let's say there are two such units: SI (km/h) and conventional (mph). Let's also say the user will be able to change the display units by hitting a button on the screen; when that happens, the detail screen should switch to show the relevant units.

So far, here's what I've done to try and solve this.

The HTML might look something like this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" lang="en-US">
<head>
<title>Some Car</title>
<link rel="stylesheet" media="screen" type="text/css" href="persistent.css" />
<link rel="alternate stylesheet" media="screen" type="text/css" href="si.css" title="si" />
<link rel="alternate stylesheet" media="screen" type="text/css" href="conventional.css" title="conventional" />
<script type="text/javascript" src="switch.js"></script>
</head>
<body>
<h1>Some Car</h1>
<div id="si">
<h2>Top Speed: 160 km/h</h2>
</div>
<div id="conventional">
<h2>Top Speed: 100 mph</h2>
</div>
</body>

The peristent stylesheet, persistent.css:

#si
{
    display:none;
}

#conventional
{
    display:none;
}

The first alternate stylesheet, si.css:

#si
{
    display:inline;
}

#conventional
{
    display:none;
}

And the second alternate stylesheet, conventional.css:

#si
{
    display:none;
}

#conventional
{
    display:inline;
}

Based on a tutorial at A List Apart, my switch.js looks something like this:

function disableStyleSheet(title)
{
    var i, a;
    for (i = 0; (a = document.getElementsByTagName("link")[i]); i++)
    {
        if ((a.getAttribute("rel").indexOf("alt") != -1) && (a.getAttribute("title") == title))
        {
            a.disabled = true;
        }
    }
}

function enableStyleSheet(title)
{
    var i, a;
    for (i = 0; (a = document.getElementsByTagName("link")[i]); i++)
    {
        if ((a.getAttribute("rel").indexOf("alt") != -1) && (a.getAttribute("title") == title))
        {
            a.disabled = false;
        }
    }
}

function switchToSiStyleSheet()
{
    disableStyleSheet("conventional");
    enableStyleSheet("si");
}

function switchToConventionalStyleSheet()
{
    disableStyleSheet("si");
    enableStyleSheet("conventional");
}

My button action handler looks something like this:

- (void)notesButtonAction:(id)sender
{
    static BOOL isUsingSi = YES;
    if (isUsingSi)
    {
        NSString* command = [[NSString alloc] initWithString:@"switchToSiStyleSheet();"];
        [self.webView stringByEvaluatingJavaScriptFromString:command];
        [command release];
    }
    else
    {
        NSString* command = [[NSString alloc] initWithFormat:@"switchToConventionalStyleSheet();"];
        [self.webView stringByEvaluatingJavaScriptFromString:command];
        [command release];
    }
    isUsingSi = !isUsingSi;
}

Here's the first problem. The first time the button is hit, the UIWebView doesn't change. The second time it's hit, it looks like the conventional style sheet is loaded. The third time, it switches to the SI style sheet; the fourth time, back to the conventional, and so on. So, basically, only that first button press doesn't seem to do anything.

Here's the second problem. I'm not sure how to switch to the correct style sheet upon initial load of the UIWebView. I tried this:

- (void)webViewDidFinishLoad:(UIWebView *)webView
{
    NSString* command = [[NSString alloc] initWithString:@"switchToSiStyleSheet();"];
    [self.webView stringByEvaluatingJavaScriptFromString:command];
    [command release];
}

But, like the first button hit, it doesn't seem to do anything.

Can anyone help me with these two problems?

1
Irrelevant, but you can simply the 3 ObjC statements into one: [self.webView stringByEvaluatingJavaScriptFromString:@"switchToSiStyleSheet();"];kennytm

1 Answers

2
votes

You've probably long ago figured this out but since this is the best page on this topic on the web I'll answer for the sake of completeness.

You were very close. All you need to do is add an initial call to your function in your HTML head.

<head>
<title>Some Car</title>
<link rel="stylesheet" media="screen" type="text/css" href="persistent.css" />
<link rel="alternate stylesheet" media="screen" type="text/css" href="si.css" title="si" />
<link rel="alternate stylesheet" media="screen" type="text/css" href="conventional.css" title="conventional" />
<script type="text/javascript" src="switch.js"></script>
<script type="text/javascript">switchToSiStyleSheet();</script>
</head>