Location.realod vs function call


#1

I have this code which adds an innerHTML of some element to a small note with an orange background:

// ==UserScript==
// @name        Duolingo
// @include     *://duolingo.com/*
// @include     *://www.duolingo.com/*
// ==/UserScript==
let myFunc = ()=>{
  let myTimeout = setTimeout(()=>{
    let myInput = document.querySelector('._7q434._1qCW5._2fPEB._3_NyK._1Juqt._3WbPm');
    let myNote = document.createElement('div');
    document.body.appendChild(myNote);
    myNote.setAttribute("style", "position: fixed; bottom: 0; right: 0; width: 400px; height: 400px; background: orange");

    document.addEventListener('keydown', (k)=>{
      if ( k.keyCode === 13 ) {
        myNote.innerHTML = myInput.textContent;
        myFunc();
      }
    });
  }, 3000);
}

myFunc();

I run this code on Duolingo exercises (you need to register to duolingo.com to go through one of these).

This code works only twice, and then no longer works --- i.e, the function call doesn't re run the code endless times.

On the other hand if I do location.reload(true) the code will work again for 2 times.

What is the difference between location.reload(true) and the function call in the sense in location.reload(true) the code will work again but in the function call it won't? What's changed with the former that isn't changed with the latter?

Thanks,


#2

Hi, why do you need to keep rerunning this code, recreating DOM elements and reattaching the event listener? What are you trying to accomplish? Surely it would be sufficient to run the code once and be done.


#3

You are right. It will do no good and I did that by mistake. In my original code which I'll paste in a moment the addEventListener was called just once, but it didn't work more than once, so I thought, mistakenly, that there might be some framework/library bias and that if I'll call it each time anew it will work.

Here is the original code I tried:

// ==UserScript==
// @name        Duolingo
// @include     *://duolingo.com/*
// @include     *://www.duolingo.com/*
// ==/UserScript==
setTimeout(()=>{
  let myInput = document.querySelector('._7q434._1qCW5._2fPEB._3_NyK._1Juqt._3WbPm');
  let myNote = document.createElement('div');
  document.body.appendChild(myNote);
  myNote.setAttribute("style", "position: fixed; bottom: 0; right: 0; display: block; width: 400px; height: 400px; background: orange; color: #000");

  document.addEventListener('keydown', (k)=>{
    if ( k.keyCode === 13 ) {
      myNote.innerHTML += myInput.value + '<br>';
    }
  });
}, 2000);

I wasn't sure what to do with this and felt I missed something badly so I asked about it here in StackExchange and got this answer that works fine:

// ==UserScript==
// @name        Duolingo, answer text recycler
// @match       *://*.duolingo.com/*
// @run-at      document-idle
// ==/UserScript==
let myNote = document.createElement ('div');
document.body.appendChild (myNote);
myNote.setAttribute (
    "style",
    "position: fixed; bottom: 0; right: 0; width: 400px; height: 400px; background: orange; overflow: auto;"
);

document.addEventListener ('keydown', (zEvent) => {
    if (zEvent.keyCode === 13) {
        if (zEvent.target.nodeName === 'TEXTAREA') {
            let myInput = document.querySelector ('textarea[data-test]');
            if (myInput) {
                myNote.innerHTML += myInput.value + '<br>';
            }
        }
    }
} );

Here's what I've learned from it in chronological order:

  1. According to my understanding of the author (Brock Adams) in the comments section, z before Event in zEvent could help distinguish the stream "Event" from other contexts it might have, and z is taken from the Hungarian notation convention in computer programming.

  2. if (myInput) {} makes sure the code will keep running even if the element was not found and it's always good to do so.

  3. It's important to keep clear from large automatic selectors like ._7q434._1qCW5._2fPEB._3_NyK._1Juqt._3WbPm and prefer giving a basic element type to target TEXTAREA, and using this elements attributes as in ('textarea[data-test]') to ensure targeting which is specific enough.

  4. A basic reference to the event target (the event's associated element) must first include a general reference to the type of that target (if (zEvent.target.nodeName === 'TEXTAREA'), and only then, a local, more specific reference (let myInput = document.querySelector ('textarea[data-test]')).

  5. nodeName of an event target should usually be written all uppercased.

Note, I took down the // @run-at document-idle because by principle I prefer not to use userscrip agent shortcuts for JS aspects like DOMContentLoaded.


#4

Glad you got it sorted.

Meh! You're dealing with an event object, so why not call it event? This convention is used all over the internet.

Kinda.It's a good idea here, as you're not in control of the page you are running the code against. I generally wouldn't do this in code which manipulates HTML I had written.


#5

Meh! You're dealing with an event object, so why not call it event? This convention is used all over the internet.

Pullo, I personally agree with you and I assume that event is more common than zEvent.

In my local copy, I intent to call it just event or ev (as opposed to el or e for element).

I just noted my understanding of what the author wrote.

Kinda.It's a good idea here, as you're not in control of the page you are running the code against. I generally wouldn't do this in code which manipulates HTML I had written.

I agree. I should wrote there "at least sometimes".


#6

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.