2

I desperately need help with writing a Tampermonkey/Greasemonkey script that takes part of the information within the web page and makes it part of the page (and window) title.

A client's name is part of the target (internal) web page, and clearly labeled within the HTML:

<div id="patient-info" class="ehr-patients-info">
    <div id="patient-identification">
        <span title="" id="patient-name">
            Johnnyfirst

            Smithylast
        </span>
    </div>
... 

I want to add the text "Johnnyfirst Smithylast" to the window title and tried:

var ptname = document.getElementById("patient-name") ;
document.title = document.title + " | Name: " + ptname ;

But that resulted in titles like: ...| Name: null.

The second problem is that the web site to which I am piggybacking this userscript doesn't load all at once. After the initial page load, there's heavy javascript functionality which loads various parts of the page and ends up displaying the client name as above.

When I try $(window).on('load', function() { ... }) or $(document).ready(), it seems to be acting on a preliminary version of the web page that doesn't have the information fully loaded yet.

Brock Adams
  • 90,639
  • 22
  • 233
  • 295
kwantum
  • 59
  • 6

1 Answers1

1

Your target page is AJAX driven and Greasemonkey/Tampermonkey fires way before most AJAX page loads finish. So, you must use techniques like MutationObserver, waitForKeyElements, etc., to compensate.

For example, here's a complete Tampermonkey script that changes the title when it finds the patient-name node:

// ==UserScript==
// @name     _Put the patient Name in the title
// @match    *://YOUR_SERVER.COM/YOUR_PATH/*
// @noframes
// @require  https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js
// @require  https://gist.github.com/raw/2625891/waitForKeyElements.js
// @grant    GM_addStyle
// @grant    GM.getValue
// ==/UserScript==
// @grant    none
//- The @grant directives are needed to restore the proper sandbox.
/* global waitForKeyElements */
/* eslint-disable no-multi-spaces, curly */
'use strict';

waitForKeyElements ("#patient-name, .patient-name", scrapeTextToTitle);

function scrapeTextToTitle (jNode) {
    var nameRaw         = jNode.text ().trim ();
    var nameSanitized   = nameRaw.replace (/\s+/g, " ");
    document.title     += " | Name: " + nameSanitized;
}
Brock Adams
  • 90,639
  • 22
  • 233
  • 295
  • Thank you for the quick response! I noticed that you were the one who authored waitForKeyElements, but I never dreamed I'd get a response from Brock Adams himself! Thanks for the help. Will try it out once I get the chance. // Also thanks for editing my post; I was trying to strike a balance between being brief and explaining my motivation so that I wouldn't get replies like "Why would you even want to do it that way? Just do it this way instead..." – kwantum Jul 05 '19 at 21:30
  • Thank you, @Brock! Your solution seems to work, for some circumstances. Other circumstances I note that the patient name is denoted thus within the web page: `

    Johnnyfirst Smithylast

    ` In your code, you have the "#" in front of the patient name. Does that mean to look for "id=" in the tag? Is there another character that means look for "class=" in the tag, such as "class=patient-name ng-binding"?
    – kwantum Jul 07 '19 at 11:27
  • Sounds like I should find the descendant node for a class rather than an id, as in `

    `. I see that your waitForKeyElements() function already does that if I give an iframeSelector. How do I specify an iframeSelector? The website seems to use iframes, but there is no actual `

    – kwantum Jul 07 '19 at 14:26
  • @kwantum, See the updated answer and reference https://api.jquery.com/category/selectors/ . – Brock Adams Jul 07 '19 at 14:28
  • It doesn't sound to me yet like you need to do anything special regarding iframes. But there's plenty of Q&A's here on that if required. – Brock Adams Jul 07 '19 at 14:30
  • The script seems to work in most of the AJAX-generated pages, except for the one I mentioned which inserts some 3rd-party content. Somehow the script won't detect that content. This probably involves other aspects of Javascript, and I'll ask a separate question for this. Thank you for helping me with the main issue of triggering Tampermonkey only after the AJAX content gets loaded! I looked at your waitForKeyElements source code. It calls itself recursively. Wouldn't this eventually overflow if it waits a long time for elements that never appear? Should I rewrite it as a loop instead? – kwantum Jul 08 '19 at 00:37
  • @kwantum, waitForKeyElements does not call itself recursively. And you would have to invoke it scores of times on a massively bloated page to notice a performance hit. Also, setting `bWaitOnce` to true (if applicable) causes it to unload after a single node is found. But there are many ways to skin the same cat. You don't need to use waitForKeyElements if you want to invent a new wheel. – Brock Adams Jul 08 '19 at 00:53