This patch is based upon conversations I had with quicksketch over here: http://drupal.org/node/399982
To begin with, I found the existing implementation of #ahah very restrictive, in that all you could do with it was return a piece of HTML. The above linked issue noted that the actual work needed to set up this return value was very high.
With Views, and later refined in CTools, I created a framework whereupon the PHP server has a sort of macro language that can be used to set up a series of commands on the server. In other words, this macro language can easily say "Replace this #id with this HTML" as well as other common, obvious commands. In addition, since I knew I would not think of everything we would need for this, the command space can be extended. The actual mechanism for that works like behaviors, in that functions can be added to the Drupal.AJAX.commands space much like behaviors can be added to the Drupal.behaviors space.
After some discussion with quicksketch, we decided that this really does change the system from being AHAH (which just returns HTML) to true AJAX (really AJAJ since we return JSON, not XML but AJAX sounds cooler).
1) This patch adds an ajax.inc file to hold the AJAX framework functions and documentation.
2) This patch contains an ajax_render() command to easily send data back to the client.
3) This patch renames the ahah.js to ajax.js and related #ahah namespace to #ajax.
4) This patch refines the #ahah wrapper so that the form callback is very easy to use. Example from poll.module:
// We name our button 'poll_more' to avoid conflicts with other modules using
// AJAX-enabled buttons with the id 'more'.
$form['choice_wrapper']['poll_more'] = array(
'#type' => 'submit',
'#value' => t('More choices'),
'#description' => t("If the amount of boxes above isn't enough, click here to add more choices."),
'#weight' => 1,
'#submit' => array('poll_more_choices_submit'), // If no javascript action.
'#ajax' => array(
'callback' => 'poll_choice_js',
'wrapper' => 'poll-choices',
'method' => 'replace',
'effect' => 'fade',
),
);
And the callback that it provides:
/**
* Menu callback for AHAH additions. Render the new poll choices.
*/
function poll_choice_js($form, $form_state) {
$choice_form = $form['choice_wrapper']['choice'];
// Prevent duplicate wrappers.
unset($choice_form['#prefix'], $choice_form['#suffix']);
return theme('status_messages') . drupal_render($choice_form);
}
All this really does is re-render that particular piece of the form and send it back, and the client puts the new HTML in.
Note that the #ajax wrapper is already intelligent enough to let you choose your own path and return anything that is needed. This allows, for example, actual ajax submission of forms, something the current #ahah wrapper is incapable of.
Still remaining TODO:
1) Documentation. This system provides a good place to document our AJAX framework, including the use of the #ahah property and some deeper stuff in ajax.inc -- this needs to be fleshed out, but without some reviews I feel this documentation to be premature.
2) Only poll.module is converted to the new format. I took a look at field.module and I do not understand enough of what it is doing to feel comfortable converting it. I may need a bit of a hand. My hope is that the conversion will be easy and straightforward. upload.module also needs to be converted. I think this is fairly straightforward, but again, I want some reviews before I continue. Also this is a nice way for other people to play with the system very early.
3) Tests. poll.test needs to be updated. I'm not up on the testing framework, so I may need some help and/or guidance with that. We may want to add some general tests of the ajax framework as well, though I'm not sure what we can/should actually add.
Comment | File | Size | Author |
---|---|---|---|
#110 | drupal.ajax-docs.patch | 3.27 KB | sun |
#106 | ajax_docs_d7_update_544418_03.patch | 3.57 KB | rfay |
#103 | ajax_docs_d7_update_544418_02.patch | 3.25 KB | rfay |
#98 | ajax_docs_d7_update_544418.patch | 3.09 KB | rfay |
#84 | drupal.ajax_.84a.patch | 2.03 KB | sun |
Comments
Comment #2
merlinofchaos CreditAttribution: merlinofchaos commentedUpdated patch. This converts upload and book. It tries to convert form but I'm not sure if I succeeded. That's going to take some test.
Still needs: Fix poll.test, possibly form tests.
Comment #3
merlinofchaos CreditAttribution: merlinofchaos commentedAs a sidenote, it seems like we ought to be able to provide some tools to make the form manipulations done a little easier.
I tried to convert book to use the same structure that poll uses, but the form callback pretty much requires a button to be clicked to work, and that causes the form to submit which totally blew up. Also, for what it's worth, it also seemed like the book outline code wasn't actually functioning *at all* prior to this patch. I made a modification or two to make it seem ok. It was using the slide effect, for example, which was really jarring when switching from one book to another.
Comment #5
sunAwesome! Almost ready to commit for me.
1) "Drupal.AJAX" - why all uppercase? Not really in line with our camelCase naming for JS. (And I personally find that Drupal.ajax['foo'] looks much nicer than Drupal.AJAX['foo'])
2) I'm by all means no OOP expert, but those ajax_command_*() functions as well as the example invocation snippet made me question whether we shouldn't use a class/object on the PHP side as well?
...to something like this:
That way, we'd have pretty similar AJAX objects on both layers - PHP and JS. No?
Comment #6
merlinofchaos CreditAttribution: merlinofchaos commented#1 I've always been a little unsure of how camelcase is supposed to work with capitalized abbreviations like that. .ajax looks wrong to me, but I don't actually care all that much.
#2 sounds really good until I remember that it's awfully hard to extend. Remember the macro language is extensible, so that applications which need weird things can do it.
Comment #7
yched CreditAttribution: yched commentedFor the record, fields 'add more' JS callback (field_add_more_js()) is a god-awful piece of code, directly inherited from CCK D6.
#367567: Use AJAX framework for "Add more" / load include file containing form / introduce $form_state['build_info'] was open to update it to D7's ahah improvements and hopefully streamline it in the process - but it was agreed to postpone it while #399982: Simplify and standardize returning an AHAH response settles.
Since this issue now takes over, it's probably a good time to revive this, but I'm not sure where to start, and I not-so-secretly hope quicksketch will chime in :-p.
Also, note that much of the ugliness in field_add_more_js() was added in D6 to account for filefield widgets specific needs - or at least the needs reported by the folks with their hands in filefield back in spring 08 (filefield governance was a little hectic back then)
For this reason too, i hope quicksketch will be of good help on this.
And major yay for the patch, BTW !
Comment #8
yched CreditAttribution: yched commentedfrom patch #2 :
It looks like the $form_id is never set ?
Comment #9
yched CreditAttribution: yched commentedHaving to specify the HTML target to be replaced looks odd - isn't it already specified in the $element['#ajax']['wrapper'] property ?
Comment #10
yched CreditAttribution: yched commented[edited]
I fixed #8 by adding $form_id = $form['#form_id']; after theajax_get_form() call in ajax_form_callback().
Then, it seems the *second* time you click the 'add more poll choices'button fails.
$form = form_get_cache($form_build_id, $form_state); returns NULL in
ajax_get_form().
Actually, $form_build_id in ajax_form_callback() has the same problem than $form_id: not set.
Fixed that locally by changing ajax_get_form() to return ($form, $form_state, $form_id, $form_build_id).
(sorry for the flood, I'm playing with the patch to refactor field's own 'add more' code - works beautifully, but it will require some confirmation from quicksketch that it doesn't break filefield, so it's probably best to keep it for a followup. The current patch keeps the existing ugly code working anyway...)
Comment #11
merlinofchaos CreditAttribution: merlinofchaos commentedIt failed the second time? That's very odd. We should make sure I didn't break the replacement code. Though in my tests I did it several times. I will try again.
I was thinking at dinner that having to specify the wrapper should be unnecessary, that data IS available in this case. I'll make sure the next patch addresses that.
Comment #12
yched CreditAttribution: yched commentedoops, crosspost : edited my comment #10 with the fix.
Comment #13
merlinofchaos CreditAttribution: merlinofchaos commentedOk, I confirm that does fix the issue. Though I'm not so sure about having it return 4 items in a list. OTOH it's a worthwhile abstraction for use elsewhere.
Comment #14
merlinofchaos CreditAttribution: merlinofchaos commentedA quick note since you're working: Passing NULL through ajax_command_replace for the selector will replace the default wrapper that was set in #ajax[wrapper] so that's an easy fix while you're working.
Comment #15
merlinofchaos CreditAttribution: merlinofchaos commentedAlso I'm around for a bit if you want to discuss this on IRC.
Comment #16
yched CreditAttribution: yched commentedYeah. Did the trick for me locally, but obviously YMMV whether it's the best fix.
IRC: sorry, bedtime :-). I should've logged on IRC earlier, actually, would have saved 5-6 comments...
Comment #17
merlinofchaos CreditAttribution: merlinofchaos commentedUpdated patch fixes yched's issues with $form_id and setting wrapper IDs unnecessarily.
Comment #18
merlinofchaos CreditAttribution: merlinofchaos commentedAdditional TODO:
ajax_render() should probably automatically support jsonp. This should probably be a second patch, but with this framework in place I believe it would be nigh unto trivial. Here's an explanation of jsonp: http://remysharp.com/2007/10/08/what-is-jsonp/
It doesn't really cover what jsonp is for, which is a way to get around the XSRF problems with normal ajax calls. JSONP can allow ajax calls to work to domains not the client domain. This can be valuable, though we will need to evaluate the security. (another good reason to make it a separate patch).
Comment #19
katbailey CreditAttribution: katbailey commentedThis looks truly awesome. In order to take it for a serious spin, I'd want to convert Quicktabs over to using it, but unfortunately I think this patch cannot wait that long :-(. In the meantime, I did just test out the poll creation form and there's still a problem when you add a fourth choice - it adds the the elements fine but the tabledrag handles don't get added. Will look at it some more tomorrow if I get a chance.
Comment #20
mattyoung CreditAttribution: mattyoung commentedsubscribe
Comment #21
yched CreditAttribution: yched commentedMinor: the PHPdoc for ajax_get_form() needs to be updated for the new return values.
Comment #22
kika CreditAttribution: kika commented...really AJAJ since we return JSON, not XML but AJAX sounds cooler
Will "being cool" justifies a DX confusion of expected return format? Or is AJAJ such a weird term no-one gets? Wikipedia seems to redirect from AJAJ to AJAX: http://en.wikipedia.org/w/index.php?title=AJAJ&redirect=no
Comment #23
merlinofchaos CreditAttribution: merlinofchaos commentedkika: I believe AJAJ is so unused no one will get it.
in jquery the command is $.ajax() which is enough reason, to me, to standardize on ajax as the term.
Comment #24
RobLoachSubscribing..... Awesome to the max.
Comment #25
effulgentsia CreditAttribution: effulgentsia commentedsubscribing. this is awesome. looking forward to it being committed.
Comment #26
catchFixed the test failures.
Comment #27
merlinofchaos CreditAttribution: merlinofchaos commentedRemaining TODO: Clean up the @todo lines in the documentation then. And a review from quicksketch. I hope he has time soon, though he indicated ot me yesterday that he is not made of time right now. :/
Comment #28
merlinofchaos CreditAttribution: merlinofchaos commentedWhoops did not mean to change status.
Comment #30
tic2000 CreditAttribution: tic2000 commented3 parameters in phpdoc, only 2 in the function.
No new line before @return (as with all the others in the patch).
This description is for the previous function. This one is about css.
Missing the one line summary.
Do we need a @param here or is just self explanatory?
#ahah should be #ajax
Pour interface. Are you lost? Where are your parents?
This review is powered by Dreditor.
Comment #31
merlinofchaos CreditAttribution: merlinofchaos commentedentity.inc?! That should not be in this patch.
Comment #32
yched CreditAttribution: yched commentedentity.inc probably comes from catch's reroll ;-)
What is surprising though is that there's only 1kb difference between #26 and #17, while there are somthg like 200 additional lines of unrelated entity.inc ?
Comment #33
sunNot sure about the PHPDoc syntax for linking to another defined group.
@catch: entity.inc is missing a CVS $Id$ at the top of the file ;)
Comment #35
sunIs that the proper syntax for linking to another @defgroup ?
"sometimes"? When?
Missing parenthesis after drupal_add_js().
Why type-agnostic matching?
Missing parenthesis after drupal_json(). We avoid abbreviations comments ("don't").
This does not allow for multiple error messages + processing... considering that there may be X modules involved in returning an AJAX response for Y, that might not be a good idea?
We want to squeeze a drupal_alter() in here, right before ajax_render() is invoked.
Shouldn't we check for !isset($js_added[$element['#id']]) first?
Use !empty() here.
Also, the default error message sounds a bit awkward... (think of regular users)
Does not wrap at 80 chars.
(and elsewhere)
s/selector jQuery uses in $()/jQuery selector/.
I wonder whether we shouldn't stuff "jQuery" before the command name here to make any sense of those summaries...
Appended to what? The selector provided as $star?
s/whatever/any/
Typo in "(c)hanges".
Array elements should be wrapped in ''.
I still think that we should use Drupal.ajax - also, to match jQuery.ajax.
1) We need a place to document those generic CSS classes. (Very useful!)
2) It's not entirely clear to me what the actual difference between those 2 classes is.
No space here (empty object).
What happens if #id is not defined?
We should add the .processed CSS class first. (Also, to prevent any possible recursion.)
Exceeds 80 chars.
Use single quotes.
(possibly elsewhere) Use $ instead of jQuery.
Wrap 'nojs' and 'ajax' in single quotes and append "in the URL" to clarify what we're talking about.
"clk" ?
Missing space before function arguments, i.e. "function (...)".
Especially this class supports the renaming to lowercase ;)
Forgot the global renaming of "javascript" to "JavaScript" in this file.
Beer-o-mania starts in 20 days! Don't drink and patch.
Comment #36
merlinofchaos CreditAttribution: merlinofchaos commentedUpdated patch. Addresses most of sun's review. Fixes the tabledrag problem (settings were not being properly transmitted back). Fixes some CSS problems I spotted thanks to sun's review. Re-breaks the poll test.
TODO, still:
Document #ajax
Document use-ajax class
Document use-ajax-submit class
Fix poll test
Fix book test
Fix field test
Also for some reason this patch does not appear to delete ahah.js even though it should. patch kinda lame.
Comment #38
yched CreditAttribution: yched commentedField test failures: the first fail is
in _fieldPostAhah(). I guess that this part needs to be updated too ?
Also, this function was stolen from poll tests, so I guess some poll failures might have the same explanation.
Comment #39
merlinofchaos CreditAttribution: merlinofchaos commentedThis should pass all tests, includes the TODO documentation. I think this is ready for a real review prior to RTBC.
Comment #40
Frando CreditAttribution: Frando commentedWow, great patch. This is really flexible and absolutely coreworthy. Makes it really really simple to do the little ajax/ahah link that does a couple of small things on a page. Amazing. Documentation is also really nice.
Couple of nits
typo: alternerative
typo: colon should be a dot.
This sounds weird. Let's remove teh "AJAX-like".
Let's just move the code from ajax.insertNewContent over here. ajax.insertNewContent isn't used anywhere else, and is the actual command, so simpler codeflow++
This review is powered by Dreditor.
IMO this is RTBC, after these are fixed. Great work.
Comment #41
merlinofchaos CreditAttribution: merlinofchaos commentedI didn't move insertNewContent because the core documentation suggested it was overridable. That said I don't think overriding it is really a valid thing to do anymore, so I'm not averse to moving it. I'd like quicksketch's opinion on that, but he's not been available this week and I'm not sure when he'll have time to look at this.
For my part, I leave a week from Sunday and will not be available to carry this after that, so that's a hard window on my participation here.
I'll upload a new patch with the rest of the fixes shortly.
Comment #42
Frando CreditAttribution: Frando commentedWRT to the insertNewContent code: it will still be overrideable even if it's in Drupal.ajax.commands.prototype.insert, so no loss of functionality at all by moving it to the more logical place.
Instead of overriding
Drupal.ajax[my_base].insertNewContent
you'd overrideDrupal.ajax[my_base].commands.insert
in your behaviour. Both ajax.prototype.insertNewContent and ajax.prototype.commands.insert are eqally accessible/replaceable for a specific form element inside a behavior since the ajax objects were made public in #396466: Support custom success callbacks in ahah.js, I think.Comment #43
merlinofchaos CreditAttribution: merlinofchaos commentedYou are totally right. Ok, I'll address that and upload a new patch shortly. Thanks!
Comment #44
merlinofchaos CreditAttribution: merlinofchaos commentedHere we go. All of Frando's nits addressed.
Comment #45
catchI started a nitpick pass, but frando beat me to it. Didn't spot anything beyond those (or even all the ones frando found).
Comment #46
catchTwo more nitpicks:
Seems like this variable is set but never used?
s/settings/setting
Also, not a nitpick, but what a lovely hunk:
I haven't played with the AHAH stuff really yet, so not qualified to review on functionality, but in general this makes things a lot more readable from the perspective of someone not familiar with the existing code, and it seems like the people who are familiar with it are also very happy, so should be otherwise rtbc I think.
Comment #47
merlinofchaos CreditAttribution: merlinofchaos commentedUpdated for catch's nitpicks
Comment #48
drewish CreditAttribution: drewish commentedwow... looks really good... but i manged to find some nits to pick :D
Boolean should be capitalized since it's named after George Boole:
I think it would be helpful to add parens after drupal_json so it's clear we're referring to the function:
Please capitalize URL:
The description of ajax_command_error() doesn't match the format used by all the other ajax_command_*() functions.
The description of ajax_command_html() doesn't match the format used by all the other ajax_command_*() functions. It should say something about creating a jQuery html command for the AJAX responder. The current description would be great for a second line.
I'm not sure what to make of the "key:" bit here...
Actually there's a few of those... it doesn't seem like the rest of core's docs.
The description for ajax_command_css() is wrong. I'd also like another sentence explaining what it does.
I'd love to see a couple more comments in Drupal.behaviors.AJAX.attach. I'd also suggest reviewing the comments that are in there. They could use some work.
The wrapping on this seems off or that there should be two paragraphs:
There's an extra space after URL:
Couple of small things here, the whole "in. form.clk" is odd. We should probably quote the form.clk part. And there's a teh in there:
I'd love a line of white space after the block of code and before the comment here:
It would be nice it we explained why we wanted to detect the enter key and special case it:
Small one but I think we capitalize HTML in comments:
misc/ajax.js the insert command references a jQuery issue (http://dev.jquery.com/ticket/1152) that's been marked as a duplicate so we should probably reference the updated ticket: http://dev.jquery.com/ticket/3178
Grammar bug:
Should probably be "Determine what effect to use..."
This was mentioned once up thread but in poll.test:
You should probably copy the comment from field.test where it's already been fixed.
I always like it when these type of comments explain why you're doing something then how you're doing it. How about:
Actually maybe we should make that "<iframe>"? to match the "<textarea>" mentioned in ajax_render()?
Comment #49
merlinofchaos CreditAttribution: merlinofchaos commentedUpdated patch. Addresses most of drewish's nits.
However:
It would be nice it we explained why we wanted to detect the enter key and special case it:
It would be nice. I just moved this from ahah.js to ajax.js and I do not feel comfortable trying to explain why. I can guess but I'd rather not put a guess in the documentation. Then it becomes fact.
I also didn't do anything about "This doesn't really match other core docs." I'll let someone who really gets core docs to submit a followup patch if those things need changes, but I don't have the energy to spend on docs especially when I still haven't written all of the book stuff I'm supposed to do. :)
Comment #50
drewish CreditAttribution: drewish commentedOn the whole this patch keeps getting better the more I look at it. I've fixed a few capitalization, punctuation and line wrapping issue issues.
I'm not sure what is meant by the header here:
Does that refer to the Content-type header?
Is started synching up the descriptions of ajax_command_*() functions. I kind of punted on the ajax_command_error() one. It'd be nice if someone (read: Earl) could take a look at it.
It would be nice if these commands referenced the JS object where they're implemented, e.g. ajax_command_replace() Drupal.ajax.prototype.commands.insert... and in the process of looking that up I realized I was confused because in PHP space the command is "error" but in JS space it's "alert". I'm not sure if it makes sense to get the names to match up but if we don't then we should definitely reference the JS code that implements the commands.
I started doing some actual testing on this using the upload.module and got the following warnings:
But after reverting the patch found the same warnings so I don't think they're related.
I thought poll module was a little wonky in that if you re-order items and then click "preview" or "more choices" the order gets reset. But reverted the patch and it's wonky both ways.
Comment #52
drewish CreditAttribution: drewish commentedtalked with earl on irc about fixing the docs for the ajax_command_*() functions. i think i've got a pretty good start on explaining what's returned, where those commands are implemented in JS and if/when they map to jQuery code.
the bot doesn't seem to like my patches but lets see if this one works better.
Comment #54
mattyoung CreditAttribution: mattyoung commentedShould also detect
event.keyCode == 10
, iPhone Safari send 10 for ENTERComment #55
drewish CreditAttribution: drewish commentedmattyoung, i'm not sure i really want to make that change as part of this issue. it's a "pre-existing condition" probably merits it's own discussion. care to open up a new issue for it?
Comment #56
merlinofchaos CreditAttribution: merlinofchaos commentedTwo quick notes. drewish's update of the documentation hilited that there probably needs to be an 'alert' command that maps to the 'alert' function, since right now we only use it for errors but alerts could be for things that are not errors, and we do not offer that option. That's a silly oversight. I'm not sure if it should be renamed to ajax_command_alert and to add a $title argument (which means ajax_command_error usages get a little more awkward) or if we should *add* an ajax_command_alert and have ajax_command_error pass through to it, filling in the t('Error') title.
The second note is that 'replace' is actually using empty() and insert() and in fact my original implementation of replace used replaceWith() which includes replacing the wrapper. This is actually very important in some situations because it's actually difficult to have a wrapper in some circumstances. For example, if you want to replace a single row of a table, it's really convenient to have the id on the
<tr>
tag and to replace the entire tr. And in fact in my usage, this turned out to be much more desired than the standard insert behavior. So I think I need to restore that behavior so that there is a replace and an append or maybe append can gain a provision to empty() the wrapper first.Given that *all* the usages of this in core go out of their way to provide an extra wrapper, I think switching to the replaceWith method would actually work a little more nicely since it'll allow us to avoid doing this:
The above is silly and annoying anyway.
Finally, drewish's documentation changes look quite good. I've discussed a little bit and while no one has said "Yeah!!" to it, I've not gotten any objections yet either, so I'm thinking to formally name this system DJON, or the Drupal JsON system.
I'm gone for most of the day but I may get to work on this tonight. If not, there's tomorrow. Alternately either sun or drewish should be capable of acting on the above.
Also, despite test bot being unable to apply drewish's patches, they apply fine for me.
Comment #57
drewish CreditAttribution: drewish commentedmerlin, what do you think about just renaming ajax_command_error() to ajax_command_alert()? the only place it's called is ajax_render_error(). i think it's better to keep the php function->protocol command->js function naming as simple as possible. it seems like ajax_render_error() would be the best place to address error handling anyway, rather than in a command building function.
using replaceWith() seems like a really good solution. i'll start on that once i'm done cooking this batch of beer.
the DJON name sounds fine to me but i'll hold off on changing the docs until there's more feedback.
Comment #58
mattyoung CreditAttribution: mattyoung commented#55
>care to open up a new issue for it?
#550360: AHAH framework needs to check for keyCode == 10 in addition to keyCode == 13
Comment #59
merlinofchaos CreditAttribution: merlinofchaos commentedYea, renaming command_error to command_alert makes sense. The shortcut is ajax_command_error, no need for 2.
Comment #60
drewish CreditAttribution: drewish commentedmade the changes in #57.
I've changed replace() to use replaceWith() but removing the
unset($choice_form['#prefix'], $choice_form['#suffix']);
bits was resulting in extra DIVs. In the process I started trying to see where ajax_command_replace() was called and noticed that the selector was being omitted. After puzzling over that for a bit I discovered that if you omit the selector then it provides the element as the default (right?).Also does alert really take two parameters? I couldn't seem to find any documentation supporting that.
Comment #61
merlinofchaos CreditAttribution: merlinofchaos commentedI thought alert took a title and a text. doesn't it?
Comment #62
drewish CreditAttribution: drewish commentedokay dropped the title from alert and fixed the selector docs. i think i've broken something though... the ajax bits aren't going...
Comment #63
sunok, first of all, this is a re-roll of drewish's last patch, because that was partially reversed.
Comment #64
sunNot quite. It seems, some hunks got lost during the past re-rolls.
Comment #65
sunFinal review + test.
Comment #66
sunReady to fly.
A few changes:
- I've introduced a drupal_alter() JUST to have it there, because that would turn out to be an API change later on, unlikely to be added later:
- I replaced all references to JavaScript functions with proper @see directives:
Just because our API parser doesn't grok JavaScript, this doesn't mean that we can't use the proper syntax.
- I re-introduced blank PHPDoc lines between @param, @return, and @see directives for better readability:
- Changed all instances of $().size() into $().length.
- The 'changed' AJAX command now uses a CSS class name with a proper namespace ("ajax"). Additionally, $star has been changed into $asterisk:
Comment #67
sunI want to amend that uploading an attachment throws a boat of PHP notices at you. However, that's not caused by this patch (they also appear without it) - it seems like drupal_process_form() is horribly broken currently.
Comment #68
drewish CreditAttribution: drewish commentedsun,
i'm a bit surprised that you RTBCed your own patch... usually you're a stickler for protocol.
i specifically didn't use the PHPDoc @see tag because it'll give you a useless link that doesn't help you figure out where the method lives. i wanted the reference to be usable. until we have a working parser lets make it easy on the reader rather than being "correct".
i also encountered those those php notices and mentioned them back in #50.
Comment #69
sunRevamped introduction in ajax.inc.
Watch the patch name! XD
Comment #70
sunReverted the change to @see for JS function pointers to keep all of us happy :)
Comment #71
webchickStarting with a docs-only review:
1. I'm really encouraged to see the level of review that this patch has received. Makes me feel pretty comfortable committing it once i've had a good pass at it. Thanks for all of your hard work.
2. I am NOT a JS developer, so I am completely befuddled about some of this stuff and have tried to make comments accordingly. You can argue back that these docs are not for people like me, and that is fine. However, since #ahah ties into the form API, i think it would be lovely if your average PHP developer could use it, and I think that's its intention. That said, if I say something *very* silly, feel free to ignore it and chalk it up to 2am. ;)
I'm sure that's very technically accurate, however it went zooming way over my head. I don't think that it's Drupal's job to define AJAX, but something that would really help here is an architectural overview of how this system works.
For example (update for actual correctness):
"Drupal's AJAX framework is used to dynamically update parts of a page's HTML based on data from the server. Upon a specified event, such as a button click, a callback function is triggered which performs server-side logic and then returns updated markup, which is then replaced on-the-fly with no page refresh necessary."
Finally, what would really gel it for me is instead of talking about a PHP macro language, show me some code snippets like there are in this issue of a simple form, a simple callback, etc.
There are far too many "F" APIs in Drupal now to get away with "FAPI". ;)
Probably specify "menu path" here, as opposed to file path some other kind of path. Also indicate what needs to happen at this path. Maybe something like, "The menu path to use for this request. This path should map to a menu page callback that returns JSON."
Also, I don't think this is your intent, but reading this makes me now terrified to use the default path and thinking it's very limited and will blow up in my face. Can we re-phrase that so it sounds more positive? :P Like "The default path is useful for .... but in the event you need something more fancy, you may also define your own custom path."
Also, on this and others, can we get an indication of which fields are required? See http://api.drupal.org/api/function/hook_theme for an example.
What if I'm not using the default path? Maybe swap these around, so that we actually define the index first, then talk about the default path after?
This assumes I know AJAX areas should have IDs. Let's make sure to mention that in the paragraph at the top that gives an overview of how this works.
I'm confused about "is often created using #prefix and #suffix tags". Is there a way to write this more clearly, and/or could we use a code example here?
How do I know the default behaviour? Can you give me some hints?
Feel free to say no, since you're pointing me off to the jQuery docs anyway, but is there any way you could put in parentheses what 'html' does? The rest are pretty clear.
1. FAPI again.
2. Also, can we move "This is particularly useful for things such as pop-ups" before the implementation details? ("By adding the 'use-ajax' class...") I was just going to type "You should tell me why I'd use this" when you did, a couple sentences later. ;)
Also, this is back into fuzzyville. I can haz code example?
What type of commands can go in a commands array? Are these PHP functions or JS functions or something else entirely?
Oh, I see. It's an object. please tell me that a little sooner. I don't know what the Drupal.ajax[command] space means. But I guess you mean a JS function that's in scope. How do I get stuff in scope?
Also, "correlate"
I feel like this code is meant to be self-explanatory, but it's not for me...
I *think* what this might be saying is:
$commands = array();
// Replace the contents of the 'object-1' ID's element on the page with 'some html here'
$commands[] = ajax_command_replace('#object-1', 'some html here');
// Notify the #object-1 element that it has changed since the last request.
$commands[] = ajax_command_changed('#object-1');
// Output new markup to the browser and end the request.
ajax_render($commands);
...but I'm not positive.
14 days to code freeze. Better review yourself.
Comment #72
quicksketchI've been promising a review on this for a while now so here we go.
First of all, this patch is FLIPPING AWESOME. I'm really happy that merlinofchaos (and team) has made this great effort. The "Core" approach with #ahah and the "Views/cTools" approach with AJAX commands have from the beginning been taking completely dividing efforts. This patch unifies the approaches while maintaining all the functionality from both of them. Despite the length of the patch, this patch introduces a very small API change for people familiar with the current system, since it essentially just renames "#ahah" to "#ajax", which is probably a good change for recognizably.
My only structural complaint is that I'm not a big fan of the "automatic" replacement of "nojs" with "ajax" in URLs. Though at the same time I know that this is what Views and Panels use, and I know it can work for any application, I just usually prefer to use an indicator like "?js=1" in the query string. However... this has absolutely NO effect on the use of the #ajax (formerly #ahah) property, and it doesn't prevent using that other mechanism if desired later. So even though it's not the approach I'd use, there's nothing wrong with it and it's obviously proven to work through the D6 release cycle in Views.
Okay first pass just on reading the code:
- The one-line description for ajax_process_form() is too long:
- Even though I know that ajax_process_form() is essentially a clone of form_process_ahah(), we should switch to using #attached_js and #attached_library in ajax_process_form().
- #ajax['path'] documentation is incorrect, since it can be used on any element. #ajax['callback'] is the one that will only work on buttons.
- The use of @see is a bit strange in places. Usually @see is left until the end of docs, but with all the ajax_command_* functions, it's in two separate places, both before the parameters and after them.
Just to test out *crazy* edge case scenarios I applied the CCK UI patch, installed the CVS HEAD of File module, AND this patch to test compatibility. I was able to "port" File module to the new system in 2 minutes, and every thing work absolutely perfectly. Other than small nitpicks, this patch is completely architecturally sound and a complete breeze to leverage for someone familiar with the current system.
Comment #73
webchickAlso, near the top it might be good to mention that there are three ways to attach AJAX to Drupal's output: through form elements, through link clicks, and through button clicks. That would help with my surprise that the docs just go on and on and the bottom part has nothing to do at all with what the top part was talking about. :)
Comment #74
webchickOopsie.
Comment #75
sunAll nitpicks and feedback incorporated.
- #attached_library doesn't exist yet.
- @see is perfectly valid in between. To be used where it makes sense most for the reader of API documentation to refer to related information.
Comment #76
chx CreditAttribution: chx commentedNot even a watchdog?
And if it's not then...?
Use
$commands = array(ajax_command_replace(NULL, $html));
But why not just
$commands = $callback($form, $form_state);
and then use this "if string convert to whatever"? Saves the else (but not the comment I asked for in the previous hunk!)I stopped reading approx here because a) it's too late and I have a long flight tomorrow (sorry) b) apparently there is a new array structure in town which does the awesomeness and even if it's documented somewhere there needs to be an awful lot of @see to that place.
15 days to code freeze. Better review yourself.
Comment #77
sunIncorporated most of chx's feedback.
Ready to hit the floor to do some windmills and foot-work, to dis #ahah. Yay! Where's the party at?
Comment #78
webchickYou know, I honestly spent quite some time looking for something to nitpick in the code, but it seems like that's basically all been done for me. ;) There are a couple of spots I still find a bit confusing, and I'm sure the documentation could be improved even more, but this has the buy-in from every major player in this space and I'm pretty confident anything else remaining could be handled in a follow-up patch.
Therefore... committed to HEAD!
This will definitely need some upgrade docs. Marking needs work for upgrade documentation.
Comment #79
webchickSorry!! I get the dunce cap of shame. I remembered ahah.js and ajax.js but missed ajax.inc. All of our lovely docs! Sniff!
Should be good now.
Comment #80
yched CreditAttribution: yched commentedYay ! I'll update #367567: Use AJAX framework for "Add more" / load include file containing form / introduce $form_state['build_info'] with a new patch when I return to my coding env in a couple days.
Comment #81
merlinofchaos CreditAttribution: merlinofchaos commentedYay committed!
Just a quick note:
I object to this:
Because if we ever want to change it and add another command there, the code is harder to restructure. Plus, the 'formula' of 'create an empty command array and then add commands to it' is disrupted somewhat. I realize this is not a super big deal, but I liked the DX of always doing it the same way.
Comment #82
emjayess CreditAttribution: emjayess commentedHi all, just stumbled in via earl's tweet; sounds bloody awesome and all that, and trying to wrap my head around it...
Question: does this have any facilities (or leave room for) content [type] negotiation? e.g.
jQuery.ajax()
options let the client specify the preferred format of the response -- xml, html, json, jsonp, script, or [plain]text -- by setting theAccept
HTTP header on the request, and the server/php can process & respond accordingly...I can understand if this is a non-concern to the discussion of applying this to core, whereas everything in core can follow a JSON/DJON declared "Drupal Way"... but should this consideration be addressed & made available for emerging applications, cross-app interop, etc?
Comment #83
merlinofchaos CreditAttribution: merlinofchaos commentedNo, this specifically uses JSON and a well-known protocol specifically to make it easier for Drupal modules to do this. For external stuff that may need its own protocol, you'll have to go back to a more raw $.ajax call.
Comment #84
sunMinor follow-up, adding the requested watchdog() I forgot, and reverting the command syntax.
Additionally, the links to the ajax_command group didn't work out. So trying to fix that, too.
However, looking http://api.drupal.org/api/group/ajax/7, it seems we can just link to that page in the upgrade docs.
Comment #85
merlinofchaos CreditAttribution: merlinofchaos commentedNo comments on the @link but I approve of the watchdog and the other changes.
Comment #86
sunso, well - not sure whether it groks that combination of @see and @link, but we'll see.
Comment #87
Dries CreditAttribution: Dries commentedCommitted to CVS HEAD. Thanks!
Comment #88
sunThanks!
Still needs documentation. I guess it boils down to replacing the FAPI property #ahah with #ajax (no inner changes). Advanced AHAH usage needs to be replaced with the new command structure, but that's explained in detail in the API.
Comment #89
jhodgdonI have put this into the module update guide: http://drupal.org/node/224333#ahah-now-ajax -- if someone could look over the example and verify that it was a good choice, and/or put in a different one that's better, that might be useful.
I can probably also update the FAPI reference page (http://api.drupal.org/api/file/developer/topics/forms_api_reference.html/7, which is in the contrib repository), though I am not sure what to do with the current #ahah section... I'm tempted just to refer to other doc, such as http://api.drupal.org/api/group/ajax/7 -- or is there more information elsewhere, with examples? Here's the current AHAH section:
http://api.drupal.org/api/file/developer/topics/forms_api_reference.html...
However, before I do that editing, one thing I noticed is that the doc page http://api.drupal.org/api/group/ajax/7 doesn't include the #ajax['progress'] parameter, although it appears that it still applies.
Comment #90
mattyoung CreditAttribution: mattyoung commented>important to ensure that this wrapper exists in the form
Is it true the wrapper can only be part of the form? What if I want ajax update to some area outside of the form?
Comment #91
rfayI'll work the docs. If anybody has any additional info you want to communicate, give me a yell.
Comment #92
rfay@mattyoung (#90) I can confirm through experimentation that, as always, there is no need for the ID to be within the form. However, I will try to figure out if this is just a bug in the docs or if there's some reason for it.
Comment #93
rfayI updated the upgrade guide to the current API, so now people should be able to upgrade successfully. However, this remains a pet issue of mine and I'll attempt to get much better docs of the whole out there. For now, I've posted a working Drupal 7 AJAX module on http://randyfay.com/ahah/drupal7 and will work toward complete docs including docs of the new ctools-derived AJAX Framework Commands.
@jhodgdon: Re #89:
Comment #94
merlinofchaos CreditAttribution: merlinofchaos commentedI would not say that 'path' is deprecated. Even if we fix it so that most things can use system/ajax, none of my stuff is ever likely to because I am still mostly incompatible with form caching. Marking it deprecated means some enterprising soul might think it's ok to take it out and that would make me sad.
Comment #95
mattyoung CreditAttribution: mattyoung commented>"It is important to ensure that this wrapper exists in the form." is incorrect as far as I've been able to determine. The ID can be anywhere in the page, although it's most common that you would be replacing a portion of the form.
What if I want to update multiple wrappers all over the page? Can this framework support this?
Comment #96
drewish CreditAttribution: drewish commentedOf course. Build your own callback and send insert/replaceWith command(s) with a jQuery selector that targets your wrappers.
Comment #97
rfay@merlinofchaos: I agree, deprecated is not the right word. A better way to say is is "for simple jobs, 'callback' will almost always be used. 'path' is for situations that the generic code that calls 'callback' does not accomplish.
@mattyoung: With the framework as it is, you get one wrapper per #ajax. However, if you use merlinofchaos's far more extensible Ajax Framework Commands, then you can issue multiple commands at once, and before long you'll build panels :-)
Comment #98
rfayI updated the Form API Reference with the updated information. Commit #256138
Attached is the patch for ajax.inc to update the documentation included in that file.
Comment #99
jhodgdonA couple of minor issues with the patch:
a) I think a couple of the lines are more than 80 characters.
b) I wouldn't mention "...is new in Drupal 7". We generally don't in API doc.
c) Maybe refer to #ajax['callback'] as "the name of a callback function" rather than just "callback", for clarity.
d) I couldn't figure out from that doc what HTML is replaced by the return value of #ajax['callback']? 'wrapper' just says it is used for 'path'.
Comment #100
jhodgdonRegarding your changes to the FAPI doc, you changed a LOT of lines -- see http://cvs.drupal.org/viewvc.py/drupal/contributions/docs/developer/topi... -- so it's really hard to review. Sigh.
Comment #101
rfay@jhodgdon, I used an HTML editor due to the difficulty of working in HTML with those horrible examples. It added missing elements like tbody to the file. Sorry for the inconvenience. However, when I did a diff, it was obvious what were semantic changes and what were line wrap changes. My preference is always to just work with HTML, but with a document this complex, I was forced out of that strategy.
Comment #102
jhodgdonIt isn't obvious which are line wrap changes on that page cited above -- could have slipped in a word change and no one would be the wiser. ;)
Anyway, thanks for the edits!
Comment #103
rfayHere's the updated patch reflecting comments in #99.
Comment #104
sunCan we move the "Note" before the sentence about 'path' ?
(and elsewhere) Lines are exceeding 80 chars.
We should additionally state that 'wrapper' must be used without leading # sign. Found it out the hard way on my own. ;)
A @see would be nice here. (on a new line)
Beer-o-mania starts in 3 days! Don't drink and patch.
Comment #105
mcrittenden CreditAttribution: mcrittenden commentedSub.
Comment #106
rfayHere is the updated documentation patch re: the issues in #104. Thanks for your review, @sun. And I finally learned how to turn on Eclipse's 80-character limit line :-)
Comment #108
rfayComment #110
sunRe-rolled. Looks RTBC.
Comment #111
jhodgdonLooks like both sun and rfay like this patch, the testing bot likes the patch, and I also think it looks good from a structure and writing point of view. That should be enough. :)
Comment #112
webchickCommitted to HEAD. Thanks!
Comment #113
effulgentsia CreditAttribution: effulgentsia commentedThanks again to everyone who worked so hard to get this AJAX framework into core. I'm looking forward to seeing some pretty sweet contrib modules come out for D7 that take advantage of it. I submitted a follow-up issue to address a WTF that's been bugging me with respect to AJAX callbacks having a fundamentally different return signature than normal page callbacks: #599804: Unify page, AJAX 'path', and AJAX 'callback' callbacks. I know most of you are super busy with a ton of other issues, but if any of you can spare some time to review it, I'd appreciate it. Thanks!
Comment #114
rfayDocumentation followup on this is moving to #610068: Document AJAX no-js and use-ajax. Many issues can be combined there.
Comment #116
effulgentsia CreditAttribution: effulgentsia commentedSeeking help from someone who understands how AJAX and FAPI are supposed to work together. There appears to be a critical bug in this regard that might require an API change. But we're stuck on knowing what the bug is, because we're confused about how multi-step FAPI forms are supposed to work. Please see http://drupal.org/node/622922#comment-2235954.
Comment #117
srisso CreditAttribution: srisso commented(Sorry for my english, I'm French)
I've got this error message when I want to simulate the shipping
Une erreur HTTP AJAX s’est produite.
Code de statut HTTP : 500
Informations de débogage ci-dessous.
Chemin : /drupal/drupal-7.12/ ?q=system/ajax
StatusText : Internal Server Error
ResponseText :
I've try to apply your patch but I've obtain this error message
root@sylvain:/var/www/drupal/drupal-7.12/includes# patch -p1 --dry-run -i drupal.ajax-docs.patch
patching file ajax.inc
Hunk #1 FAILED at 26.
Hunk #2 FAILED at 53.
2 out of 2 hunks FAILED -- saving rejects to file ajax.inc.rej
Anyone could help me please ?
Comment #118
shantanu1 CreditAttribution: shantanu1 commentedWrite your first ajax form submit.....
Thanks
Shantanu Karmakar