Please see #452678: Data loss when using tabledrag to re-order items for a CCK text field using tinymce/CKEditor for a fuller description of the problem. That issue is specifically for wysiwyg, but the problem is a generic issue for iframes within draggable rows. When a row is swapped, the action of moving it within the dom causes reload of iframe, which potentially has several problems, the most annoying one that I've come across being in the context of the wysiwyg module using tinymce as the editor.
To properly fix this within wysiwyg, it would be ideal if there was a way to add a listener to the before row swap and after row swap events. Those listeners could implement specific solutions, such as detaching/attaching editors, but the specifics of those listeners is beyond the scope of this issue. What I'm asking for in this issue is for there to be *some way* by which to register those listeners.
Specifically, I'm asking for some event/hook/function to get called at the beginning of Drupal.tableDrag.prototype.row.prototype.swap, and at the end. Perhaps this.onSwap() is sufficient for the end, I'm not sure, except as far as I can tell, there's no easy way to register an onSwap for every row without clobbering an existing onSwap(). But I confess to not really understanding the architecture behind tabledrag.js.
As an alternate to making this specific enhancement to Drupal.tableDrag.prototype.row.prototype.swap, if the jquery aop plugin were included in core (the way jquery.form.js is), that would also address my needs. However, unless that plugin is in core, I don't think the wysiwyg module will want to use it.
Basically, what I'm asking for boils down to this: for D6, I needed to create the wysiwygcck module in order to not have the tinymce editor break after a tabledrag row swap. The relevant code from that module is:
/**
* Extend tabledrag.js's default row swapping behavior to take into account
* that wysiwyg editors are usually in an iframe, and iframes get reloaded when moved
* in the dom.
*/
if (Drupal.tableDrag) {
jQuery.aop.around({target: Drupal.tableDrag.prototype.row.prototype, method: 'swap'}, function(invocation) {
// TODO: What's the proper way to handle situation where this.group has
// multiple items?
if (this.group.length > 1) {
return invocation.proceed();
}
// Get the editor instances in the row being dragged. If there aren't any, let tabledrag's
// default implementation proceed.
var position = invocation.arguments[0];
var referenceRow = invocation.arguments[1];
var thisRow = this.group[0];
var instances = Drupal.wysiwygcck.getInstances(thisRow);
if (!instances) {
return invocation.proceed();
}
// If thisRow is the same as referenceRow, then nothing will happen during a swap.
// However, letting the default swap behavior run will result in the editors' iframes
// being reloaded and messed up, so instead, we just force nothing to happen.
if (thisRow == referenceRow) {
return;
}
// If we reached here, it means we need to let tabledrag swap the rows. However,
// if the editors have iframes, they'll probably get messed up by the swap,
// so we want to detach the editors before the swap, and reattach them after the swap.
for (var id in instances) {
Drupal.wysiwygDetach(thisRow, instances[id]);
};
result = invocation.proceed();
for (var id in instances) {
Drupal.wysiwygAttach(thisRow, instances[id]);
};
return result;
});
}
For D7, I would like this functionality to be part of the wysiwyg module rather than an add-on module, but I don't think the jquery aop approach would be considered acceptable unless the drupal community decides that we want jquery aop as part of core. So I'm asking for us to either make jquery aop part of core, or for a change to tabledrag.js so that jquery aop isn't needed for this.
Thanks!
| Comment | File | Size | Author |
|---|---|---|---|
| #7 | iframesrc.zip | 3.01 KB | effulgentsia |
| #2 | drupal-tabledrag-detachbehaviors_on_row_swap-561796-2.patch | 662 bytes | effulgentsia |
| #2 | iframesrc.zip | 3.03 KB | effulgentsia |
Comments
Comment #1
sunThat's basically the same as #561726: ajax.js and tabledrag.js need to implement Drupal.detachBehaviors(), just not about ajax.js.
Comment #2
effulgentsia commentedThanks sun! Given that, here's the patch.
I'm also attaching a tester module. @sun, feel free to use it as a starting point for a tester of #561726: ajax.js and tabledrag.js need to implement Drupal.detachBehaviors(). I won't have time before code-freeze to help with that issue, but if it's still unresolved in a couple weeks, I'll be able to help then.
The tester module, iframesrc, creates a field and widget. The widget presents an iframe that can be navigated. The field stores the value of the last url visited in that iframe. I doubt this is a useful feature, but it tests the same issue that occurs in wysiwyg: namely how do you keep information that's within an iframe synchronized with a different element that is outside the iframe that is used for storing the value of the field instance.
Here's the test that's relevant for this issue:
Without this patch, after a row swap, the iframe is reloaded with its initial src. With this patch, the iframe is reloaded with the url it was on prior to the row swap.
Comment #4
sunIntroducing a new tag for feature freeze: API clean-up.
Comment #5
sunTagging absolutely critical clean-ups for D7. Do not touch this tag. Please either help with this or one of the other patches having this tag.
Comment #6
effulgentsia commentedPatch #2 still works fine for me. Want to see what testbot thinks.
Comment #7
effulgentsia commentedUpdated tester module. See #2 for what it does.
Comment #8
effulgentsia commentedThis has been rolled into #561726: ajax.js and tabledrag.js need to implement Drupal.detachBehaviors().
Comment #9
gisleOfficial tag is "API clean-up" - https://www.drupal.org/node/1207020