Monthly Archives: June 2010

Do-it-yourself mobile optimization: A proposition

There are a lot of websites I visit on my phone that haven’t been optimized for smartphones.

BYU.edu (unoptimized) on a Palm Pre at 320x480

First of all, those websites bug me. Pinching and zooming and panning around just to find the tiny link I’m searching for gets old really fast.

So I have a proposition. I want a mobile app that will let me apply my own stylesheets to those websites. That way even though those webmasters refuse to optimize their site for me, I can still get an acceptable (read: usable) experience on their website from my phone.

Take BYU’s website for example. It was designed for a screen at least 985 pixels wide. That’s great on a computer, but it’s awful on a mobile screen that’s only 320 pixels wide.

Luckily, BYU’s web designers were smart enough to do almost all of the layout using CSS. This means that I can create a stylesheet of my own that will display only the stuff I want to see. For example, it could only show the Students and Route Y menus and hide the news feed and all the other links that I don’t care about.

The Web Developer add-on in Firefox will let me apply my own stylesheets to any website so I can make it look just how I want. Indeed, this sort of user modification of website styling was one of the core intentions of CSS in the first place. Users need not be at the mercy of webpage authors as far as presentation of content is concerned.

BYU.edu with custom user stylesheet (320x480)

At the right, you can see the results when I disabled all linked stylesheets and instead used my own user stylesheet. At 320 pixels, you still can’t see everything, but it’s a start.

It would be cool if this app were a Kynetx endpoint. That would allow me to write rule-based modifications of websites in the cloud, without having to store anything locally on my phone. It would be even cooler if that app would just modify content right my default browser.

But even if that doesn’t work out, it would be possible to create a mobile app that displays the web pages in an embedded browser and then applies my favorite stylesheets to them as they’re being loaded.

It would be really cool if all browsers (including mobile browsers) would just support this natively. Opera does. Why does no one else?

Maybe I’ll just go write this mobile app myself.

Getting Gabble to “Yam!”

I discovered Gabble this morning, a native Mac OS X client for Yammer. The interface is great, and it integrates seamlessly with Mac OS X. It offers threaded messaging, something the Adobe AIR client doesn’t do (even though it’s not quite as slick as the web application). It doesn’t artificially truncate URLs, meaning you can copy and paste URLs directly to/from the messages themselves without having to do any hoop-jumping or black magic.

It also uses Growl for its notifications.

The only catch is that you can’t use the default Yammer notification sounds. One of my friends particularly likes the one that says “Yam!” when a new message arrives.

I figured out a way to satisfy his “Yam!” fix.

Growl lets you customize notifications from individual applications, including specifying a sound that should play when a notification pops up. However, by default, only the typical Mac sounds are listed as options. But you can add a custom sound to that list if you put the sound file in ~/Library/Sounds.

Remember the Mac OS X program “say”? You can use it to create sound files as well. And if you use the voice “Cellos”, it sounds almost like the original “Yam!” sound from the AIR client. Run this command:

say -o ~/Library/Sounds/Yam.aiff -v Cellos yam

Now go to System Preferences and open up the Growl section. Click on Applications and then choose Gabble from the list. Click the Configure… button. You should now see an entry at the bottom of that list labeled “Yam.” Select that one and close Preferences.

There you go! Now you can have the goodness of a native Mac OS X Yammer client, message threading, and no annoyingly truncated URLs, all without sacrificing that beloved “Yam!” sound.

Enjoy!

Linux notifications for the Kynetx KRL command-line tool

This is a response to Mike Grace’s excellent post, Growl Notifications for Kynetx KRL Command Line Tool. The idea is entirely his; I’ve just implemented a solution for Linux. I recommend you go read his post so you know what this is all about.

Since Linux uses libnotify instead of Growl, it’s fairly simple to implement as similar solution to Mike’s on a Linux system.

You’ll need the libnotify-bin package installed. You can do that in the normal manner.

First, add the following to your ~/.bashrc file:

krl() {
  if [[ $1 == "commit" ]]; then
    command krl $@ | tee status.txt
    notify-send -i ~/.kynetx-x.png “KRL” “`cat status.txt`”
    rm status.txt
  else
    command krl $@
  fi;
}

