James Gardner


Orange GPRS via Samsung Bluetooth on Debian

Posted in Desktop Software, Debian, Hardware by thejimmyg on the August 26th, 2007

I have a Samsung SHG-E250 mobile phone on Orange pay as you go in the UK. I’ve also got a Belkin USB bluetooth dongle model F8T013xx1 and I wanted to be able to access the internet from my Debian laptop over GPRS. This article is a working solution but there is a lot about the intricacies of what’s going on that I don’t understand so whilst I hope this is useful, I make no guarantees!

Paying a Provider

The first challenge is the cost. Standard tariffs is £4 per MB which is frankly outrageous. There is a handy trick you can use if you want to use GPRS on Orange. If you have Pay As You Go in the UK you get unlimited GPRS data until midnight that day for just £1. It is called an “Orange Extra” and you and rather than internet access it is called “Orange World”. From your phone dial 450 free. Then choose options 3111 followed by:

1 - Unlimited data until midnight for £1
2 - 4Mb total valid for 30 days for £4
3 - A week’s unlimited access for £5

The amount is taken off your Pay As You Go Balance immediately and you are asked to hold until the service has gone through and you are sent a txt after a few seconds confirming you can start using the service. You can check your remaining balance, including the Orange World access you just bought by dialing 453. You can use the unlimited data for £1 extra each day if you like.

Setting up Bluetooth on the Desktop

Once the financial side is sorted out you need to set up your connection. If you have installed the standard Gnome desktop then the “bluez” Bluetooth stack will already be set up. Just plug the dongle in and you can start pairing the devices. Right click the Bluetooth icon on the gnome panel which appears when you plug in the Bluetooth dongle. Choose preferences, give your computer a sensible name and choose “Visible and connectable for other devices”. My computer is called dirac-0 which you’ll see in some of the output later on.

On your phone turn on Bluetooth and select scan for devices to pair with the computer. You’ll be asked to enter a 4 digit pin. Choose something memorable. A message box will pop up on the desktop. Click it, enter the PIN and the devices will be bonded. That’s the easy bit, now time to test the connection.

Playing with Bluetooth

Scan for devices:

james@dirac:~$ sudo hcitool scan
Scanning …
    00:1A:8A:86:6D:CE    SGH-E250

Find out about a device:

james@dirac:~$ sudo hciconfig -a
hci0: Type: USB
        BD Address: 00:0A:3A:7A:E6:53 ACL MTU: 1017:8 SCO MTU: 64:0
        UP RUNNING PSCAN
        RX bytes:10237 acl:210 sco:0 events:217 errors:0
        TX bytes:4609 acl:210 sco:0 commands:71 errors:0
        Features: 0xff 0xff 0×8d 0xfe 0×9b 0xf9 0×00 0×80
        Packet type: DM1 DM3 DM5 DH1 DH3 DH5 HV1 HV2 HV3
        Link policy: RSWITCH HOLD SNIFF PARK
        Link mode: SLAVE ACCEPT
        Name: ‘dirac-0′
        Class: 0×3e0100
        Service Classes: Networking, Rendering, Capturing, Object Transfer, Audio
        Device Class: Computer, Uncategorized
        HCI Ver: 2.0 (0×3) HCI Rev: 0×4102 LMP Ver: 2.0 (0×3) LMP Subver: 0×430e
    Manufacturer: Broadcom Corporation (15)

Ping a device:

james@dirac:~$ sudo l2ping 00:1A:8A:86:6D:CE
Ping: 00:1A:8A:86:6D:CE from 00:0A:3A:7A:E6:53 (data size 44) …
44 bytes from 00:1A:8A:86:6D:CE id 0 time 37.50ms
44 bytes from 00:1A:8A:86:6D:CE id 1 time 75.61ms
44 bytes from 00:1A:8A:86:6D:CE id 2 time 66.62ms
3 sent, 3 received, 0% loss

Connecting for Dial Up Networking

Once all that is working nicely it is time to search for a device with Dial Up Networking:

james@dirac:~$ sdptool search DUN
Inquiring …
Searching for DUN on 00:1A:8A:86:6D:CE …
Service Name: Dial-up Networking
Service RecHandle: 0×10002
Service Class ID List:
  ”Dialup Networking” (0×1103)
