Currently in HEAD, we have three types of "page" callbacks:

  • Normal page callbacks return a string of html, or better, a renderable array, that gets passed back to index.php which then calls drupal_render_page() on it.
  • AJAX callbacks invoked via $element['#ajax']['callback'] can return a string of html or an array of AJAX commands (which although an array is NOT the kind of renderable array that normal page callbacks return) or can issue ajax_render() themselves forcing an exit.
  • AJAX callbacks invoked via $element['#ajax']['path'] can't return anything, because doing so would trigger print drupal_render_page() and drupal_page_footer(), neither of which is desired in AJAX context. Instead, these kinds of callbacks MUST issue ajax_render() themselves forcing an exit.

YUCK!!

My proposal coming in a follow-up comment.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

effulgentsia’s picture

Status: Active » Needs review
FileSize
18.16 KB

Here's my proposed patch to deal with this. This patch introduces a separation between a "page callback" (whose job is to return an html string or a renderable array) and a "delivery callback" (whose job is to use the appropriate mechanism to send the result of a page callback to the browser). This allows all 3 types of page callbacks described at the top of this issue to be equivalent with respect to what they return: either an html string or a renderable array. Specifically, this patch:

  • Adds a delivery_callback field to the {menu_router} table.
  • Adds drupal_deliver() and drupal_deliver_page() functions to common.inc and changes index.php to use drupal_deliver() instead of hard-coding a delivery mechanism.
  • Adds ajax_deliver() to ajax.inc and sets up some, but not all, AJAX callback paths to use it. I setup a couple this way to demonstrate the code, but not all to both keep this patch smaller and to demonstrate that the code is "backwards compatible" (if an AJAX callback issues its own ajax_render() forcing an exit, then it doesn't matter what delivery callback is used, since we never get to that stage).
  • Changes ajax_form_callback() to transparently return the return value of the specific callback it calls, creating a complete unification between the two kinds of AJAX callbacks with respect to return value. ajax_form_callback() remains an awesome utility function for doing the FAPI cruft.
  • Changes poll_choices_js() to demonstrate that a renderable array can be returned from an AJAX callback, just like one can be returned from a normal page callback.
  • Creates a new renderable element type (ajax_commands), so that we retain the ability for an AJAX callback to return specific AJAX commands in situations where you want to do something more than just return HTML content. The use of this is demonstrated in book_form_update().

I kept the patch as small as possible to implement my recommendation and have a use case for each situation. If this patch lands, a follow up patch can deal with cleaning up other places to take advantage of the new capabilities.

effulgentsia’s picture

Some additional notes if you're interested in architectural implications (feel free to skip over reading this if you're not):

  • This patch was inspired by a conversation I had with crell. In that conversation, he mentioned the concept of a payload/envelope software pattern. However, as I understand the concept of "envelope", it strictly deals with wrapping a payload, but not with delivering it. I'm open to changing the name of "delivery callback" to "envelope callback", but because the delivery callback deals with printing as well as packaging, I chose the word "delivery". I could envision expanding the concept to include separate callbacks for envelope and delivery, but given where we are in the D7 cycle, I wanted to keep this patch as simple as possible. Perhaps for D8, we could investigate decoupling envelope and delivery.
  • I dislike that ajax_render() issues an exit. It sucks for unit testing or reusing anything that ends up calling it. But I decided not to deal with that in this issue. However, this patch landing would lend itself to a fairly straightforward follow up issue to change ajax_render() to not exit. That would require changing all AJAX callbacks to use the ajax_deliver() delivery callback, but that's not a big deal to do, and is arguably a good idea anyway.
  • If this patch lands, I can envision contrib modules coming up with their own delivery callbacks for things like outputting to XML or to SWF or whatever. I like that because if that happens, then when we work on refining this concept in D8, we'll have some implemented use cases to look at. Because a contrib module can implement hook_menu_alter() to change the delivery callback of any page, just about anything ought to be possible with no further changes to core. But for D8, we can add support to have the needed flexibility without resorting to hook_menu_alter().

Status: Needs review » Needs work

The last submitted patch failed testing.

effulgentsia’s picture

Status: Needs work » Needs review
FileSize
18.18 KB

Yay, testbot!

mattyoung’s picture

.

rfay’s picture

Subscribing

sun’s picture

Priority: Normal » Critical

I'm sorry. I really really love this patch. But I also really doubt that we find a valid, sustainable, working, and approved solution within the next 5 days. :-/

