I've just been asked to look into a way to 'stream' information from the server to any listening clients. Basically it's a server-push rather than client-pull system where changes made on one client are (almost) immediately reflected on all other clients. This is similar to AJAX in that there is no page refresh but it is more autonomous.
I've been reading up on Comet, which is basically just a term for a kind of AJAX solution to this problem, but it doesn't specify any implementation suggestions.
Bayeux takes this a step further by actually outlining a protocol for message transfer between client and server.
Most implementations on the server-side are in Java but we need PHP. I've tracked down a PHP implementation called Comep that works quite well on the server-side (although its procedural rather than OO based) and I'm going to look into replacing its vanilla-javascript client-side with this jQuery Comet plugin.
For any other LAMP developers interested in Comet a good place to start is the Comet Daily Blog.
Update, 2008-06-15: Although PERL rather than PHP based it is also worth mentioning Meteor, which is a highly polished comet server implementation.
Tips and tricks for LAMP (Linux Apache MySQL PHP) developers.
Tuesday, 10 June 2008
Comet server-push framework
Thursday, 1 May 2008
Custom ExtJS header buttons
ExtJS Panels can have a limited range of buttons on the header bar but what if you want a custom button? These can be added to a toolbar just underneath the header but if space is at a premium or perhaps you only want one button it's not always ideal.
One solution is to have no header and just make the toolbar look like a header:
tbar: new Ext.Toolbar({
// make the toolbar background look like a header
cls: 'x-panel-header',
height: 25,
items: [
// give the toolbar a title which looks like a Panel title
'<span style="color:#15428B; font-weight:bold">Title Here</span>',
'->', //fill element
{
text: 'Button Text',
iconCls: 'add', // optional icon class
handler: function() {
// do stuff here
}
},' ']
}),
// ...
});
(The styles used above fit the standard ExtJS theme)
This produces something like this:
Saturday, 19 April 2008
Extending classes in JavaScript
Note: This post was originally written in 2008. There's a 2015 update at the bottom.
There are many different ways to achieve Object Orientation in JavaScript and the Internet is littered with examples.jQuery Uses an extend method within the super-class that allows you to add functionality onto an instance of that class, creating a kind of sub-class (although it is an object):
SuperClass.prototype = {
// ...
extend: function() {
var int_count = 0;
var arr_prop;
while ( (arr_prop = arguments[int_count++]) != null ) {
for ( var i in arr_prop ) {
this[i] = arr_prop[i];
}
}
// Return the modified object
return this;
}
}
// ...
var obj_subclass = new SuperClass();
obj_subclass.extend({
foo: 'bar',
// ...
});
This is quick and dirty but not proper OO and if you want several instances of the 'sub-class' you need to call extend on each one.
You probably already know that to add member variables/methods to a class you assign them to its prototype property. This can be one value at a time:
SuperClass.prototype.foo = 'bar';
Or a simple object can be assigned:
SuperClass.prototype = {
foo: 'bar',
x: 'y',
super_func: function() {
//...
}
}
A good way to simulate inheritance is to assign an instance of the super-class to the sub-class' prototype example here:
function SubClass() {}
SubClass.prototype = obj_super;
This means that all member variables/functions of SuperClass are now contained within SubClass' prototype.
In order to now extend SuperClass' functionality in SubClass we revert back to adding one new thing at a time with SubClass.prototype.sub_func = function() { //... }. This is fine but if you plan on adding a lot more stuff it's not ideal.
The solution I have come up with (I say "I", maybe other people do this but I can't find any mention of it on the net) is to combine the two methods above:
function SubClass() {}
SubClass.prototype = obj_super.extend({
foo: 'bar',
sub_func: function() { //... },
// ...
});
This way we are still creating a proper sub-class and inheriting the super-classes functionality whilst conveniently adding our own.
Note: You can call super-class methods directly from within the sub-class with SuperClass.prototype.super_func.call(this, arg1, arg2, argN);
Update (03/01/2015)
The above used to be how I extended 'classes' in JavaScript but these days I use a different method. Again, there are many ways to achieve JS extension, what follows is just my preference.
This method has two main requirements:
- You call the constructor of the parent inside the constructor of the child using the child's context
- You copy the parents prototype onto the child's prototype via the Object.create method
function SuperClass() { var a = 1; this.getA = function() { return a; }; } SuperClass.prototype.functionA = function() { alert('SuperClass functionA'); }; function SubClass() { SuperClass.call(this); var b = 2; this.getB = function() { return b; }; } SubClass.prototype = Object.create(SuperClass.prototype); SubClass.prototype.functionB = function() { var aPlusB = this.getA() + this.getB(); alert('SubClass functionB. a+b == '+aplusB); }; var eg = new SubClass(); eg.functionA(); // alerts "SuperClass functionA" eg.functionB(); // alerts "SubClass functionB. a+b == 3"
Now SubClass extends SuperClass. So why not use SubClass.prototype = new SuperClass();
you ask? Well there's a subtle difference between new
and Object.create()
in that the latter doesn't actually call SuperClass's constructor, it just copies the prototype so the SuperClass constructor will only get called at the time of creation of the SubClass (as we are calling it explicitly with SuperClass.call(this)
).
Note that, as with the old method from this post, the way to call SuperClass function directly is with SuperClass.prototype.functionName.call(this, arg1, argN)
Wednesday, 9 April 2008
Creating a basic select box in ExtJS
I'm currently working on a project that involves generating an entirely ExtJS-based interface from PHP code.
I needed to be able to produce in ExtJS the equivelent of a standard HTML <select> box. This can be achieved with a ComboBox, however, it seems that ComboBoxes are heavily geared towards doing lots of clever things like loading in options over AJAX, allowing the user to type in their own options, auto-completing typed in options, etc. That's all great but if all you want is a standard drop-down with a predefined set of options it takes a bit of work.
I incorrectly assumed that something like the following would work:
name: 'countries',
items: [
{value: '1', text: 'UK'},
{value: '2', text: 'US'},
// ...
]
});
Unfortunaltey, it's not that simple.
Here's an example of the actual code required:
name: 'countries',
// Stop users being able to type in the combobox
editable: false,
// Even though the user cant type any more
// once they select one option it'll remove any
// others that don't start with the same letters
// unless we turn off filtering
disableKeyFilter: true,
// Only allow users to pick an option that exists
// in the list of options (not one of their own)
forceSelection: true,
// This isn't entirely necessary but the combox
// will start off blank otherwise
emptyText: '--select one--',
// This one's vital: when the user clicks on the
// drop-down show ALL options
triggerAction: 'all',
// By default it retrieves remote data,
// we're using local data
mode: 'local',
// ComboBox will only accept data from a Store
// so we have to create a basic one
store: new Ext.data.SimpleStore({
id: 0,
fields: ['value', 'text'],
data : [['1', 'UK'], ['2', 'US']]
}),
// Specify which fields in the store hold
// the value and the display text
valueField: 'value',
displayField: 'text',
// Important: by default the POST/GET data
// for this item will contain the display text
// not the value. This option creates a hidden field
// with the same name as the dropdown containing the
// selected value so it is that which gets returned
hiddenName: 'countries'
});
With all those set (plus any of your own) you should have the equivalent of an HTML select box in ExtJS.
For good examples of different ComboBoxes (but unfortunately little explanation of them) check this link:
http://extjs.com/deploy/ext/examples/form/combos.html
Friday, 4 April 2008
Traversing XML in ExtJS
We've just started using the JavaScript ExtJS framework for a new project and whilst it is very good at presentational stuff we have found it to be lacking in the DOM manipulation and traversal department.
We use XML a lot to send data back and forth and so we needed to use that instead of ExtJS' preferred JSON. That in itself is fine, ExtJS provides an XmlReader class that can interpret XML. However, this is geared towards reading in a result set for use in a grid, etc. We wanted to simply return some messages and get ExtJS to read them.
Not impossible I'm sure but we we're struggling with it.
Long story short: we decided to use jQuery for that bit :)
We were already very familiar with jQuery and where it is not as good at presentation as ExtJS it makes up for it in it's superior (imo) DOM traversal and manipulation.
ExtJS and jQuery can co-exist quite peacefully so this was no problem, here's a sample:
// ..
// success and failure functions are passed
// the XMLHTTPRequest object
success: function(obj_response) {
var str_val=$('mynode',obj_response.responseXML).text();
alert(str_val);
}
// ...
});
This would work for:
<mynode>This would be the output</mynode>
Again, I'm sure ExtJS can do something similar but I couldn't get it to work.
Bear in mind that other ExtJS classes that can make AJAX calls sometimes pass the success and fail functions another object which contains the XMLHTTPRequest object, so the call is something like obj_response.response.responseXML. Check the ExtJS API Docs for more.
If you are familiar with ExtJS and not jQuery, or vice-versa, I'd highly recommend reading up on both :)
Exclude certain files from a cp command
I needed to be able to exclude files with a certain extension from a cp command that was going to be executed automatically as part of a much larger script.
There doesn't seem to be any direct way to do this (e.g. cp --exclude...) and although there are several suggestions on the net on how to overcome this I found the neatest way was to use the tar command instead:
tar -czf /path/to/archive.tar.gz ./ --exclude=*.txt
cd /copy/to/path
tar -xzvf /path/to/archive.tar.gz
Of course this isn't ideal, creating a tar archive when it isn't necessary but the files I needed to copy weren't large and so it was nice and quick and dirty.