How do I take text contained in web page and make it part of the page title? - tampermonkey

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.

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;
}

Related

Replacing an extension-less image in gmail HTML view with tampermonkey

On HTML gmail view top left corner the new Gmail logo could be seen. I want to replace it with the old one ( https://i.imgur.com/kAQfeoj.png ) but I'm not sure how. I've tried a 9 year old stackoverflow thread but it didn't work since the gmail logo link isn't a link to the file with an extension.
found a way
// ==UserScript==
// #name Image Replacer
// #version 1.1
// #description Image Replacer
// #require http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js
// #match https://www.pinterest.com/pin/*
// #grant none
// ==/UserScript==
/*globals $*/
var old_url = "https://ci6.googleusercontent.com/proxy/WQ_JO_iFWK3AKuIPeHz_fnMMOaGLG0HAsCJWOkWiRo9Oa_NHUeQYCdmJEfw8llIVJ8fMP1mriJ81iPzrebHtesFsF7VIDS0QKCFmqu_RMT_-ow=s0-d-e1-ft"
var new_url = "https://i.imgur.com/kAQfeoj.png"
$(document).ready(function(){
$("img[src='"+old_url+"']").attr("src", new_url);
});

Dose Tampermonkey can run script before the page loaded?

I'm trying to use tampermonkey to refresh a website, its works except the server was busy, and the respond time is long, may i know can the script run before the page fully loaded?
I would also wanna now can the script work on any website without the #match / #include?
Many thanks.
// #name TEST
// #version 1
// #grant none
// #match http://busy.example.com
// ==/UserScript==
setTimeout(
function(){
document.location = "http://example.com";
}, 10
);

removing an element with a userscript

First attempt at a userscript, and despite finding numerous examples on the internet of how to remove elements from a page, none of them work (and this looks like one of the most basic applications of a userscript, too).
Using violentmonkey-2.12.8 on this page:
https://www.zerohedge.com/economics/2020-greatest-hits-most-popular-articles-past-year-and-look-ahead
I want to remove the "exitModalOverlay" div (disabling it in the developer tools does exactly what I want), which blacks out the page (preventing me from reading it).
I will insert one of the more common techniques I have found (which doesn't work). I would appreciate any method which does. Thanks.
// ==UserScript==
// #namespace confused
// #name zehohedge_remove_subscription_popup
// #version 1
// #description removes the overlay div that asks to subscribe
// #match https://www.zerohedge.com/*
// #grant none
// #noframes
// ==/UserScript==
var todelete = document.getElementById('exitModalOverlay');
if (todelete) { todelete.parentNode.removeChild(todelete); }
Based on the post & comments, it seems the element is loaded/created after the DOM. In that case, you would need to run the script after page loading is complete.
Although when testing on the link provided with JavaScript enabled (https://www.zerohedge.com/economics/2020-greatest-hits-most-popular-articles-past-year-and-look-ahead), the element does not appear, here is an example of how you can remove the item.
It is possible there are other factors involved (e.g. browser, country, login, cookies etc).
ViolentMonkey by default runs on document-end which is after DOM loaded but before all external elements are loaded.
Setting the userscript to run at document-idle will run after everything is loaded.
// ==UserScript==
// #namespace confused
// #name zehohedge_remove_subscription_popup
// #version 1
// #description removes the overlay div that asks to subscribe
// #match https://www.zerohedge.com/*
// #grant none
// #noframes
// #run-at document-idle
// ==/UserScript==
// find element
const todelete = document.getElementById('exitModalOverlay');
// remove element if found
if (todelete) { todelete.remove(); }
Removing the element is not the only way to get rid of an element. You can also use CSS to achieve a similar outcome by setting its display to none. For example:
// ==UserScript==
// #namespace confused
// #name zehohedge_remove_subscription_popup
// #version 1
// #description removes the overlay div that asks to subscribe
// #match https://www.zerohedge.com/*
// #grant GM_addStyle
// #noframes
// ==/UserScript==
const css = `
#exitModalOverlay {
display: none;
}`;
GM_addStyle(css);
Using JavaScript to apply CSS to the element without GM_addStyle (although not as good as above)
// ==UserScript==
// #namespace confused
// #name zehohedge_remove_subscription_popup
// #version 1
// #description removes the overlay div that asks to subscribe
// #match https://www.zerohedge.com/*
// #grant none
// #noframes
// #run-at document-idle
// ==/UserScript==
// find element
const todelete = document.getElementById('exitModalOverlay');
// remove element if found
if (todelete) { todelete.style.display = 'none'; }
📌 It is worth noting that CSS applies all the time (unless over-written specifically), even if an element is created later, while JavaScript applies at the time it runs and will not apply to elements created later (without additional methods to cause it to run again).
Maybe so...
window.onload = function() {
var todelete = document.querySelector('#exitModalOverlay');
todelete.outerHTML = '';
}
or
window.onload = function() {
var todelete = document.querySelector('#exitModalOverlay');
todelete.remove();
}

Userscript to bypass "You are now leaving" page

A web site's links external links all redirect to a "You are now leaving" page.
When I copy the originally posted link-URL, they look like this:
https://www.flashback.org/leave.php?u=http%3A%2F%2Fwww.swatab.com%2F%3Flang%3Den
Page HTML:
<a href="/leave.php?u=http%3A%2F%2Fwww.swatab.com%2F%3Flang%3Den"
target="_blank">http://www.swatab.com/?lang=en</a>
I would like to create a userscript that bypasses the /leave.php page and redirects me to the true link on click.
Is there a simple solution to this?
That's a job for a relatively standard redirect script.
Note the use of #run-at document-start and of location.replaceDoc.
// ==UserScript==
// #name Flashback.org, skip the "You are now leaving" page
// #match *://www.flashback.org/leave.php*
// #grant none
// #run-at document-start
// ==/UserScript==
var targUrlEnc = location.search.replace (/\?u=/i, "");
if (targUrlEnc) {
var targUrl = decodeURIComponent (targUrlEnc);
location.replace (targUrl);
}

Angular js way to download file and show loading screen using the $resource

I am using Angular js to show loading screen. It works for all the REST services call except REST service to download the file. I understand why it is not working because for download I am not making any service call using $resource; instead of that I am using normal approach to download the file therefore Angular js code doesn't have any control on start/finish the service request. I tried to use $resource to hit this REST service however I am getting the data from this service and in this case loading screen was working fine however not sure how to use this data to display to user to download in angular way. Following are required details. Please help.
Approach 1 using iframe approach:
/*Download file */
scope.downloadFile = function (fileId) {
//Show loading screen. (Somehow it is not working)
scope.loadingProjectFiles=true;
var fileDownloadURL = "/api/files/" + fileId + "/download";
downloadURL(fileDownloadURL);
//Hide loading screen
scope.loadingProjectFiles=false;
};
var $idown; // Keep it outside of the function, so it's initialized once.
var downloadURL = function (url) {
if ($idown) {
$idown.attr('src', url);
} else {
$idown = $('<iframe>', { id: 'idown', src: url }).hide().appendTo('body');
}
};
Approach 2 using $resource (Not sure how to display data on screen to download)
/*Download file */
scope.downloadFile = function (fileId) {
//Show loading screen (Here loading screen works).
scope.loadingProjectFiles=true;
//File download object
var fileDownloadObj = new DownloadFile();
//Make server call to create new File
fileDownloadObj.$get({ fileid: fileid }, function (response) {
//Q? How to use the response data to display on UI as download popup
//Hide loading screen
scope.loadingProjectFiles=false;
});
};
This is the correct pattern with the $resource service:
scope.downloadFile = function (fileId) {
//Show loading screen (Here loading screen works).
scope.loadingProjectFiles=true;
var FileResource = $resource('/api/files/:idParam', {idParam:'#id'});
//Make server call to retrieve a file
var yourFile = FileResource.$get({ id: fileId }, function () {
//Now (inside this callback) the response data is loaded inside the yourFile variable
//I know it's an ugly pattern but that's what $resource is about...
DoSomethingWithYourFile(yourFile);
//Hide loading screen
scope.loadingProjectFiles=false;
});
};
I agree with you that this is a weird pattern and is different of other APIs where the downloaded data is assigned to a parameter in a callback function, hence your confusion.
Pay attention to the names and the cases of the parameters, and look that there're two mappings involved here, one between the caller to the $resource object and the object itself, and another between this object and the url that it contructs for downloading the actual data.
Here are some idea's for the second approach, you could present the user with a link after the download has happened:
With a "data url". Probably not a good idea for large files.
With a URL like "filesystem:mydownload.zip" You'd first have to save the file with the filesystem API. You can find some inspiration on html5rocks

Resources