Protocol Descriptor List:
  ”L2CAP” (0×0100)
  ”RFCOMM” (0×0003)
    Channel: 3
Profile Descriptor List:
  ”Dialup Networking” (0×1103)
    Version: 0×0100

As you can see the device 00:1A:8A:86:6D:CE (which you know is an SGH-E250 phone from the sudo hcitool scan command you ran above) supports RFCOMM and on channel 3. It is important to make a note of the channel because you’ll need it for the next command:

james@dirac:~$ sudo rfcomm bind 0 00:1A:8A:86:6D:CE 3
james@dirac:~$ sudo rfcomm show 0
rfcomm0: 00:1A:8A:86:6D:CE channel 3 clean

This tells you that you now have your Bluetooth phone connected on /dev/rfcomm0. If you leave it too long after binding before trying the show command you might see this:

james@dirac:~$ sudo rfcomm show 0
rfcomm0: 03:00:00:00:00:00 channel 1 closed

In which case release and then bind again:

james@dirac:~$ sudo rfcomm release 0
james@dirac:~$ sudo rfcomm bind 0 00:1A:8A:86:6D:CE 3
james@dirac:~$ sudo rfcomm show 0
rfcomm0: 00:1A:8A:86:6D:CE channel 3 clean

Now you have a Bluetooth connection you are ready to set up your GPRS connection.

Testing Your Connection Settings

If you already know all the settings you need to use you can skip this bit and go straight to setting up the GPRS connection via PPP. Installing and playing with minicom isn’t strictly necessary, it will just help you track down problems more quickly.

First you’ll need a tool such as minicom.

james@dirac:~$ sudo apt-get install minicom

You need to add your user to the dialout group to use minicom as a non-root user.

Then create a configuration file:

sudo minicom -s

You get shown an options screen. In the “Serial port setup“ screen choose “A“ to make the

A - Serial Device : /dev/rfcomm0

Then choose “E“ to change the “Bps/Par/Bits“ to “57600 8N1“. You do this by pressing “H“ and “Q“. You can try 115200 later if 57600 works. Press ““ to go back to the main menu and choose “Save setup as..“ to save the settings as “bluetooth.dfl“ before exiting.

To use your new configuration type:

minicom bluetooth.dfl

If you have any problems it is worth running “sudo rfcomm show 0“ again to check you still have a clean connection. If not, release the connection and bind to the channel again first.

When you run this command for the first time the phone will ask you something like: “DUN connect with dirac-0″. Choose yes.

Once you are connected you’ll see a screen like the one below. Type the following to initialise GPRS:

at
ate1
at+cgdcont=1,”IP”,”orangeinternet”,”",0,0
atdt*99#

After each line you should see an OK message except after the last line when you should see a CONNECT as shown below.

If you were able to connect successfully, great. If not you might need to search on the internet for the correct settings for your provider and phone. In particular the atdt*99# line might need changing.

Setting up PPP

If you want your phone to bind automatically you can edit your /etc/bluetooth/rfcomm.conf so it looks like this:

#
# RFCOMM configuration file.
#
rfcomm0 {
    bind yes;
    device 00:1A:8A:86:6D:CE;
    channel 3;
    comment “Bluetooth PPP Connection”;
}

Obviously you’ll need to enter the correct channel and device for your phone based on the output you received earlier from running sdptool search DUN. You’ll then need to restart Bluetooth with:

/etc/init.d/bluetooth restart

I chose not to add the lines to rfcomm.conf because I want to always manually connect my phone to avoid the chance of running up any unwanted bills (of course just binding to the device doesn’t mean I am connected to the internet but I’m just being paranoid).

If you want to bind manually you should do so now:

james@dirac:~$ sudo rfcomm bind 0 00:1A:8A:86:6D:CE 3
james@dirac:~$ sudo rfcomm show 0
rfcomm0: 00:1A:8A:86:6D:CE channel 3 clean

Next create the file /etc/ppp/peers/bluetooth and add the following content. I had to play around with this for a long time so if it doesn’t work for you, take a look at other examples for your phone/provider and mix and match commands from different configurations until it does. This example is based on the one from here.

# File:
# gprs
#
# Description:
# Serial cable, IrDA, Bluetooth and USB pppd options for GPRS phones.

