0

I'm actually developing a Chrome Extension to work on a specific page (actually a tool that we use at work). This page has its own javascript engine which handles all the redirects, navigation, saves and almost every operation or single click in the page. In this page we have a Textarea which we use to put details about a reference. We have just one textarea but we would need more fields in order to work properly, but the platform owner always refused to add them (I don't know why). So, what I achieved is to hide that textarea and add some custom fields on the fly and work on them. Then, on save, wrap all the text from the custom fields into the original description in order to process it properly. This works by parsing the text and using some headers like: [section]

The javascript engine often tries to make the original textarea to show up again after being hidden by my extension. To avoid it, I setup a mutation observer in order to hide it again when it happens. It works fine and I'm happy with it.

What happens and cause an issue is that, when I remove the custom fields (for reload it in some cases or when the extension gets disabled) I disconnect the observers and make the original textarea back again.

To do this I have some global vars used to hold the references to the observers when I connect them:

$(window).on('load', function () {
var removalObs_ref;
var descriptionObs_ref;
var descriptionAdd_ref;

When the initializer starts, I have a function that create, connect and save the Observers references in this vars:

const containerRemovalObs_cfg = { childList: true, subtree: true };
    const containerRemovalObs = new MutationObserver(function (mutationList) {
        for (let mutation of mutationList) {
            if (mutation.removedNodes) {
                for (let removedNode of mutation.removedNodes) {
                    if ($(removedNode).attr('id') == 'sh_container' || $(removedNode).find('#sh_container').length > 0) {
                        console.log("INFO: SH container has been removed (Removal Observer).");
                        destroy({ reload: true });
                        containerRemovalObs.disconnect();
                    }
                }
            }
        }
    });
    containerRemovalObs.observe(document.body, containerRemovalObs_cfg);
    removalObs_ref = containerRemovalObs;

    const descriptionAddObs_cfg = { childList: true, subtree: true };
    const descriptionAddObs = new MutationObserver(function (mutationList) {
        for (let mutation of mutationList) {
            if (mutation.addedNodes) {
                for (let addedNode of mutation.addedNodes) {
                    if (($(addedNode).attr('name') == $(siebelDescription).attr('name') || $(addedNode).find('textarea[name="' + $(siebelDescription).attr('name') + '"]').length > 0)) {
                        console.log("INFO: Siebel Description added (Add Observer).");
                        destroy({ reload: true });
                        descriptionAddObs.disconnect();
                    }
                }
            }
        }
    });
    descriptionAddObs.observe(document.body, descriptionAddObs_cfg);
    descriptionAdd_ref = descriptionAddObs;

    const descriptionDisplayObs_cfg = { attributes: true, attributeOldValue: true };
    const descriptionDisplayObs = new MutationObserver(function (mutationList) {
        for (let mutation of mutationList) {
            if (mutation.attributeName == 'style') {
                if (/display: none;/.test(mutation.oldValue)) {
                    console.log("INFO: Siebel Description showed (Display Observer).");
                    _hideSiebelDescription();
                    if (currentSR != $('[aria-label="SR Ref ID"]').val()) {
                        console.log('INFO: Switched SR, going to reset the view.');
                        init();
                    }
                }
            }
        }
    });
    descriptionDisplayObs.observe($(siebelDescription)[0], descriptionDisplayObs_cfg);
    descriptionObs_ref = descriptionDisplayObs;

Then, I have a function called "Destroy" which serves as a removal of my objects and shows the original textarea back again:

function destroy(options) {
    console.log('REMOVAL OBS:' + removalObs_ref);
    console.log('DESC OBS:' + descriptionObs_ref);
    removalObs_ref.disconnect();
    descriptionObs_ref.disconnect();
    console.log('INFO: Observers disconnected (Destroy).');

    if ($('#sh_container').length) {
        (typeof options.save !== 'undefined' && options.save == true) ? _forceSiebelUpdate() : $(siebelDescription).show().focus().val(_wrapDescription().trim());
        $('#sh_container').remove();
        console.log('INFO: SH container removed (Destroy).');
    }

    if (typeof options.reload !== 'undefined' && options.reload == true) {
        window.setTimeout(function () {
            console.log('INFO: Reloading.');
            init(typeof options.neworder !== 'undefined' ? options.neworder : null);
        }, 100);
    } else {
        descriptionAdd_ref.disconnect();
        console.log('INFO: Add observer disconnected.');
        window.setTimeout(function () {
            $('span#Description_Label').show();
            $('span#Description_Label').closest('div.mceGridLabel').html(':');
            $(siebelDescription).show();
            console.log('INFO: Siebel Description showed back.');
        }, 500);
    }
}

In the first rows of the destroy function you can see that I begin disconnecting 2 observers, so, after that, they shouldn't being trigger again (I think).

Unfortunately, sometimes happens that, when I call the destroy function and I got the Observers disconnected, one of them gets still triggered causing a loop:

Console log screenshot

You can see in the second row of my logs that the observers have been disconnected (at least, the disconnect function has been executed and we got the log. Check the destroy function.) but then, when the "Description" (original textarea) showed up again, it has been hidden again by the observer that I disconnected a while before!

Could you please explain me if I'm missing something? Should I check the disconnection in some way or do it in a different way?

I really don't understand what's wrong here.

Thank you very much in advance for your help.

Best regards.

Fabrizio
  • 233
  • 1
  • 10
  • 1
    If observer.takeRecords() won't help you, the only obviously wrong thing to me is the complexity and fragility of this approach per se. 1) To hide the textarea there should be no need to set its style attribute, just add a ` – wOxxOm Dec 11 '19 at 12:16
  • @wOxxOm hi, thanks a lot. Well, there was a reason for me to use that approach, but the addition of Style node seems working. I was afraid that the page was able to bring it up again even with this approach but it seems workinf fine, thanks! – Fabrizio Dec 11 '19 at 16:27

0 Answers0