0

I have a userscript (Tampermonkey in Chrome) which runs either when the page is opened by the user, or which may open the page in a separate window (where the concerned script then runs). When the page is opened by the user, everything works as expected.

However, when the page is opened in another window, this function sometimes does not process the text as expected.

Code:

function processTableRows() {
  var regex = new RegExp(/(.*?)(\d{7})/);
  var texts = document.querySelectorAll(".table__row");
  var out = [];
  texts.forEach(text=> {
    var fixMonth = text.innerText.replace(/(\d*)月/, function(p1) {
      const monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
      return monthNames[(parseInt(p1) - 1)];
    }).replace(regex,
             "example.com/page.html?id=$2\n$1");
    out.push(fixMonth);
  });
 return out;
}

Example page text (before script):

05 6月 2019  8989898
Some text

Some more text

When the user opens the page, both the userscript and the code in the console give the expected output:

example.com/page.html?id=8989898
05 Jun 2019     
Some text

Some more text

However, when it is launched in a separate Window, it returns (Both TM script and console run):

05 Jun 2019
example.com/page.html?id=8989898

Some text

Some more text

I can't imagine for the life of me why the second replace() seems to be functioning differently in a separate window. I thought it may be related to some of JavaScript's regex funkiness, e.g. moving an index, affecting the chained call, but MDN indicates it only returns a string.

EDIT: Further information obtained after the comments that were below:

When the page is launched in a new (popup) window, it is small and the original text renders like:

05 6月 2019
8989898
Some text
Some more text

However, when the window is larger (as when the user visits it), it looks like:

05 6月 2019  8989898
Some text

Some more text
Brock Adams
  • 90,639
  • 22
  • 233
  • 295
sinaraheneba
  • 781
  • 4
  • 18
  • The target page is not publicly accessible; to be clear, when I refer to not being able to replicate it in console, that is including in the console of a window opened by the script, so it should not be any difference in the final rendering. It's possible that it is a timing issue, although I'd expect it would also occur when opened by the user in that case. I'll look into `textContent` and see if that provides different/better results – sinaraheneba Jun 06 '19 at 03:21
  • I'm very aware of the use of minimal reproducible examples; not feasible for me to provide a copy of the website, or much more than the text previously provided. That said, your previous comment was correct--it was because the dimensions of the window opened differed, causing the white space rendered (and therefore the value of `innerText`) to change. `textContent` provides a stable reference suitable for consistent formatting, thank you very much! – sinaraheneba Jun 06 '19 at 04:06
  • 1
    @BrockAdams That knowledge on `textContent` was just what I needed to fix some other perennial bugs (and doubtlessly avoid countless others in the future); I'd love to accept it as the answer if you care to whip something up. Thanks again! – sinaraheneba Jun 07 '19 at 08:04

1 Answers1

1

In general, if the same userscript gives different results -- on the same page -- depending on how that page is opened, the causes can be:

  1. Timing. The page loads slower or faster depending on various factors, frequently caching. So the script may fire before the content it seeks is present/finished.
    Use waitForKeyElements or MutationObserver to compensate. Search around for previous questions where this has been covered.

  2. AJAX. The page is not actually doing a normal HTML load, but is using javascript to (re)write a "new" page.
    Again, waitForKeyElements or MutationObserver are helpful against such pages. And, again, covered in previous questions.

  3. "Responsive" layout/behaviors. The same page may display different content, and/or in a different ways depending on window size (typically) or some state tracking or some passed-in parameters.
    In such a case, your script may need logic code to adapt to different variants of the page.

  4. Code that is sensitive to rendering. If your script relies on positioning, CSS style, element sizes, etc.; it may break merely when the window is a different size, or when the page takes different times to render.

In this case, the question code appears to have a variant of reason 4. It uses innerText and innerText varies its results depending on whitespace and visibility. (innerText is also slower than textContent.)

The solution is to use textContent instead of innerText.

Here's a demo showing how the two properties can differ:

srcNode = $(".variableDiv")[0];
$("#TC").text (srcNode.textContent);
$("#IT").text (srcNode.innerText);
.variableDiv {border: 1px solid gray; margin-bottom: 1em;}
td, th {border: 1px solid gray;  padding: 0.2ex 1ex;}
table {border-collapse: collapse;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Source Div:
<div class="variableDiv">
    Chuck Norris has two speeds: <br> Walk, and Kill.<br>
    <span style="display:none">Hidden Text</span>
</div>
<table>
  <tr> <th>textContent</th> </tr>
  <tr> <td><pre id="TC">&nbsp;</pre></td> </tr>
  <tr> <th>innerText</th> </tr>
  <tr> <td><pre id="IT">&nbsp;</pre></td> </tr>
</table>

IIRC, different browsers might also vary innerText's results on hidden overflow and/or occluding elements, but I haven't verified that.

Brock Adams
  • 90,639
  • 22
  • 233
  • 295
  • Absolutely brilliant, and thank you again! Small question on using `waitForKeyElements` with timing/AJAX issues--this page does load information with AJAX, and my script previously used `waitForKeyElements` to support that. I've since changed it so that I have a function which checks if the element exists and calls itself again via `setTimeout()` if it does not. Are there problems with doing it this way, or some other benefit provided by `waitForKeyElements` which I'm unaware of? – sinaraheneba Jun 08 '19 at 12:06
  • 1
    @Altigraph, better to use `setInterval` in for that kind of thing. Repeated/chained `setTimeout`s can become a memory/performance hit in some cases. ... The advantages of `waitForKeyElements` are (1) Ease of use, (2) Easier to have multiple or chained waits without conflicts, (3) Your script code is more "self documenting", (4) easier to change/extend. ... But, use whatever works for you (and whomever has to work with the code a couple years from now (even if it's your future self) ). – Brock Adams Jun 08 '19 at 16:16