How best to move forward implementing priority AJAX functionality?
We've got a lot of pieces in the works.
- Drupal.js helpers and the existing core behaviours (collapse, autocomplete, etc.)
- Thox's contributions beyond existing core pieces, including AJAX spellcheck
- Steven's contributions beyond existing core pieces, including tablesorting
- Jaza's Activeselect
- Jjeff has 'prototyped' methods for scriptaculiousifying Drupal in S/P Ajax.
- Based on his Moo module, Steve McKenzie has roughed in a very cool edit in place behaviour.
- I've recently sketched in a number of behaviours (AJAX form submitting with preview, dynamically loading content into a block, etc.) as Javascript Tools
- etc.
So there's a lot of good work underway. How can/should we coordinate efforts? How can we ensure that different behaviours know about each other as needed? If various behaviours need the same helpers (e.g, determining the base url), how can we register these once? How can we avoid unneeded duplication of efforts, e.g., developing different implementations of the same behaviour?
In coversations with Steve and Jjeff over the past couple of days, we've come up with a few ideas. Here they are. Please wade in and correct or comment!
- Behaviours should be distinct from effects. Implement behaviours in generic ways so that various effect libraries could be attached. Expose effects (e.g., collapsing or scrollIntoView from collapse.js) so that effects libraries can attache effects to them.
- We need a way to register behaviours - including core ones - so e.g. we can reattach them to dynamically loaded content.
- Put commonly needed helpers into a shared place, as is done in drupal.js for core behaviours.
- Ideally, implement namespace to avoid functionname collisions/
- Communicate, collaborate--hence this new group!
A possible approach:
- Refactor the existing Javascript Tools library so that it is its own module with an equivalent to drupal.js--a place for common methods, some of them candidates for eventual inclusion in drupal.js. E.b., jstools.js. Use an equivalent to drupal_add_js to ensure that this is loaded before any behaviour libraries relying on it.
- Behaviours register themselves to an object defined in jstools.js. Existing core behaviours are also detected (through detecting their attach functions).
- All effects are pulled into separate function calls. jstools.js implement 'vanilla' effects, like the existing drupal.js ones (e.g., toggling of classes for collapse). Effects libraries can override these with their own versions.
Some rough sample code. I'm using object notation to minimize collisions, but we could easily follow drupal.js instead.
A. Provide a set of helper functions, beyond those in drupal.js.
// A set of helper functions, beyond the methods declared in drupal.js.
function jsToolsHelpers() {};
// Cookie handling helpers
jsToolsHelpers.prototype.setCookie = function(sName, sValue, nDays) {
var expires = "";
if (nDays) {
var d = new Date();
d.setTime(d.getTime() + nDays * 24 * 60 * 60 * 1000);
expires = '; expires=' + d.toGMTString();
}
document.cookie = sName + '=' + sValue + expires + '; path=/';
};
B. Factor out our effects.
var jsToolsEffects = function() {};
// Returns the event's source element
jsToolsEffects.prototype.collapse = function(node) {
toggleClass(node, 'collapsed');
}
C. Register behaviours.
if (jsToolsHelpers && jsToolsEffects) {
var jsTools = {
behaviors: {},
helpers: new jsToolsHelpers(),
effects: new jsToolsEffects(),
init: function() {
jstools.attachBehaviors();
// We detect core behaviours after inital attachment because they already register themselves
// as load events.
jstools.detectCoreBehaviors();
},
attachBehaviors: function(elt) {
if (!elt) {
elt = document;
}
for(var behaviorName in jsTools.behaviors) {
jstools.behaviors[behaviorName](elt);
if (jstools.behaviorListeners[behaviorName]) {
for (var listenerName in jstools.behaviorListeners[behaviorName]) {
if (jstools.behaviors[listenerName]) {
jstools.behaviors[listenerName](elt);
}
}
}
}
},
detectCoreBehaviors: function() {
var coreBehaviors = {'upload': uploadAutoAttach};
for (behaviorName in coreBehaviors) {
if (coreBehaviors[behaviorName]) {
jstools.behaviors[behaviorName] = {
attach: coreBehaviors[behaviorName]
};
}
}
}
};
We would declare a new behaviour as:
if (jsTools) {
jsTools.behaviours['autowhatever'] = autowhateverAutoAttach;
}
Comments
thanks nedjo for this
thanks nedjo for this awesome start.
We have 22 subscribers.. now to see who's going to help us out :)
We need to figure out who wants to work on what and all that jazz.
...or who can and can't
As a subscriber, I can say I'm interested, and have done cross-browser DHTML, but since I have not used an AJAX library I don't know how useful I am... :-/
So my hand up for testing :-)
i will use this so if there
i will use this so if there have some new informations about xajax etc. Please tell me,thanks.
Ajax Spellcheck
There's only one bug in the ajax_spellcheck module that stops it working on Drupal 4.7. It relied on the
<base>HTML element but now we need to get the site's base url from somewhere else. I'd prefer to see the code for that put into drupal.js, as a lot of AJAX stuff will need to get the URL from somewhere. Note: autocomplete.js gets it from hidden inputs as the URL changes for each autocomplete field.I'd also personally prefer a rewrite of the AJAX code into one function (e.g.
request()) as opposed to the current HTTPGet() and HTTPPost().I always set $base_url on the client
I just put it in a global variable, but a more elegant place for it is probably desired. +1 for the feature.
I think it’s best to just
I think it's best to just have the global variable but in drupal.js at say the bottom of the file
var base_url = "whatever.com";as simple as that.
problems
drupal.js isn't dynamic, shouldn't be edited, and shouldn't pollute the global namespace.
a better implementation would be something like this:
<?phpglobal $base_url;
drupal_call_js('drupal.setBaseUrl', "$base_url");
?>
The drupal object could then be used for all sorts of things.
Common issue
Detecting base url is a good example of a problem we need a shared solution for. Robert, Steve, and I have now all come up with our own implementations.
Yes, we can and probably should try to get something into drupal.js, but meantime we can together develop the best solution, and make it available to any AJAX behaviour that needs it.
There was also a xajax
There was also a xajax module in work at http://cvs.drupal.org/viewcvs/drupal/contributions/modules/xajax/ I dont know if the original author is still interested though.
The basic idea of xajax is to have an easy way to have php callbacks called by automatically created javascript code. This could be useful for example to handle form submission.
I want to have a look at the jstools module this weekend though, because there is already an ajaxsubmit module that might supersede xajax.
Some first steps taken
I've taken some first steps by refactoring Javascript Tools in the way outlined here. It now has a core library where we can put common methods, and a way to register behaviours and effects. I've reworked some of the jstools modules to use this new approach. I need to do the rest, and to complete the work of pulling out the effects.
Jstools.module loads two scripts: a static jstools.js, with a jsTools object and various methods; and a dynamically generated file where variables are set:
jsTools.basePath is the base path as given by the Drupal function base_path()
jsTools.query is '?q=' if we don't have clean urls, an zero-lenght string '' otherwise.
Together these can be used to determine path locations.
Anyone ready to jump in? Steve, could you add some of your very useful methods to the jsToolsHelpers object in /modules/jstools/jstools.js? E.g., arg()? Maybe you could also give some attention to defining effects, by adding new methods to the jsToolsEffects object.
sounds good.. tomorrow I
sounds good.. tomorrow I will for sure. Being saturday, I'll have all day.