This is basically creating a function that will run whenever you issue the “krl commit” command. It pipes the output of the KRL gem to a file and then uses the text of that file in the notification.

You can download the Kynetx “X” image to your home directory if you like with the following command:

curl https://kynetx-apps.s3.amazonaws.com/krl-commit-growl-notify/kynetx-x.png > ~/.kynetx-x.png

That’s it! Have fun!

XHR AJAX doesn’t work across subdomains

I’ve finally come to the bottom of a vexing problem: XMLHttpRequest AJAX calls only work on the same subdomain.

In addition, cookies are passed to their proper places as you would expect, and redirects are handled correctly by the browser. But the ultimate result that the webpage making the AJAX request and the web service returning the data must be on the same subdomain is a little disappointing.

It’s possible to overcome this with JSONP or by having the web service wrap its return value in a callback function. But for security reasons, we decided that this was not the best model for our web services and are seeking other solutions.


If you’re interested in the technical details of how I came to these conclusions, I’ll describe them now.

Protocols and subdomains

First of all, I set up my /etc/hosts file to have localhost.byu.edu and snay2.byu.edu point back to 127.0.0.1 for testing purposes. I also set up my local Tomcat 6 to take requests both on port 8080 (for normal HTTP) and on 8443 (for HTTPS) to test the different protocols. These are the results:

  • When calling from a page on the HTTP side, access to services on HTTPS is disallowed. That is, the jQuery AJAX call returns an HTTP status code of 0. Firebug reveals that the request is actually made and that a response comes back, but the browser refuses to process it.
  • The reverse is also true: When calling from a page on HTTPS, access to services on HTTP is disallowed.
  • AJAX calls can’t be made across subdomains. When I call from localhost.byu.edu to localhost.byu.edu the request succeeds (and returns data). But when I call from snay2.byu.edu to localhost.byu.edu (or the reverse), the HTTP status code is 0 and the browser won’t let jQuery handle the data that comes back.

The odd thing about all of this is that Firebug is showing that the requests were indeed made and that they come back with data. jQuery simply won’t invoke the callback function I gave it to use the data. If anyone knows why that is, please enlighten me.

Redirects and cookies

The other two issues that seemed to be involved in the problem (albeit indirectly) were redirects and cookies. CAS (Central Authentication Service) makes extensive use of HTTP redirects (usually a 302) to handle authentication. When initially trying to debug these web service calls, it was unclear whether the redirects simply weren’t being handled by jQuery or if there was something else going on. A few tests with PHP scripts allowed me to confirm that jQuery AJAX does indeed handle redirects properly.

The first PHP script makes an AJAX request (note that these scripts are all on the same subdomain):

test.php:

<html>
<head>
  <title>Test</title>
  <script src=”jquery.tools.customized.min.js” type=”text/javascript”></script>
  <script type=”text/javascript”>
    var callService = function() {
      var request = ‘http://www.scnay.com/coe/services/landing.php’;
      $.get(request, gotResponse);
    };

    var gotResponse = function(data) {
      alert(“Got the results!! ” + data);
    };

   </script>

</head>
<body>
  <input type=”button” onclick=”callService();” value=”Call service” />
</body>
</html>

The second one sends a redirect to the browser:

landing.php:

<?php
header(‘Location: http://www.scnay.com/coe/services/real.php’);
?>

The third script returns some data:

real.php:

<?php
echo ‘Success!’;
?>

Clicking the button from test.php sends a request to landing.php. The redirect is properly handled and the string “Success!” is returned from real.php. Redirects work!

The other issue in question was cookies. CAS stores a TGT cookie on the cas.byu.edu domain so that the user doesn’t have to re-login every time a CAS-secured request is made. The question was whether that TGT cookie was getting passed to cas.byu.edu when the request was made there, either explicitly or through a redirect.

To test this, I first modified test.php to set a cookie. Then I modified real.php to return “Success!” only if the cookie was found and otherwise to return an error message.

This simple test showed that the cookies are indeed passed along as would be expected.


Conclusion

While the answer is not wholly satisfying (XMLHttpRequest AJAX calls can’t be made across subdomains without using JSONP, callbacks, or proxies), at least we now know what’s going on. Now to search for a reasonable solution…

Do you have experience with this? Any suggestions I might try?