0

This one has always boggled my mind and I've been scouting for StackOverflow questions about dealing with the anonymous scope in userscripts for many years, never satisfied with the sidestepping workarounds proposed instead in most answers.

So there is a script on a page that assigns a callback to a DOM element's onblur event.
To clarify, just in case, the callback is not assigned with inline HTML.
I want that callback to never fire. I can't disable the event (can I?), but theoretically I can unset a callback function from it.

Naturally I get that element in console and check its .onblur property — I get null.
Well, I'd love to believe that... but there is in fact a callback and it still triggers every time the element is blurred.

If I assign my own callback to that event — then both the "hidden" one and my callback get triggered.

The page in question is any random FANDOM/Wikia page with their new Oasis layout, e.g. Fandom Developers Wiki.

When I prettify this script from the page in Waterfox (a conservative Firefox fork), these lines catch my "eye":

6963:$(function($) {
6964:    'use strict';
6965:    var $globalNav = $('.wds-global-navigation'),
6966:        $searchContainer =
6967:        $globalNav.find('.wds-global-navigation__search-container'),
6968:        $searchInput = $globalNav.find('.wds-global-navigation__search-input'),
6969:        $searchSubmit = $globalNav.find('.wds-global-navigation__search-submit'),
6970:        $searchToggle = $globalNav.find('.wds-global-navigation__search-toggle'),
6971:        activeSearchClass = 'wds-search-is-active';
6972:    function activateSearch() {
6973:        if (!$globalNav.hasClass(activeSearchClass)) {
6974:            $globalNav.addClass(activeSearchClass);
6975:            $searchInput.focus();
6976:        }
6977:    }
6978:    function deactivateSearch() {
6979:        $searchSubmit.prop('disabled', true);
6980:        $searchInput.val('');
6981:        $globalNav.removeClass(activeSearchClass);
6982:        $searchContainer.removeClass('wds-search-is-focused');
6983:    }
6984:    $searchInput.on('input', function() {
6985:        var textLength = this.value.length;
6986:        if (textLength > 0 && $searchSubmit.prop('disabled')) {
6987:            $searchSubmit.prop('disabled', false);
6988:        } else if (textLength === 0) {
6989:            $searchSubmit.prop('disabled', true);
6990:        }
6991:    });
6992:    $searchInput.on('keydown', function(event) {
6993:        if (event.which === 27) {
6994:            deactivateSearch();
6995:            $searchInput.blur();
6996:        }
6997:    }).on('blur', function() {
6998:        if (!this.value.length) {
6999:            deactivateSearch();
7000:        }
7001:    })[…]

I work with ViolentMonkey in Waterfox. (Should be roughly equivalent to GreaseMonkey in Firefox)
I don't know much of jQuery (which that code smells of to me) and never seemed to really need it in tinkering, but let me know if I'm missing something obvious.

To summarize in more specifics (wait, what now?):

I'm trying to unset a callback from document.getElementsByClassName('wds-global-navigation__search-input')[0].onblur on e.g. Fandom Developers Wiki to make the search field remain on screen at all times instead of only appearing after you click on the search button (easily simulated with document.getElementsByClassName('wds-global-navigation__search-toggle')[0].click()) but until the field loses focus (that's the hard part to neuter).

It's so jarring when I open the code on a page in a debugger, immediately see what needs changing in the script or in the memory after the script ran but have no ability to affect either.

I guess I could go @run-at document-start and document.onbeforescriptexecute = funcRef; to highjack the whole script and try dissecting it, but aren't there less drastic approaches?

P.S.
I couldn't create a "violentmonkey" tag to mark my question. Sorry, it's all about reputation.
Decided not to use the "greasemonkey" one, since it's outdated and grew its own slew of quirks.

From a practical standpoint, I'll still appreciate a simple special-case solution to keep that search field constantly open, but I'd like the focus to be on the general case of the question since I tend to run into this problem of altering data in the anonymous scope pretty often.

What are the ways of accessing the values in the anonymous scope from a userscript, like that "hidden" callback value of the onblur event that I don't seem to be able to change?

Erquint
  • 49
  • 4
  • 1
    `.onblur` property is one way to listen to a blur event ... `.addEventListener('blur', ...` is another - overwriting `.onblur` overwrites what was there ... adding using `.addEventListener` adds another listener. you remove those using `.removeEventListener` - however, that's not going to help you - but, if you can add event listener before any other is added, then you can prevent the subsequent listeners from getting the event – Bravo Oct 23 '19 at 21:40
  • 1
    oh, forgot to mention, jQuery `.on('blur'` uses `.addEventListener('blur'` not `.onblur =` - but ... since the event listener is added using jQuery, you can do `xxx.off('blur')` - unfortunately, you've decided to hide the code between 6983 and 6997. Some line shortly before 6997 is the key to your success - you need to know what xxx is :p – Bravo Oct 23 '19 at 21:43
  • Code is not magic. It does what is is designed to do. `jQueryElement.css('display', 'none');`. – StackSlave Oct 23 '19 at 21:48
  • @Bravo, you must suspect how awkward it gets citing a giant slab of minified JS, especially when the built-in beautifier doesn't indent properly. Expanded the code block just in case. Thanks for the clarification on eventListener and jQuery `.on`. Why is `.removeEventListener` not going to help though? – Erquint Oct 23 '19 at 22:28
  • If you were referring to `$searchInput` "shortly before 6997" — then I still don't know how to access its scope to `.off('blur')` it. – Erquint Oct 23 '19 at 22:52

0 Answers0