-
-
Save adamhotep/7c9068f2196326ab79145ae308b68f9e to your computer and use it in GitHub Desktop.
| /*--- waitForKeyElements(): A utility function, for Greasemonkey scripts, | |
| that detects and handles AJAXed content. | |
| Original: https://gist.github.com/BrockA/2625891 | |
| Non-jQuery version by: Adam Katz, | |
| https://gist.github.com/adamhotep/7c9068f2196326ab79145ae308b68f9e | |
| License: CC BY-NC-SA 4.0 (*not* GPL-compatible) | |
| changes made by Adam Katz (tracked by adamhotep's github gist) are | |
| also licensed GPL v2+ (but note the CC BY-NC-SA prevents commercial use) | |
| License via https://gist.github.com/BrockA/2625891#gistcomment-1617026 | |
| Usage example: | |
| // ==UserScript== | |
| // … | |
| // @require https://git.io/waitForKeyElements.js | |
| // ==/UserScript== | |
| waitForKeyElements ( | |
| "div.comments", | |
| commentCallbackFunction | |
| ); | |
| //--- Page-specific function to do what we want when the node is found. | |
| function commentCallbackFunction (elem) { | |
| elem.innerHTML = "This comment changed by waitForKeyElements()."; | |
| } | |
| */ | |
| function waitForKeyElements ( | |
| selectorTxt, /* Required: The querySelector string that | |
| specifies the desired element(s). | |
| */ | |
| actionFunction, /* Required: The code to run when elements are | |
| found. It is passed the matched element. | |
| */ | |
| bWaitOnce, /* Optional: If false, will continue to scan for | |
| new elements even after the first match is | |
| found. | |
| */ | |
| iframeSelector /* Optional: If set, identifies the iframe to | |
| search. | |
| */ | |
| ) { | |
| var targetNodes, btargetsFound; | |
| //--- Additionally avoid what we've found | |
| var selectorClean = selectorTxt.replace(/(,)|$/g, ":not([wfke_found])$1"); | |
| if (typeof iframeSelector == "undefined") | |
| targetNodes = document.querySelectorAll(selectorClean); | |
| else { | |
| targetNodes = []; | |
| var iframe = document.querySelectorAll(iframeSelector); | |
| for (var i = 0, il = iframe.length; i < il; i++) { | |
| var nodes = iframe[i].contentDocument.querySelectorAll(selectorClean); | |
| if (nodes) targetNodes.concat(Array.from(nodes)); | |
| } | |
| } | |
| if (targetNodes && targetNodes.length > 0) { | |
| btargetsFound = true; | |
| //--- Found target node(s). Go through each and act if they are new. | |
| for (var t = 0, tl = targetNodes.length; t < tl; t++) { | |
| if (!targetNodes[t].getAttribute("wfke_found")) { | |
| //--- Call the payload function. | |
| var cancelFound = false; | |
| try { | |
| cancelFound = actionFunction (targetNodes[t]); | |
| } | |
| //--- Log errors to console rather than stopping altogether | |
| catch (error) { | |
| var name = actionFunction.name; | |
| if (name) | |
| name = 'in function "' + name + '":\n'; | |
| console.log ("waitForKeyElements: actionFunction error\n" | |
| + name + error); | |
| } | |
| if (cancelFound) | |
| btargetsFound = false; | |
| else | |
| targetNodes[t].setAttribute("wfke_found", true); | |
| } | |
| } | |
| } | |
| else { | |
| btargetsFound = false; | |
| } | |
| //--- Get the timer-control variable for this selector. | |
| var controlObj = waitForKeyElements.controlObj || {}; | |
| var controlKey = selectorTxt.replace (/[^\w]/g, "_"); | |
| var timeControl = controlObj [controlKey]; | |
| //--- Now set or clear the timer as appropriate. | |
| if (btargetsFound && bWaitOnce && timeControl) { | |
| //--- The only condition where we need to clear the timer. | |
| clearInterval (timeControl); | |
| delete controlObj [controlKey] | |
| } | |
| else { | |
| //--- Set a timer, if needed. | |
| if ( ! timeControl) { | |
| timeControl = setInterval ( function () { | |
| waitForKeyElements ( selectorTxt, | |
| actionFunction, | |
| bWaitOnce, | |
| iframeSelector | |
| ); | |
| }, | |
| 300 | |
| ); | |
| controlObj [controlKey] = timeControl; | |
| } | |
| } | |
| waitForKeyElements.controlObj = controlObj; | |
| } |
shouldn't the iframe code be like this?
document.querySelectorAll("frame[name=\"mainframe\"]")[0].contentWindow.document.querySelector("form")
https://stackoverflow.com/questions/26630519/queryselector-for-web-elements-inside-iframe
General note: I've since migrated all of my scripts to use nf.wait$() from my Nofus.js project at https://github.com/adamhotep/nofus.js. That function doesn't have special provisions for iframes because they haven't appeared necessary.
@z-aki, I'm not sure what you're referring to. Where is name="mainframe" used? I don't know my connection to your linked Stack Overflow post, which doesn't appear to refer to me or this code, nor have I participated in that question.
Is this a reference to this answer of mine (which also does not mention a name attribute)? My answer there should work just fine with nf.wait$() in place of waitForKeyElements(). If the frame(s) in question are not created dynamically, you don't need this sort of function at all; just use document.querySelectorAll("iframe, frame").forEach(…) to find the frame and apply a function to it.
line 58
var nodes = iframe[i].querySelectorAll(selectorClean);
should be
var nodes = iframe[i].contentWindow.document.querySelectorAll(selectorClean);
The existing gist doesn't work for a call like this where frame is selected and then a div inside it is selected.
waitForKeyElements("div[id='country2']", fix, false, "frame[name='mainframe']");
website: https://www.indianbankcreditcard.in/indbcreditcustomer/html/LoginFrame.html
// ==UserScript==
// @name Indian bank Credit Card expand terms and conditions
// @version 0.1
// @description Removes the height style from the parent div of country1/2/3/4.
// @author https://github.com/z-aki
// @namespace https://github.com/z-aki
// @match https://www.indianbankcreditcard.in/indbcreditcustomer/html/UAMLogin.jsp
// @icon https://www.indianbankcreditcard.in/indbcreditcustomer/html/favicons/android-icon-192x192.png
// @grant none
// @require https://gist.github.com/adamhotep/7c9068f2196326ab79145ae308b68f9e/raw/373f5e8405b98781001aea9a9e74585367344960/waitForKeyElements.js
// @downloadURL none
// ==/UserScript==
function fix(elem) {
console.log("Tampermonkey: Fixing height");
// remove the height style from the parent div of country1/2/3/4
elem.parentElement.style.height = "";
}
waitForKeyElements("div[id='country2']", fix, false, "frame[name='mainframe']");
Ah, thanks for clarifying that the name attribute was from your code and not mine or any of the linked SO posts. I've adjusted line 58 as per your suggestion (though I used contentDocument rather than contentWindow.document, which should be identical).
thanks. But the script mentioned above doesn't work still, on the website linked above.
however this works https://z-aki.github.io/tampermonkey/2025/07/15/indian-bank-credit-card-expand-terms-and-conditions/
@z-aki: that code uses @CoeJoder's waitForKeyElements() rather than this function. I'm glad you found something that works.
To others reading this, I highly suggest using nf.wait$() from my Nofus.js project. That function doesn't have special provisions for iframes because they haven't appeared necessary. Also notably, it utilizes a MutationObserver rather than a loop on a timer (as all waitForKeyElements() functions do). This means it runs every time the document changes rather than having to poll for changes periodically. This is both faster and more efficient.
In my first revision, I credited the original author, noted the license, and incorporated changes from EnterTheNameHere's first (and currently only) revision (#5), which uses
try/catchexception handling in case there is a problem with the function provided towaitForKeyElements()to act on.I've also created https://git.io/waitForKeyElements.js for easier loading in userscripts.