Feel free to try. Pulling some people from IRC into this issue might help, too.

merlinofchaos’s picture

Priority: Critical » Normal

Ok, I was dubious when I started looking at this patch. After reading the code, I think I really like this. I have two issues.

1) I normally use URL switching mechanism to do javascript degradation. i.e, you visit panels/ajax/do-something or panels/nojs/do-something and my code checks the argument and I use a menu _load() function to do the test. In this system I believe I would have to have 2 different menu entries for this.

2) Similar, other systems like to use ?js=1 as a query parameter to say that this is an ajax call. In that system, you can't do it with menu entries.

Both of these could be solved with a menu_set_delivery_callback() function. We could also theoretically introduce a standard where a query variable could *automatically* change the delivery callback. In that case, I think the order of precedence would be:

a) Was a callback set with menu_set_delivery_callback() -- if so, use that.
b) Was a type requested with a query string? -- note, we'd obviously have to map identifiers to functions for safety here.
c) Was a delivery callback set from the menu?
d) Fallback to normal HTML delivery.

3) drupal_access_denied() and drupal_not_found() should be modified respect the delivery callback. This goes well with the comment you had to @todo about error handling in either case. For both cases, ajax_command_error(t('Page not found')) and ajax_command_error(t('Access denied')) are certainly acceptable.

We already have a pretty good fallback for "I have HTML, you want it as AJAX, package it up and send it". It does require that the client know what to do with it, but I think we're well prepared for that.

effulgentsia’s picture

Thanks, merlinofchaos! I really appreciate you taking the time to probe it despite your initial reservations. This patch includes the ajax_command_alert() commands when a menu status constant is passed to ajax_deliver(). I used the same error message text as is used in the drupal_not_found(), drupal_access_denied() and drupal_site_offline() functions.

Regarding issues #1 and #2, my design goal in this patch was to make the least possible change to core. As sun says, only 5 days for this to land, so the less that's in it that's controversial, the better. That said, delivery callbacks are pluggable and chainable. So, you can implement a panels_deliver() callback that makes its own determination as to whether to route to drupal_deliver_page() or ajax_deliver() or something else, based on whatever run-time information you want to use. I'm all in favor of core having more built-in support for run-time changing of delivery callback and/or query-string conditionality of delivery callback, but what do you think of letting that be a follow up issue once this one lands? That way, if it takes more time to get everyone to agree on the details than is available before API freeze, it can get bumped to D8, but D7 would still have a way of accomplishing what's needed, just with modules having to implement their own custom delivery callback routers.

Regarding changing drupal_access_denied(), drupal_not_found() and drupal_site_offline() to be usable in contexts other than a drupal_deliver_page() delivery, I also agree that it would be nice, but also perhaps too ambitious for this patch? Regardless of whether that's done, what I would really like to see is a change to all page callbacks that call those functions to return the appropriate menu status constant instead, which IMO would be the preferable way of being delivery callback agnostic. That said, if you have an idea for how to change these functions in a way that won't derail the chances of this patch landing, please share it.

For all reviewers: regarding comment #7, please share anything you think in not valid, sustainable, or working in this patch. As can be seen from comment #8, this patch might have the flaw of not going as far with the idea as would be ideal if we had sufficient time to flush it out, but is there anything about it that would make D7 worse than not having it land?

effulgentsia’s picture

While researching something else entirely, I just happened to stumble on #145551: Enable loading and rendering into multiple formats (html, xml, json, atom, etc.), and found this neat gem in patch 91:

// jQuery sets a HTTP_X_REQUESTED_WITH header of 'XMLHttpRequest'.
if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') {
  $render_type = 'json'; 
}

I'm still wary of changing the drupal_deliver() function in patch #9 to be any more sophisticated than what's in the patch, but I also continue to like merlinofchaos' idea to allow for request-time swapping of delivery callback (i.e., menu_set_delivery_callback()), query-string based intelligence, and now, $_SERVER['HTTP_X_REQUESTED_WITH'] based intelligence. I'm open to implementing any or all of these within this patch if it helps rather than hurts the chances of this patch landing within the next 5 days. Otherwise, if this patch lands more or less as-is, I'm interested to see something like ctools implement a more sophisticated delivery callback router.

effulgentsia’s picture