# Keep pppd attached to the terminal:
# Comment this to get daemon mode pppd
nodetach

# Debug info from pppd:
# Comment this off, if you don’t need more info
debug

# Show password in debug messages
show-password

# Connect script:
connect ‘/usr/sbin/chat -v -f /etc/chatscripts/bluetooth’

# Disconnect script:
# AT commands used to ‘hangup’ the GPRS connection.
disconnect /etc/ppp/peers/gprs-disconnect-chat

# Serial device to which the GPRS phone is connected:
# /dev/ttyS0 for serial port (COM1 in Windows),
# /dev/ircomm0 for IrDA,
# /dev/ttyUB0 for Bluetooth (Bluez with rfcomm running) and
# /dev/ttyUSB0 for USB
#/dev/ttyS0 # serial port one
#/dev/ttyS1 # serial port two
#/dev/ircomm0 # IrDA serial port one
/dev/rfcomm0 # Bluetooth serial port one
#/dev/ttyUSB0 # USB serial device, for example Orange SPV

# Serial port line speed
115200 # fast enough
#57600 # perhaps usefull with IrDA

# Hardware flow control:
# Use hardware flow control with cable, Bluetooth and USB but not with IrDA.
crtscts # serial cable, Bluetooth and USB
#nocrtscts # IrDA

# Ignore carrier detect signal from the modem:
local

# IP addresses:
# - accept peers idea of our local address and set address peer as 10.0.0.1
# (any address would do, since IPCP gives 0.0.0.0 to it)
# - if you use the 10. network at home or something and pppd rejects it,
# change the address to something else
:10.0.0.1

# pppd must not propose any IP address to the peer!
noipdefault

# Accept peers idea of our local address
ipcp-accept-local

# Add the ppp interface as default route to the IP routing table
defaultroute
# DNS servers from the phone:
# some phones support this, some don’t.
usepeerdns

# ppp compression:
# ppp compression may be used between the phone and the pppd, but the
# serial connection is usually not the bottleneck in GPRS, so the
# compression is useless (and with some phones need to disabled before
# the LCP negotiations succeed).

#novj
#nobsdcomp
#novjccomp
#nopcomp
#noaccomp

# The phone is not required to authenticate:
noauth

# Username and password:
# If username and password are required by the APN, put here the username
# and put the username-password combination to the secrets file:
# /etc/ppp/pap-secrets for PAP and /etc/ppp/chap-secrets for CHAP
# authentication. See pppd man pages for details.
# Example, Radiolinja operator pap-secrets:
# “rlnet” * “internet” *
#user “rlnet”
#user “Orange”

# Asyncmap:
# some phones may require this option.
#asyncmap 0xa0000

# No magic:
# some phones may require this option.
nomagic

# Require PAP authentication:
# some phones may require this option.
#require-pap

Now you’ll need to create the /etc/chatscripts/bluetooth referenced in the file above:

TIMEOUT 35
ECHO ON
ABORT ‘\nBUSY\r’
ABORT ‘\nERROR\r’
ABORT ‘\nNO ANSWER\r’
ABORT ‘\nNO CARRIER\r’
ABORT ‘\nNO DIALTONE\r’
ABORT ‘\nRINGING\r\n\r\nRINGING\r’
” \rAT
OK ‘AT+CGDCONT=1,”IP”,”orangeinternet”,”",0,0′
OK ‘ATD*99#’
CONNECT “”

and also the /etc/ppp/peers/gprs-disconnect-chat script:

#!/bin/sh
#
# File:
# gprs-disconnect-chat
#
# send break
exec /usr/sbin/chat -V -s -S \
ABORT “BUSY” \
ABORT “ERROR” \
ABORT “NO DIALTONE” \
SAY “\nSending break to the modem\n” \
“” “\K” \
“” “+++ATH” \
SAY “\nPDP context detached\n”

You’ll need to make this one executable otherwise it won’t be able to be executed when you disconnect (not that it seems to be a huge problem).

Finally, update /etc/resolve.conf to use the Orange nameservers:

nameserver 193.35.133.10
nameserver 193.35.134.10

