Tuesday, January 11, 2011

Cache-Control and iPhone 4.1 Safari

If you want to use cookies in WebKit applications on iPhone 4.1 or earlier you will need to know about this little trick. Basically Safari for iPhone in 4.1 has caching issues with cookies and you will need to disable proxy caching and securePagesWithPragma to make those earlier browsers not have problems with cookies that you may want to use for OAuth.

Big Overview on Caching Headers

Here's the tomcat config:

<Context path="/" docBase="/root/webapps/ratecred_20110108" reloadable="true">
<Valve className="org.apache.catalina.authenticator.BasicAuthenticator"
disableProxyCaching="false" securePagesWithPragma="false"/>
</Context>


Also you ned to to check the headers generated from Apache, I found that apache was automatically setting the Cache-Control header to no-cache="set-cookie", this also cause specific problems with cookie caching in 4.1 versions of Safari on iPhone in order to accommodate this issue I would use the following command:

lwp-request -e -d http://foobar.com


This returns a list of headers for the request so I can see how apache is adding headers:

claygraham@h-34-0-36-125:~$ lwp-request -e -d http://ratecred.com
Cache-Control: no-cache="set-cookie"
Connection: Close
Date: Thu, 13 Jan 2011 05:59:33 GMT
Vary: Accept-Encoding
Content-Language: en-US
Content-Type: text/html;charset=UTF-8
Content-Type: text/html;charset=UTF-8
Client-Date: Thu, 13 Jan 2011 05:59:34 GMT
Client-Peer: 50.16.212.144:80
Client-Response-Num: 1
Client-Transfer-Encoding: chunked
Link: ; media="screen, projection"; rel="stylesheet"; type="text/css"
Link: ; media="print"; rel="stylesheet"; type="text/css"
Link: ; media="screen, projection"; rel="stylesheet"; type="text/css"
Link: ; rel="stylesheet"; type="text/css"
Link: ; /="/"; rel="stylesheet"; type="text/css"
Link: ; rel="stylesheet"; type="text/css"
Link: ; /="/"; rel="stylesheet"; type="text/css"
Link: ; /="/"; rel="shortcut icon"
Set-Cookie: JSESSIONID=73B7B4606A5F99D37378DFA21E475942; Path=/
Set-Cookie: AWSELB=3505DFB9122FAFC80483E17CBEB5E23D24546B00A71218A5BAE3B79F14317437BEAEDA7FEC501E9826163E4BE26AAE3DE36A6B6A375DB7C3AEF0E17F41A873610F8EA3D068;MAX-AGE=600
Title: RateCred Home
X-Meta-Description: RateCred Home Page, Rate places earn credit. What if you mashed up yelp, foursquare and twitter on Android phones?
X-Meta-Generator: RateCred
X-Meta-Google-Site-Verification: u9YkTj5gr6aeYBst1Aac-B_5cCvJe_Ataauqep_EwEE
X-Meta-Googlebot: index,follow
X-Meta-Refresh: 20
X-Meta-Robots: index,follow


so to modify the header I add to httpd.conf

Header unset Cache-Control
Header set Cache-Control "max-age=3600, public"

Monday, January 10, 2011

Article on Fuzzy Matches

Lexical parsing with match ranking. This is really good for fuzzy matches between multiple databases. I will probably add the code for this which I have written so come back.

http://www.catalysoft.com/articles/StrikeAMatch.html

Great Article on Writing JavaScript Plugins

Really love this article. I just wish he had a link to his libs javascript. Looks like this could be a good jQuery plugin.

http://peter.michaux.ca/articles/how-i-write-javascript-widgets

Sunday, January 09, 2011

Sencha Howto: Templated Ajax View

I am making this available as a HOWTO because I could not find an example that brings all of this together, but I think its something that many developers probably want to do. This is a single view with its own template driven from an Ajax request. A specific id is passed to the view to drive the request. Hope this helps.


ratecred.views.RatingView = Ext.extend(Ext.Panel, {
fullscreen: true,
dockedItems: {
xtype: 'publicToolbar',
},
layout: {
type: 'fit'
},
initComponent: function() {

var ratingId = this.ratingId;

var mainPanel = new Ext.Panel({
html: 'Rating View'
});

Ext.apply(this, {
items:[ mainPanel ]
});
ratecred.views.RatingView.superclass.initComponent.apply(this, arguments);

var ratingTemplate = new Ext.XTemplate(
'<div class="margin-10 rating">',
'<table width="100%">',
'<tr>',
'<td width="48" valign="top"><img src="{owner.raterImage.filename}" width="48" height="48" class="img-align-left"/></td>',
'<td valign="top"><div class="place-name">{place.name}</div></td>',
'<td width="48" valign="top"><div class="value text-16">{raterRating}</div></td>',
'</tr>',
'<tr>',
'<td colspan="3"><div class="notes">{notes}</div></td>',
'</tr>',
'<tpl for="attributes">',
'<tr>',
'<td colspan="3"><div class="attribute">{type}, {name}</div></td>',
'</tr>',
'</tpl>',
'<tpl for="compliments">',
'<tr>',
'<td colspan="3"><div class="compliment"><img src="{owner:this.getProfileImageUrl}" width="48" height="48" class="img-align-left"/> owner:{owner.userName} {note}</div></td>',
'</tr>',
'</tpl>',
'</table>',

'</div>',

{
compiled: true,
getProfileImageUrl: function(rater){
if(rater.raterImage.type=='S3REPO')
return 'http://media.servicetattler.com/web/iv/'+rater.raterImage.filename;
else
return rater.raterImage.filename;
},

}
);

Ext.getBody().mask('Loading...', 'x-mask-loading', false);

//rating id is set at create time
Ext.Ajax.request({
url: 'http://dev.ratecred.com/v2/rating/'+ratingId+'.json',
success: function(response, opts) {
var reader = new Ext.data.JsonReader({
model: 'Rating'
});
var data = reader.getResponseData(response);
ratingTemplate.overwrite(mainPanel.body, data);
Ext.getBody().unmask();
}
});

},
});

Ext.reg('ratingView', ratecred.views.RatingView);