By the way, one of the reasons I'm concerned about adding sophistication to drupal_deliver(), is that it might start looking to Dries like this patch is primarily a feature addition (which isn't allowed any more) rather than an API clean-up (which is this issue's primary intent, and still allowed for 5 more days). If Dries gives his blessing on a particular direction, I'll happily implement it.

effulgentsia’s picture

I got some great feedback from chx on IRC, incorporated in this patch.

@merlinofchaos: There's now a hook_page_delivery_callback_alter(). And the code example for it in system.api.php shows how you can achieve what you were wanting in #8. I'm not sure if this should remain the official code example, but I wanted to have it in this patch as a discussion point.

effulgentsia’s picture

A little cleanup, because I rolled patch 12 a little too tired. I'm liking this more and more with each pass.

effulgentsia’s picture

Sorry, forgot one other thing. This one has it.

effulgentsia’s picture

chx’s picture

This looks really good now. My only problem is with drupal_alter('menu_router_item', $router_item, $path); this is not just an ordinary menu router item but the active menu handler item. So what about drupal_alter('menu_active_handler', $router_item, $path);?

sun’s picture

Issue tags: +D7 API clean-up

Since we introduced the AJAX framework in D7, I think this can be treated as a clean-up - hence, applying the critical tag.

effulgentsia’s picture

With #16.

effulgentsia’s picture

Despite my initial reservations about scope-creep on this patch, I realized that merlinofchaos is right (this, of course, comes as no surprise) when he says in #8 that drupal_not_found(), drupal_site_offline(), and drupal_access_denied() need to respect delivery method. This patch fixes those functions. @merlinofchaos: please comment as to whether this patch now meets with your approval.

I decided against implementing a menu_set_delivery_callback() function that wraps a static variable, because I'm highly suspicious of propagating the equivalent of a global variable. I know we do stuff like that all over the place in core, but I hope we stop that practice soon. I prefer the alter() mechanism, and if a module wants to implement a static variable inside it, at least that stays out of core. I realize that creates an awkward implementation in drupal_not_found(), drupal_site_offline(), and drupal_access_denied(), and open to feedback on how to improve it, but I also hope that we don't let little details stop this issue from landing in D7.

effulgentsia’s picture

Fixed me being stupid in #19.

effulgentsia’s picture

Re-rolled.

effulgentsia’s picture

As a refresher to anyone newly looking at this issue:

The primary purpose of this patch is to remove the annoying WTF described at the top of this issue.

Some very nice side-effects of this patch are:
- It will make it possible for AJAX callbacks to not have to early exit. This will make it possible to re-use and unit-test these callbacks, which it is currently not possible to do.
- It will make it possible (with the aid of a contrib module) to deliver any drupal page as an AJAX response.
- It will make it possible for contrib modules to introduce new delivery callbacks, allowing any drupal page to be delivered as a response appropriate for the technology of choice (SWF, XML, etc.).

If you have the time, I encourage you to read the full comment trail. Or, if you prefer, simply read the patch. However, I decided to put together a textual explanation of what the patch does. I did this as an exercise for myself, so I could check whether everything in the patch makes sense. However, I'm also hoping it provides some help to anyone reviewing the patch.

Edit: notes were inlined here initially, but are now in an attached file in #24.

effulgentsia’s picture

And, yes, I'm not at all trying to hide the fact that I would really, really, really like to see this patch make it into D7. To that end, I'd like to point out that sun (#7), merlinofchaos (#8), and chx (#16) have all registered approval for it in principle. So far, only chx has signed off on the patch in its current state. Obviously, I'd like others to as well, or let me know what else needs to be done for it to be RTBC'able.

effulgentsia’s picture

FileSize
5.49 KB

Realized that comment #22 was too long with the notes inlined. Attaching here in a file instead.

Crell’s picture

Conceptually, it should be no surprise that I support this. :-) The specific implementation here is a bit ugly and does about a quarter of what it could potentially do, but as effulgentsia has noted we don't really have time for D7 to do all of the cool things that this could do. So I'm +1 in principle on this approach.

I've not gone over the code in minute detail, but some comments from just reading the patch:

- We shouldn't be hard coding the "html page" version of drupal_not_found() et al. Why do those have to be a special case instead of sub-call functions like everything else?

$delivery_callback = (isset($router_item) && $router_item && !empty($router_item['delivery_callback'])) ? $router_item['delivery_callback'] : 'drupal_deliver_html_page';

That line in menu_execute_active_handler() can easily be simplified by pre-choosing the delivery callback in menu rebuild. Just make that function name the default if one is not set, and then the DB has an accurate callback record for every router item.

OK, the additional alter hooks are just sexy. :-)