That’s pretty much it. Now bring down any other interfaces you have connected such as wirless or LAN connections so that when you connect over GPRS your routing tables will be set up correctly:

sudo ifdown eth0

Now check you are bound, cross your fingers and connect:

james@dirac:~$ sudo rfcomm bind 0 00:1A:8A:86:6D:CE 3
james@dirac:~$ sudo rfcomm show 0
rfcomm0: 00:1A:8A:86:6D:CE channel 3 clean
james@dirac:~$ sudo pon bluetooth

The final line is what does the connecting. A message should pop up on your phone asking for permission to start DUN. Choose yes and a load of messages should fly by and you should find yourself connected!

james@dirac:~$ sudo pon bluetooth
AT
OK
AT+CGDCONT=1,”IP”,”orangeinternet”,”",0,0
OK
ATD*99#
CONNECT
Serial connection established.
using channel 3
Using interface ppp0
Connect: ppp0 <--> /dev/rfcomm0
sent [LCP ConfReq id=0×1 ]
rcvd [LCP ConfReq id=0×1 ]
sent [LCP ConfAck id=0×1 ]
rcvd [LCP ConfRej id=0×1 ]
sent [LCP ConfReq id=0×2 ]
rcvd [LCP ConfAck id=0×2 ]
sent [LCP EchoReq id=0×0 magic=0×0]
sent [PAP AuthReq id=0×1 user=”dirac” password=”"]
rcvd [LCP EchoRep id=0×0 magic=0×0]
rcvd [PAP AuthAck id=0×1 “Login OK”]
Remote message: Login OK
PAP authentication succeeded
sent [CCP ConfReq id=0×1 ]
sent [IPCP ConfReq id=0×1 < ms-dns3 0.0.0.0>]
rcvd [LCP ProtRej id=0×2 80 fd 01 01 00 0f 1a 04 78 00 18 04 78 00 15 03 2f]
Protocol-Reject for ‘Compression Control Protocol’ (0×80fd) received
rcvd [IPCP ConfRej id=0×1 ]
sent [IPCP ConfReq id=0×2 ]
sent [IPCP ConfReq id=0×2 ]
rcvd [IPCP ConfReq id=0×1 ]
sent [IPCP ConfNak id=0×1 ]
rcvd [IPCP ConfNak id=0×2 ]
sent [IPCP ConfReq id=0×3 ]
rcvd [IPCP ConfReq id=0×2 ]
sent [IPCP ConfNak id=0×2 ]
rcvd [IPCP ConfAck id=0×3 ]
rcvd [IPCP ConfReq id=0×3 ]
sent [IPCP ConfNak id=0×3 ]
rcvd [IPCP ConfReq id=0×4 ]
sent [IPCP ConfNak id=0×4 ]
rcvd [IPCP ConfReq id=0×5 ]
sent [IPCP ConfNak id=0×5 ]
rcvd [IPCP ConfReq id=0×6 ]
sent [IPCP ConfRej id=0×6 ]
rcvd [IPCP ConfReq id=0×7 ]
sent [IPCP ConfRej id=0×7 ]
rcvd [IPCP ConfReq id=0×8]
sent [IPCP ConfAck id=0×8]
Cannot determine ethernet address for proxy ARP
local IP address 10.34.152.3
remote IP address 10.0.0.1
primary DNS address 193.35.133.10
secondary DNS address 193.35.134.10
Script /etc/ppp/ip-up started (pid 7253)
Script /etc/ppp/ip-up finished (pid 7253), status = 0×0

Disconnect by pressing Ctrl+C or as a last resort, turning off Bluetooth on your phone.

Terminating on signal 2
Connect time 2.2 minutes.
Sent 29700 bytes, received 2104 bytes.
Script /etc/ppp/ip-down started (pid 7324)
sent [LCP TermReq id=0×3 “User request”]
Script /etc/ppp/ip-down finished (pid 7324), status = 0×0
rcvd [LCP TermAck id=0×3]
Connection terminated.
Garbled time

Sending break to the modem

PDP context detached
Serial link disconnected.
james@dirac:~$

You can then connect again if you want to with:

james@dirac:~$ sudo pon bluetooth.

If things don’t work out first time my advice is to either try to work out properly what all the options mean in the PPP configuration or just use a bit of trial and error from other examples which have been written for your mobile provider, phone model or operating system. By the way, I’m using GPRS to write and save this blog entry now so it does work!

Update If you don’t set the nameservers in /etc/resolve.conf they get set for you automatically and if you comment out the :10.0.0.1 line in the /etc/ppp/peers/bluetooth line it still all works.

Windows XP on Debian with VMWare

Posted in Debian, Virtulization by thejimmyg on the August 24th, 2007

There are two really good tutorials on VMWare and Debain. The first describes how to install VMWare on Debian and the second describes how to create a Windows XP image.

You need a serial number but the basic commands to set it up are:

tar zxfv VMware-server-1.0.2-39867.tar.gz
cd vmware-server-distrib/
sudo apt-get install linux-headers-`uname -r` libx11-6 libx11-dev x-window-system-core
sudo apt-get install x-window-system xspecs libxtst6 psmisc build-essential
sudo ./vmware-install.pl
rm -fr vmware-server-distrib/
rm -f VMware-server*.tar.gz

A new icon will appear in the Applications->System Tools menu called VMWare Server Console.

You then need to do this to fix a bug which causes VMWare to crash when you browse for images:

cd /usr/lib/vmware/lib/libgcc_s.so.1/
sudo mv libgcc_s.so.1 libgcc_s.so.1.old
sudo ln -sf /lib/libgcc_s.so.1
cd /usr/lib/vmware/lib/libpng12.so.0
sudo mv libpng12.so.0 libpng12.so.0.old
sudo ln -sf /usr/lib/libpng12.so.0

If you want sound working in Windows XP you need to add a sound card to the virtual device. Start VMWare from the console with superuser privileges:

sudo vmware &

When you have browsed to open the Windows XP image, click the Edit virtual machine settings button then in the dialog which appears click the Add… button underneath the list of devices. Choose a sound adapter and finish the wizard which appears. When you next start the Windows XP image you should have sound.

Now, if only I could get VMware running at the same time as Xen…

VMware Sound Adaptor Wizard

Building a custom urllib2 opener to retrieve a DOI

Posted in Python, Web by thejimmyg on the August 18th, 2007

If you haven’t come across DOIs before they are simply unique identifiers in the form 10.XXXX/some_label where XXXX is a four digit code assigned to your organisation and some_label is any label you want to create a DOI for, usually the unique ID of some object you want to reference. You can then associate a URL with the DOI so that it can be resolved to a real object on the web.

The other day I was trying to create some code so that I could programatically discover the URL a particular DOI resolved to. What I wanted to do was use urllib2 to post my DOI to the same URL the DOI resolver form at the bottom of http://doi.org posts to and then retrieve the HTTP response to find out where the DOI redirects to.

Here was my first attempt:

import urllib2
import urllib

org_id = ‘10.3333′
label = ‘test’
data = {’hdl’:org_id+’/'+label, ‘x’:'13′, ‘y’:'8′}

fp = urllib2.urlopen(’http://dx.doi.org’, urllib.urlencode(data))
print fp.headers
fp.close()

Unfortunately this doesn’t work because the default behaviour is for urllib2 to follow the HTTP redirect to the redirect page so the headers are for the page that is redirected to, not the headers from the original response which issued the HTTP redirect which was what we wanted.

Date: Sat, 18 Aug 2007 13:04:45 GMT
Server: Apache/2.0.55 (Ubuntu) DAV/2 SVN/1.3.1 mod_python/3.1.4 \
  Python/2.4.3 PHP/5.1.2 proxy_html/2.4 mod_ssl/2.0.55 OpenSSL/0.9.8a
X-Powered-By: PHP/5.1.2
X-Pingback: http://jimmyg.org/xmlrpc.php
Connection: close
Transfer-Encoding: chunked
Content-Type: text/html; charset=UTF-8

To fix this you need to create your own handler.

import urllib2
import urllib

class CustomRedirectHandler(urllib2.HTTPRedirectHandler):
  def http_error_301(self, req, fp, code, msg, headers):
    result = urllib2.HTTPRedirectHandler.http_error_301(
      self, req, fp, code, msg, headers)
    result.status = code
    return result

org_id = ‘10.3333′
label = ‘test’
data = {’hdl’:org_id+’/'+label, ‘x’:'13′, ‘y’:'8′}

opener = urllib2.build_opener(CustomRedirectHandler())
req = urllib2.Request(’http://dx.doi.org’, urllib.urlencode(data))
fp = opener.open(req)
print fp.url
fp.close()

Now everything works as expected and the URL is printed.

There is some more information about urllib2 and redirects at Dive Into Python. Learn more about DOIs.

ExtJS HtmlEditor Example

Posted in JavaScript by thejimmyg on the August 15th, 2007

ExtJS 1.1 has added a simple WYSIWYG HTML editor. There is an official example and an api reference for the HtmlEditor class but not a simple example of how to turn a simple text area into an HtmlEditor so I thought I’d write one.

You need some imports which you’ll need to adjust depending on where you install ext-1.1:

<script type="text/javascript"   src="/ext-1.1/adapter/yui/yui-utilities.js"></script>
<script type=”text/javascript”   src=”/ext-1.1/adapter/yui/ext-yui-adapter.js”></script>
<script type=”text/javascript”   src=”/ext-1.1/ext-all.js”></script>
<link rel=”stylesheet” type=”text/css”   href=”/ext-1.1/resources/css/ext-all.css” />
<link rel=”stylesheet” type=”text/css”   href=”/ext-1.1/resources/css/xtheme-aero.css” />
<script type=”text/javascript”   src=”/ext-1.1/ext-base.js”></script>

Then somewhere in the head or even the body of the HTML add this:

<script type="text/javascript" language="text/javascript">
Ext.onReady(function(){
  var editor = new Ext.form.HtmlEditor({id:’note’});
  editor.applyTo(’note’);
})
</script>

Finally you’ll need the form and field which the editor should be applied to:

<form action="/index.py" method="post">
<textarea name=”note” id=”note” cols=”125″ rows=”20″></textarea>
<br />
<input type=”submit” name=”go” value=”Save” />
</form>

Pylons: Mako Templates in AuthKit

Posted in Pylons, Python, Web, AuthKit by thejimmyg on the August 14th, 2007

AuthKit’s form and openid methods take a authkit.form.template.obj or authkit.openid.template.obj argument which is a Paste import string to a function which returns a template. This is very handy if you want AuthKit to render a sign in page which looks the same as the rest of your site because you can use your existing templates. Here’s how…

If your project was named myproject you could create a file in myproject/lib/auth.py which looks like this:

import pylons
from pylons.templating import Buffet
from pylons import config
import myproject.lib.helpers as h

class MyBuffet(Buffet):
    def _update_names(self, ns):
        return ns

def_eng = config['buffet.template_engines'][0]
buffet = MyBuffet(
    def_eng['engine'],
    template_root=def_eng['template_root'],
    **def_eng['template_options']
)

for e in config['buffet.template_engines'][1:]:
    buffet.prepare(
        e['engine'],
        template_root=e['template_root'],
        alias=e['alias'],
        **e['template_options']
    )

class State:
    pass

c = State()
c.user = 'None'

def make_template():
    return buffet.render(
        template_name="/core/derived/signin.mako",
        namespace=dict(h=h, c=State())
    ).replace("%", "%%").replace("FORM_ACTION", "%s")

There is quite a lot of boiler plate because you need to setup your own instance of buffet just for this rendering but it does all work. You can then set the AuthKit config option like this:

authkit.form.template.obj = myproject.lib.auth:make_template

Logging In Pylons

Posted in Pylons, Python, AuthKit by thejimmyg on the August 14th, 2007

Pylons 0.9.6rc1 introduces a new logging mechanism which isn’t too well documented at the moment. This is the old method I used before 0.9.6rc1 came out.

In config/middleware.py Add this code at the end:

import logging, sys
def setup_logging(key, level=logging.DEBUG,
  formatter=”%(asctime)s %(levelname)s %(module)s %(messages)s”
):
  log = logging.getLogger(key)
  console = logging.StreamHandler(sys.stderr)
  log.setLevel(level)
  log.addHandler(console)

Then for each log you want recorded you just add this at the bottom of the file:

setup_logging('authkit.authenticate', logging.DEBUG)

This is particularly useful for tracking down problems with AuthKit. You might want to add all these for example

setup_logging('authkit.authenticate', logging.DEBUG)
setup_logging(’authkit.authenticate.form’, logging.DEBUG)
setup_logging(’authkit.authenticate.cookie’, logging.DEBUG)

YUI for AJAX Replace

Posted in Web, JavaScript by thejimmyg on the August 14th, 2007

Here’s the same example as before but implemented using YUI rather than scriptaculous:

${h.select(
    ”TopicSet-1.TopicID”,
    option_tags=topic_options,
    onchange=”callAJAX(’%s’,'diseases-select’); return false;”%(
        h.url_for(controller=”newstudy”,
               action=”disease_dropdown_fragment”),
    )
)}
<script type=”text/javascript”>
//<![CDATA[
function callAJAX(sUrl, replace){
    var callback = {
        success: function(o) {
            YAHOO.util.Dom.get(replace).innerHTML = o.responseText;
         },
        failure: function(o) {
            alert(”Failed to retrieve required information.”);
        }
}
    sUrl = sUrl +’?TopicSet-1.TopicID=’
    sUrl = sURL+YAHOO.util.Dom.get(’TopicSet-1.TopicID’).value;
    var transaction = YAHOO.util.Connect.asyncRequest(’GET’, sUrl,
           callback, null);
}
//]]>
</script>

Scriptaculous Pylons Helpers

Posted in Pylons, Web, JavaScript by thejimmyg on the August 14th, 2007

I haven’t tried to use the scriptaculous helpers much but since I’m writing a book on Pylons I thought I better give them a go.

Here are three URLs which might help you too:
http://wiki.script.aculo.us/scriptaculous/show/IntegrationWithPylons
http://wiki.pylonshq.com/display/pylonscookbook/Getting+started+with+AJAX
http://workaround.org/pylons/pylons-cheatsheet.html

The bottom line is that before you can really make use of the helpers you need to understand how scriptaculous works on its own first so I’d strongly recommend you don’t touch the helpers until you have some basic examples working. Apart from anything else they seem to do strange things with Mako and escaping which means they probably won’t work anyway!

If you do want to have a play you’ll need to add the scripts themselves:

<script src="/javascripts/prototype.js" type="text/javascript"></script>
<script src=”/javascripts/scriptaculous.js” type=”text/javascript”></script>

or if you want to use the helpers:

${ h.javascript_include_tag(builtins=True) }

Then you can write some code like this:

<select id="TopicSet-1.TopicID" name="TopicSet-1.TopicID" onchange="
new Ajax.Updater(
‘diseases-select’,
‘/newstudy/disease_dropdown_fragment’,
{
asynchronous:true,
evalScripts:true,
parameters:{’TopicSet-1.TopicID’: $(’TopicSet-1.TopicID’).value},
}
);
“>
<option value=”" selected=”selected”>Please select…</option>
<option value=”1″>Blood</option>
<option value=”2″>Cardiovascular</option>
<option value=”3″>Congenital Disorders</option>
</select>

In scriptaculous $ is shorthand for document.getElementByID so $(’TopicSet-1.TopicID’) returns the element with the ID TopicSet-1.TopicID. Notice that it is fine to have elements with a . in their id. This is really handy when it comes to using FormEncode where you might want nested data structures of fields.

The call to Ajax.Updater() does an AJAX request to a URL /newstudy/disease_dropdown_fragment which returns some HTML content which replaces the element with id diseases-select.

The controller action looks like this

def disease_dropdown_fragment(self):
set_dropdown_values(c.connection(), c, request)
return render(”/core/derived/disease_dropdown_fragment.mako”)

It just calls a function to get some values then returns the rendered HTML directly. This approach is much quicker and easier than trying to return a JSON data structure and assemble HTML client-side.

The AJAX updator itself is documented on the scriptaculous wiki.

You can also easily add visual effects. For example, to highlight the div we’ve just updated you can add this to the list of options (just before the asynchronous:true, would be fine.

onComplete:function(){ new Effect.Highlight('diseases-select');},

Remeber you need the , at the end though. Here is some more information on visual effects.

That’s just about it, there are other examples of scriptaculous around on the web but my advice is to not try to use the Pylons helpers until you are very confident using the JavaScript directly, otherwise you might get confused.