as shown in #1678002: Edit should provide a usable entity-level toolbar for saving fields the way our ajax commands are implemented is wrong.
our docs say:
/**
* Ajax object.
*
* All Ajax objects on a page are accessible through the global Drupal.ajax
* object and are keyed by the submit button's ID. You can access them from
* your module's JavaScript file to override properties or functions.
*
* For example, if your Ajax enabled button has the ID 'edit-submit', you can
* redefine the function that is called to insert the new content like this
* (inside a Drupal.behaviors attach block):
* @code
* Drupal.behaviors.myCustomAJAXStuff = {
* attach: function (context, settings) {
* Drupal.ajax['edit-submit'].commands.insert = function (ajax, response, status) {
* new_content = $(response.data);
* $('#my-wrapper').append(new_content);
* alert('New content was appended to #my-wrapper');
* }
* }
* };
* @endcode
*/
This is good, this is what everyone expects. But it's a lie.
What happens is that Drupal.ajax.prototype.commands = {}
is a single object shared by all ajax objects. What was ment is something like Drupal.ajax.prototype.commands.prototype = {}
(don't try it at home that's not where we want to end up). When you follow the docs, you don't override one command from the one ajax object you're working with, you override the command for all ajax objects ever.
what we need is
Drupal.ajax = function () {
this.commands = new Drupal.AjaxCommands();
};
Drupal.AjaxCommands = function () {}; // empty, on purpose
Drupal.AjaxCommands.prototype = {/* the old command object */};
and now the doc is right.
Comment | File | Size | Author |
---|---|---|---|
#3 | core-js-ajaxcommand-2019481-3.patch | 23.4 KB | nod_ |
#1 | core-js-ajaxcommand-2019481-1.patch | 6.6 KB | nod_ |
Comments
Comment #1
nod_Comment #2
Wim LeersContext
I spent almost 4 hours on figuring out WTF was going wrong. Any
Drupal.ajax
command that did something likewould effectively be changing the "insert" command for all other
Drupal.ajax
instances, even those that are created later.After about 4 hours of banging my head against the desk, after getting very close to tears of desperation several times (because I was really doing exactly what the docs prescribed!), after investigating whether maybe Chrome's JS engine was applying an optimization it shouldn't be doing, after questioning pretty much anything, it dawned upon me that this was just JavaScript's
prototype
being used incorrectly.I implemented a work-around to get my patch done, and I fixed the docs. The code here is the better solution, that instead keeps the docs as-is and introduces
prototype
at the right object.So, all of the above is all based on problems I found and discussed with nod_. Thanks to nod_ for writing it up in a less hate-driven manner than I would definitely have done.
To test
If a reviewer/core committer wants to verify this does indeed fix things, go to the D8 HEAD frontpage and type
Drupal.ajax.prototype.commands.insert
in the browser console:Detailed testing/validation
I rerolled #1678002: Edit should provide a usable entity-level toolbar for saving fields on top of the patch in #1 (see #147 there), to thoroughly validate this patch. It works perfectly.
Code review
The changes are crystal clear.
What's missing though, is documentation updates in PHP files, which all still refer to
Drupal.ajax.prototype.commands
. If that's fixed, this is RTBC.Comment #3
nod_with doc changes.
Comment #4
nod_an I guess
Comment #5
Wim LeersComment #6
alexpottCommitted d087f4e and pushed to 8.x. Thanks!
Comment #7
Wim LeersWow, that must've been one of the fastest fixes ever! :D
I accidentally removed the "Needs change notification" (well, d.o did). I'm not sure if it's really necessary, it's a very superficial change. But it's a change. I'll leave it to nod_ to decide.
Comment #8
jessebeach CreditAttribution: jessebeach commentedThat is so much more sane!
Comment #9
nod_crappy change notice: https://drupal.org/node/2019879
Comment #10.0
(not verified) CreditAttribution: commentedstupid image