That's all I have time for right now, I'm afraid.

rfay’s picture

I apologize that I haven't had time to do a real review of this due to "real life" issues using up all my time.

However, it looks to me like there is a consensus that this is a great thing for Drupal's architecture.

Let's go ahead and take the risk and get it in.

There are times that "doing the right thing" pays off enormously, so many times over, that it's worth doing even when we're very conservative, and in this case, even at the very end of the cycle.

My 2 cents.

effulgentsia’s picture

With Crell's feedback (both from #25 and IRC) to make drupal_not_found() and friends not be partial to HTML page delivery.

Did not implement Crell's suggestion to make 'drupal_deliver_html_page' a default in the router table. We still need to have that be a default in code to handle the situation when no router item is returned. This way, that default only exists in one place.

Also followed sun's suggestion to put some of what's in the notes in #24 into the code comments. I think it's now possible to just read the patch and understand what's going on, but I've been staring at this for a while, and so might not be the best judge of that. The notes from #24 are still useful as background information for anyone who wants it.

Status: Needs review » Needs work

The last submitted patch failed testing.

effulgentsia’s picture

Status: Needs work » Needs review
FileSize
35.91 KB

Hmmm. Works on my machine without syntax error. Trying again, in case it was a testbot fluke.

sun’s picture

This is RTBC for me - aside from the following comment tweaks: (please mark as RTBC after fixing these)

+++ includes/ajax.inc	15 Oct 2009 04:41:40 -0000
@@ -291,30 +291,56 @@ function ajax_form_callback() {
+ * Package and send the result of a page callback to the browser as an AJAX
+ * response.

(and elsewhere) PHPDoc summary shouldn't wrap at 80 chars. Just remove the newline.

+++ includes/ajax.inc	15 Oct 2009 04:41:40 -0000
@@ -291,30 +291,56 @@ function ajax_form_callback() {
+        break;
+      case MENU_ACCESS_DENIED:
...
+        break;
+      case MENU_SITE_OFFLINE:

(and elsewhere) There should be blank line between case statements of a switch (as long as you don't fall-through).

+++ includes/common.inc	15 Oct 2009 04:41:40 -0000
@@ -665,75 +665,45 @@ function drupal_goto($path = '', array $
+ * Whenever possible, write page callback functions to return MENU_SITE_OFFLINE
+ * instead of calling drupal_site_offline(). However, until Drupal implements
+ * exception handling, if you're writing a function that is called by a
+ * page callback function, and returning MENU_SITE_OFFLINE from your function
+ * would not chain up back to menu_execute_active_handler(), then calling
+ * drupal_site_offline() is appropriate.
  */
 function drupal_site_offline() {

(and elsewhere)

Please re-phrase into 3rd person here. So instead of referring to "you", we refer to "page callback functions", or, "the/a module".

Also, we do not talk about the future, so let's drop that part about exception handling ;)

+++ includes/common.inc	15 Oct 2009 04:41:40 -0000
@@ -2592,6 +2562,155 @@ function l($text, $path, array $options 
+ * When a user requests a page, index.php calls menu_execute_active_handler()
+ * which calls the 'page callback' function registered in hook_menu(). The page
+ * callback function can return NULL (to indicate no content), an integer
+ * menu status constant to indicate an error condition, a string of HTML
+ * content, or a renderable array of content. It is recommended wherever

This should be formatted as PHPDoc list.

+++ includes/common.inc	15 Oct 2009 04:41:40 -0000
@@ -2592,6 +2562,155 @@ function l($text, $path, array $options 
+ * For example, the same page callback function can be used for an HTML
+ * version of the page and an AJAX version of the page. The page callback
+ * function just needs to decide what content is to be returned and the
+ * delivery callback function will send it as an HTML page or an AJAX
+ * response, as appropriate.

How can a page callback decide? From the previous paragraph, I understand that the page callback is invoked first, returns its results, and meah() determines the delivery callback. My missing link is how my page callback can define/override this delivery callback, because this paragraph states I can.

+++ includes/common.inc	15 Oct 2009 04:41:40 -0000
@@ -2592,6 +2562,155 @@ function l($text, $path, array $options 
+ * @param $default_delivery_callback
...
+ *   to be appropriate for the page request. If not given, it is determined
+ *   from the menu router information of the current page. In either case,
+ *   modules have a final chance to alter which delivery function is called. 

Outdated?

+++ includes/common.inc	15 Oct 2009 04:41:40 -0000
@@ -2592,6 +2562,155 @@ function l($text, $path, array $options 
+  // Give modules a final chance to alter the delivery callback used. This is
+  // for modules that need to decide which delivery callback to use based on
+  // information made available during page callback execution and for pages
+  // without router items.
+  drupal_alter('page_delivery_callback', $delivery_callback);

Now I think I understand - so the PHPDoc description above should just be appended by a

@see hook_page_delivery_callback_alter()

+++ includes/common.inc	15 Oct 2009 04:41:40 -0000
@@ -2592,6 +2562,155 @@ function l($text, $path, array $options 
+  if (function_exists($delivery_callback)) {
+    $delivery_callback($page_callback_result);
+  }

What's the result if the function doesn't exist?

If it's intentional to return NULL, let's append a comment at the end to clarify so (and perhaps why).

+++ includes/menu.inc	15 Oct 2009 04:41:41 -0000
@@ -401,29 +401,52 @@ function menu_get_item($path = NULL, $ro
+ * @param $deliver
+ *   A boolean. If set to TRUE, the page is sent to the browser using the
+ *   appropriate delivery callback. If set to FALSE, the result of the page
+ *   callback is simply returned to the client code.
  */
-function menu_execute_active_handler($path = NULL) {
+function menu_execute_active_handler($path = NULL, $deliver = TRUE) {

@param description should start with:

(optional) A boolean to indicate whether the content should be sent to the browser using the appropriate delivery callback (TRUE) or whether to return the result to the caller (FALSE).

+++ includes/menu.inc	15 Oct 2009 04:41:41 -0000
@@ -401,29 +401,52 @@ function menu_get_item($path = NULL, $ro
+      drupal_alter('menu_active_handler', $router_item, $path);

Short inline comment about the purpose of this alter?

+++ modules/system/system.module	15 Oct 2009 04:41:42 -0000
@@ -307,6 +307,21 @@ function system_element_info() {
+  $types['ajax_commands'] = array(
+    '#ajax_commands' => array(),
+    // AJAX commands are used by AJAX callbacks to return a set of javascript
+    // commands for the browser to execute. When using the ajax_deliver()
+    // delivery callback, these get rendered by ajax_render(). It's possible
+    // (though not necessarily useful) to create a page callback that returns
+    // AJAX commands that are delivered to the browser using
+    // drupal_deliver_html_page(). In this case, this element would be rendered
+    // using #theme and #theme_wrappers functions as is the case with other
+    // renderable elements. By default, we don't want AJAX commands being
+    // rendered in the context of a normal HTML page, so we don't provide
+    // defaults for #theme or #theme_wrappers. However, modules can set these
+    // properties if they would like (for example, to provide a debugging page
+    // that displays rather than executes AJAX commands).
+  );

This comment should be above the type definition, not within the array.

Should also be shortened... probably all up to (and including) "In this case" can more or less go, because that's documented in ajax.inc. Here, we should explain renderable array internals/tricks only.

This review is powered by Dreditor.

sun’s picture

Title: Unify normal page callbacks, AJAX callbacks using 'path', and AJAX callbacks using 'callback' » Unify page, AJAX 'path', and AJAX 'callback' callbacks

Better title?

effulgentsia’s picture

Title: Unify page, AJAX 'path', and AJAX 'callback' callbacks » Unify normal page callbacks, AJAX callbacks using 'path', and AJAX callbacks using 'callback'
Status: Needs review » Reviewed & tested by the community
FileSize
36.78 KB

Setting RTBC as per #30.

Webchick/Dries: please see issue description and/or comment #22 for a high level "WHY?".

effulgentsia’s picture

Title: Unify normal page callbacks, AJAX callbacks using 'path', and AJAX callbacks using 'callback' » Unify page, AJAX 'path', and AJAX 'callback' callbacks

Did not intend to change title in #32.

Dries’s picture

Status: Reviewed & tested by the community » Needs work

I have to let this slip in because, well, this is exactly the architecture that I outlined 3-4 years ago!

Unfortunately, the patch no longer replies so it needs a reroll. I did a review so it should be RTBC after a reroll.

catch’s picture

Status: Needs work » Needs review
FileSize
36.78 KB

This is hopefully a straight re-roll, setting CNR. Please do not commit until tests are green.

catch’s picture

Status: Needs review » Reviewed & tested by the community
Dries’s picture

Status: Reviewed & tested by the community » Fixed

Alright, committed! Great job all.

moshe weitzman’s picture

Assigned: Unassigned » moshe weitzman
Status: Fixed » Needs review
FileSize
1.12 KB

Nice patch!

We should emit the standard http header only for http delivery. This helps command line scripts a lot. 1 line patch attached.

moshe weitzman’s picture

What do folks think about turning drupal_serve_page_from_cache() into a delivery callback? Thats what does the http headers and such for cached pages. Not sure how we go about terminating the request flow and immediately delivering the page. Still use exit?

Status: Needs review » Needs work

The last submitted patch failed testing.

moshe weitzman’s picture

Status: Needs work » Needs review

I can reproduce those test failures, but have no clue how I've triggerred that. Anyone hav a clue. Failure is on line 139 of openid.test?

effulgentsia’s picture

Status: Needs review » Needs work

The problem is that the openid_test_yadis_xrds() function in openid_test.module prints instead of returns, which is the current convention for any callback that needs to output something that it doesn't want routed through drupal_render_page(). As long as page callbacks issue print statements (or call functions that do), delivery callbacks can't call header(), since header() can't be called after print(): http://php.net/manual/en/function.header.php.

effulgentsia’s picture

Status: Needs work » Needs review
FileSize
1.43 KB

@moshe: how about this?

moshe weitzman’s picture

Status: Needs review » Reviewed & tested by the community

Nice work, effulgentsia.

Dries’s picture

Mmm, that feels like a hack.

moshe weitzman’s picture

Whats a hack? We used to unconditionally set a text/html http header very early in page processing. We did that for all requests including CLI requests and XML requests and so on. Thats hackish. This patch moves that to the html delivery callback and does so in a safe way. Thats a significant improvement, no?

katbailey’s picture

Hey all,
I've added a documentation task which could really use the eyes of the people involved in this thread: #610068: Document AJAX no-js and use-ajax
thanks!

rfay’s picture

And I hijacked katbailey's thread for a general to-do list and discussion of Ajax documentation. #610068: Document AJAX no-js and use-ajax.

catch’s picture

Issue tags: +D7 upgrade path
FileSize
1.59 KB

Fixing upgrade path, previous patch still required.

catch’s picture

FileSize
2.27 KB

Please ignore tiny kitten.

webchick’s picture

I committed #49 to fix the upgrade path. Haven't had a chance to read the rest of this issue yet, sorry.

catch’s picture

FileSize
2.95 KB

Status: Reviewed & tested by the community » Needs work

The last submitted patch failed testing.

webchick’s picture

Status: Needs work » Reviewed & tested by the community

Catch moved his upgrade path fixing efforts to #613238: Add missing columns and tables required for upgrade. Sorry folks. Carry on!

webchick’s picture

Here's a re-upload of #43 so testing bot stops complaining.

effulgentsia’s picture

Bumping this to hopefully get it unstuck. Seems there's a disagreement between Dries and Moshe (#45 and #46) with respect to whether this is good or not. What can be done to move the conversation along?

sun’s picture

I'm not sure why Dries feels uneasy about this fix.

The only thing that makes me feel a bit uneasy is the NULL condition. Otherwise, this looks ready to go.

moshe weitzman’s picture

I asked Dries to take another look at this.

Dries’s picture

Status: Reviewed & tested by the community » Fixed

Committed to CVS HEAD.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

moshe weitzman’s picture

I dislike that ajax_render() issues an exit. It sucks for unit testing or reusing anything that ends up calling it. But I decided not to deal with that in this issue. However, this patch landing would lend itself to a fairly straightforward follow up issue to change ajax_render() to not exit. That would require changing all AJAX callbacks to use the ajax_deliver() delivery callback, but that's not a big deal to do, and is arguably a good idea anyway.

Hasn't happenned yet, AFACT. Is there an issue for it? Lets unify, people. Anyone up for rolling the patch?

effulgentsia’s picture

Sorry, Moshe, it slipped my radar. Here it is: #716602: Refactor ajax_render() and clean up 'ajax' element type. I hope it's not too late.

rfay’s picture

You may be interested in #838408: Remove hook_menu_active_handler_alter if you participated here, since this is where it was introduced.