I am trying to run the following block of code on https://lichess.org/uZIjh0SXxnt5.
var x = document.getElementsByTagName("a");
for(var i = 0; i < x.length; i++) {
if(x[i].href.includes("WaisKamal") && x[i].classList.contains("user_link")) {
x[i].innerHTML = '<span class="title" data-title="GM" title="Grandmaster">GM</span> ' + x[i].innerHTML;
}
if(x[i].href.includes("WaisKamal") && x[i].classList.contains("text")) {
x[i].innerHTML = '<span class="title" data-title="GM" title="Grandmaster">GM</span> ' + x[i].innerHTML;
console.log(x[i]);
}
}
I am using tampermonkey to automate the process. When the page loads, the first if statement runs correctly, but not the second one. However, when I run the second one from the browser console, it works fine.
Here is what the script does in more detail (I want to add those orange "GM"s):
Without the script
With the script
What I want
I have checked this but it didn't solve my problem.
Any help? Thanks in advance.
Most of that page is loaded dynamically (AJAX-driven), which means that your script will normally finish running long before the nodes, that you are interested in, appear in/on the page.
You must use AJAX-aware techniques such as waitForKeyElements or MutationObserver.
Here's a complete Tampermonkey script that illustrates the process:
// ==UserScript==
// #name _Lichess.org, Glorify select users
// #match *://lichess.org/*
// #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==
//- The #grant directives are needed to restore the proper sandbox.
waitForKeyElements ("a[href*='WaisKamal']", spiffifyLink);
function spiffifyLink (jNode) {
var oldHtml = jNode.html ();
var newHtml = '<span class="title" data-title="GM" title="Grandmaster">GM</span> ' + oldHtml;
jNode.html (newHtml);
}
See this other answer for more information about choosing and using waitForKeyElements and/with jQuery selectors.
Related
sorry for bad english and maybe newby question.
I want to write script that makes something automatic (in web game), everything I need to is go to subpage, then next one, and other. Then script needs to wait specific time and repeat.
I'm using global variable (boolean) and if its true I'm trying to do something like that:
unsafeWindow.location.href = linktodo + linkequipeq + accesKey;
unsafeWindow.location.href = linktodo + linkjednoraz + accesKey;
Script skips first going to page. Using setTimeout doesn't helped. I'm using:
// #run-at document-end
Still not working, I tried to use addEventListener wit parametr 'load' but nothing (I think I need to "clean" eventlistener by closing the window? - tried to use removeEventListener after first function/window redirect is done, fail).
Is it possible to do this without opening and closing new tabs/popups?
Will script like this work in inactive tab?
Can somebody post some example of doing it or tutorial I'll learn it alone?
P.s
for some explanations, those subpages will fill on some equipment, then get some cash and go quest.
linktodo is hostname, linkequipeq is pathname, and accesKey is some secuirty builded in webpage to not doing something after reload (I get acces to it via GM using unsafeWindow).
Huh mayby somebody understand me :D
// #include "site"
// #grant GM_addStyle
// #grant GM_getValue
// #grant GM_setValue
// #grant GM_deleteValue
// #grant GM_listValues
// #grant GM_xmlhttpRequest
// #require http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js
// #require https://gist.github.com/raw/2625891/waitForKeyElements.js
// #run-at document-end
var wypki = 0;
var cash = 0;
var czas = 0;
var autowypki = false;
var linkwypki = '?a=q';
var linksklep = '?a=town=';
var linkequipeq = '?a=equip';
var linkjednoraz = '?a=buyone';
var linkrealm;
var accesKey = unsafeWindow.accessKey;
var numbercash = document.getElementsByClassName('cash')[0].getElementsByClassName('panel');
var mynumbercash = numbercash[0];
var cash1 = (mynumbercash.innerHTML);
cash = cash1.slice(28, cash1.indexOf('PLN'));
cash = parseInt(cash.replace(/\s+/g, ''));
var linktodo = link.slice(0, link.indexOf('?a='));
function doquest() {
'use strict';
unsafeWindow.location.href = linktodo + linkwypki;
setTimeout(function () {
unsafeWindow.getElementById('start')[0].click();
}, 2000);
}
function zlomek() {
'use strict';
if (cash < 20000) {
unsafeWindow.location.href = linktodo + linksklep + accesKey;
}
}
function jednoraz() {
'use strict';
if (autowypki === true && cash > 20000) {
unsafeWindow.location.href = linktodo + linkjednoraz + accesKey;
}
}
function equip() {
'use strict';
unsafeWindow.location.href = linktodo + linkequipeq + accesKey;
}
/* --- Main ----*/
function autoQuest() {
'use strict';
autowypki = true;
equip();
setTimeout(jednoraz(),5000);
}
/* --- Main ----*/
if (a === linkwypki) {
var przyciskwypki = document.getElementsByTagName("form")[0].getElementsByTagName('div')[13];
przyciskwypki.innerHTML = przyciskwypki.innerHTML + '<input class="button" type="button" style="height: 20px; width: 110px;" id="autowypki" value=" Robimy wypki" />';
}
document.getElementById("autowypki").addEventListener("click", autoQuest, false);
Greasemonkey scripts are exactly like normal scripts, they don't run unless the page is loaded
On any page that this script is injected loaded, this script will add a click event listener to the element with ID='autowypki'
when that event is fired, the script will set the page to linktodo + linkequipeq + accesKey in function equip
and that's all this script will ever do
there's nowhere that invokes functions doquest and zlomak, so they're just along for the ride in this script
function jednoraz is set to be called after a timeout of 5 seconds, but by then equip has loaded a new page, so, jednoraz wont actually be called as the page it was on is no longer loaded
however, if the same click event is fired in the page that equip loads, then perhaps jednoraz will be called - and then the page linktodo + linkjednoraz + accesKey will be loaded ... I say perhaps, because I'm not 100% sure what function equip will do if it's effectively setting the page to the current page - i.e. if that causes a page load, then jednoraz wont be called because the timeout will probably never fire as the page has reloaded
I'm trying to ensure that images in a certain website are not displayed, but the alt text is still displayed. Initially I attempted to accomplish this with Stylish (using Firefox) and asked the following question:
How to force an image's alt text to display instead of the image?
The accepted answer provided me with an alternative solution using Greasemonkey. The script uses waitForKeyElements to hide images even if they're added using AJAX.
I changed the given script to the following:
// ==UserScript==
// #name _Hide pics except for alt text
// #include http://YOUR_SERVER.COM/YOUR_PATH/*
// #require http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js
// #require https://gist.github.com/raw/2625891/waitForKeyElements.js
// #grant GM_addStyle
// ==/UserScript==
GM_addStyle ( " \
* { \
background-image: none !important; \
} \
" );
waitForKeyElements ("img", hideImageExceptForAltText);
function hideImageExceptForAltText (jNode) {
var imgAlt = jNode.attr("alt");
var imgTitle = jNode.attr("title");
jNode.css("display", "none");
var newSpan = $("<span></span>");
newSpan.attr("title", imgTitle);
newSpan.append(imgAlt);
jNode.parent().append(newSpan);
}
Just like the original script, this has the problem that the images are still displayed for a few moments as the page is loading.
Is it possible to ensure that the given function will prevent images on a page from being displayed immediately, so that they won't be visible at all?
EDIT: Brock Adams' reply had the clue I was missing. In case anyone is looking for something like this, the following is what I ended up using. It works fine on the site I needed it for, but I can't guarantee it will work on other sites or other browsers than Firefox.
The following hides images and replaces them with a link (except for background images). Clicking that link will display the image.
// ==UserScript==
// #name TCRF images
// #namespace SOMETHING
// #include http://YOUR_SERVER.COM/YOUR_PATH/*
// #require http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js
// #require https://gist.github.com/raw/2625891/waitForKeyElements.js
// #version 1
// #grant GM_addStyle
// #run-at document-start
// ==/UserScript==
GM_addStyle ( "\
* {\
background-image: none !important;\
}\
\
img.gmImgHideHidden {\
display: none !important;\
}\
" );
var num = 0;
function gmImgHideShowImg(imgId, linkId)
{
// Using plain JavaScript because the page itself may not have jquery
var img = document.getElementById(imgId);
img.className = img.className.replace( /(?:^|\s)gmImgHideHidden(?!\S)/g , '' );
var lnk = document.getElementById(linkId);
lnk.parentNode.removeChild(lnk);
}
// Exporting the "show image" function so that it can be used in the webpage
unsafeWindow.gmImgHideShowImg = exportFunction(gmImgHideShowImg, unsafeWindow);
waitForKeyElements ("img", hideImageExceptForAltText);
function hideImageExceptForAltText (jNode) {
var imgId = jNode.attr("id");
// Ensuring an id exists so the image can be searched for later
if(typeof(imgId) == "undefined")
{
imgId = "gmImgHideImg" + num;
jNode.attr("id", imgId);
}
var imgDisp = jNode.css("display");
var imgAlt = jNode.attr("alt");
jNode.addClass("gmImgHideHidden");
var linkId = "gmImgHideLink" + num;
var linkNode = $("<a></a>");
linkNode.attr("id", linkId);
linkNode.append("Image: " + imgAlt);
linkNode.attr("onclick", "gmImgHideShowImg('" + imgId + "', '" + linkId + "'); return false;");
jNode.parent().append(linkNode);
num++;
}
MutationObserver is without a doubt the best solution here. Combined with early injection by #run-at document-start we can make the script pretty much bullet-proof. Check out this fiddle (tested with Firefox 40) to see it in action.
I think the code is pretty self-explanatory. I've annotated the subtleties, but leave a comment if there's anything you don't understand.
// ==UserScript==
// #run-at document-start
// ==/UserScript==
"use strict";
/* part one: <img> elements */
(new MutationObserver(function(Records, Obs) {
for (let R of Records) {/* examine each mutation record: */
/* if the record specifies an attribute mutation… */
if (
R.attributeName === "src" &&
(R.target instanceof Element) && /* this check might be necessary */
R.target.tagName.toLowerCase() === "img" &&
R.target.getAttribute("src") !== "" /* avoid infinite loop */
) {
R.target.setAttribute("src", "");
};
/* if the record specifies a sub-element mutation… */
for (let N of R.addedNodes) {
if (
(N instanceof Element) && /* this check might be necessary */
N.tagName.toLowerCase() === "img" &&
N.getAttribute("src") !== "" /* avoid infinite loop */
) {
N.setAttribute("src", "");
};
};
};
})).observe(document, {
/* changes wot we listen for */
childList : true,
subtree : true,
attributes : true
});
/* part two: background-image styles */
let check_for_head_elem = function(_, Obs) {
if (!document.head) {return;};
Obs.disconnect();
/* apply our style */
let Style = document.createElement("style");
document.head.appendChild(Style);
Style.sheet.insertRule("* {background-image : none !important;}", 0);
};
let check_for_root_elem = function(_, Obs) {
if (!document.documentElement) {return;};
Obs.disconnect();
/* observe until the <head> element is added */
Obs = new MutationObserver(check_for_head_elem)
Obs.observe(document.documentElement, {childList : true});
check_for_head_elem(null, Obs); /* check here because it might exist already */
};
{/* observe until the <html> element is added */
let Obs = new MutationObserver(check_for_root_elem);
Obs.observe(document, {childList : true});
check_for_root_elem(null, Obs); /* check here because it might exist already */
};
There are some other ways to get images on the page that I haven't taken into consideration (<iframe>, <svg>, <canvas>, <li> bullet points), but if necessary you should be able to use mutation observers or CSS to take care of those too.
A simple, robust way to do this is to set CSS first-thing, before any of the rest of the page loads.
#run-at document-start and GM_addStyle() do this. (on Firefox; not tested on latest Tampermonkey)
That way, the images are not displayed even for a fraction of a second, like they are with the original code or with a complicated, finicky MutationObserver approach.
This complete script shows the process:
// ==UserScript==
// #name _Hide pics except for alt text
// #include http://YOUR_SERVER.COM/YOUR_PATH/*
// #require http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js
// #require https://gist.github.com/raw/2625891/waitForKeyElements.js
// #grant GM_addStyle
// #run-at document-start
// ==/UserScript==
GM_addStyle ( " \
* { \
background-image: none !important; \
} \
img { \
display: none !important; \
} \
" );
/*--- $(document).ready() is not always needed for modern Firefox, but
use for maximum portability, when script runs at document-start.
*/
$(document).ready ( function () {
waitForKeyElements ("img", hideImageExceptForAltText);
} );
function hideImageExceptForAltText (jNode) {
var imgAlt = jNode.attr("alt") || "";
var imgTitle = jNode.attr("title") || "";
jNode.after ('<span title="' + imgTitle + '">' + imgAlt + '</span>');
}
This is a follow up of my earlier question. I'm trying to use Greasemonkey to change the text in a <td> to a link that contains that text.
So the page contains
<td class="something"><div style="width: 200px;">
randomtext
</div></td>
And I want to change it using Greasemonkey to:
<td class="something"><div style="width: 200px;">
randomtext
</div></td>
So far, I've cobbled together this little bit of code, but I'm sure it's the wrong approach as I'm not getting anywhere:
// ==UserScript==
// #require http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js
// ==/UserScript==
(function() {
var reference = document.getElementsByTagName('something')
var replacement = reference.replace(reference, "www.somewhere.com/q?=" + reference)
document.getElementById("user-reference-value").innerHTML = replacement;
})();
What more do I need to do to make this work?
Forget jQuery, it'll just slow your pages down.
I haven't really tested this code, but it should work maybe with some debugging:
// ==UserScript==
// ==/UserScript==
(function() {
// collect variables
// you can change this to change which element you replace
var reference = document.querySelector('td.something>div:first-child');
var text = reference.innerText;
var replacement = text.replace(reference, "www.somewhere.com/q?=" + reference);
// create new anchor tag
var a = document.createElement('a');
a.href = replacement;
a.innerText = text;
// do the replacement
reference.innerHTML = ''; // clear the old contents of the reference
reference.appendChild(a); // append the new anchor tag into the element
})();
This is a fairly standard operation for a Greasemonkey script. jQuery's .wrapInner()Doc and waitForKeyElements()Example make it easy.
Your complete script would look like this:
// ==UserScript==
// #name _Select text (re)linker
// #include http://YOUR_SERVER.COM/YOUR_PATH/*
// #require http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js
// #require https://gist.github.com/raw/2625891/waitForKeyElements.js
// #grant GM_addStyle
// ==/UserScript==
/*- The #grant directive is needed to work around a design change
introduced in GM 1.0. It restores the sandbox.
*/
waitForKeyElements (".something > div", linkifyText);
function linkifyText (jNode) {
jNode.wrapInner ( function () {
var newHref = 'http:\/\/www.somewhere.com\/q?='
+ encodeURIComponent (this.textContent.trim () );
//-- Note that link text will be filled in automatically.
var newLink = '';
return newLink;
} );
}
For example, I am trying to change this:
<a href="javascript: void(null)" class="jv-redirectCandidate"
key="pcxe7gwP"
>Some Name</a>
Into this:
Some Name
I need the string "pcxe7gwP" that is currently part of
key="pcxe7gwp"
and then I want to attach it to part of a URL
https://www.foo.com/something.aspx?p=
and the use that as the href in place of the current
"javascript: void(null)"
I am using the Tampermonkey Chrome extension and trying to create a userscript to accomplish this. I am new to userscripts and would love any help. Thanks!
Test in Greasemonkey, don't need jquery.
// ==UserScript==
// #name Change link href with it's key
// #namespace test
// #grant none
// #version 1
// #include http://localhost:8000/*.html
// ==/UserScript==
var prefix = 'https://www.foo.com/something.aspx?p=';
var links = document.querySelectorAll('a.jv-redirectCandidate[key]');
for (var i = 0; i < links.length; i += 1) {
var link = links[i];
link.href = prefix + link.getAttribute('key');
}
If I understood right, this is what you are looking for:
<html>
<script type="text/javascript">
function changeHREF(element){
element.href = "https://www.foo.com/something.aspx?p=" + element.key;
}
</script>
<body>
Some Name
</body></html>
Another possible solution:
<html>
<script type="text/javascript">
function changeHREF(){
elements = document.getElementsByClassName("jv-redirectCandidate");
for(i = 0; i<elements.length; i++) {
elements[i].href = "https://www.foo.com/something.aspx?p=" + elements[i].getAttribute("key");
}
}
</script>
<body onload="javascript:changeHREF()">
Some Name
</body></html>
Well, there are other solutions to achieve the same results. But, I think that it is out of topic.
Cheers
Here is a complete script that will work in either Tampermonkey or Greasemonkey. It use's jQuery for ease and power:
// ==UserScript==
// #name _De-javascript links
// #include http://YOUR_SERVER.COM/YOUR_PATH/*
// #require http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js
// #grant GM_addStyle
// ==/UserScript==
/*- The #grant directive is needed to work around a design change
introduced in GM 1.0. It restores the sandbox.
*/
//-- Get links with the class "jv-redirectCandidate".
var linksToFix = $("a.jv-redirectCandidate");
//-- Loop through the links
linksToFix.each ( function () {
var jThis = $(this); //-- An individual link
var key = jThis.attr ("key");
jThis.attr ("href", "https://www.foo.com/something.aspx?p=" + key);
} );
I have the following simple Greasemonkey script:
// ==UserScript==
// #name MetaCPAN Everywhere
// #description Add to every link to CPAN a link to MetaCPAN on a Google results page.
// #namespace http://ajct.info
// #match http://*/*
// #version 0.1
// ==/UserScript==
(function() {
var page_links = document.links;
for (var i=0; i<page_links.length; i++){
if (page_links[i].href.match(/http:\/\/search\.cpan\.org\/perldoc\?(.*?)$/i)) {
var match = page_links[i].href.match(/http:\/\/search\.cpan\.org\/perldoc\?(.*?)$/i);
var span = document.createElement("span");
span.innerHTML = " MetaCPAN";
page_links[i].parentNode.insertBefore(span, page_links[i].nextSibling);
}
}
})();
If I run the JavaScript snippet through firebug it does the right thing but if I install it and visit the search results page it doesn't seem to execute the script.
It's presumably something trivial but can anyone point out what I missed?
The main thing is that Google ajaxes-in just about all of its results, so you need a way to wait for the first batch and to check for later batches.
There are numerous techniques. A simple one is to use a timer:
//--- This handles both page-load delays, and AJAX changes.
var chkInterval = setInterval (checkForResultsLinks, 500);
function checkForResultsLinks () {
var links = document.querySelectorAll ('#search a');
if (links) {
for (var J = links.length - 1; J >= 0; --J) {
var link = links[J];
if (link.weHaveProcessed)
continue;
if (link.href.match (/http:\/\/search\.cpan\.org\/perldoc\?(.*?)$/i) ) {
var match = link.href.match (/http:\/\/search\.cpan\.org\/perldoc\?(.*?)$/i);
var span = document.createElement("span");
span.innerHTML = " MetaCPAN";
link.parentNode.insertBefore (span, link.nextSibling);
link.weHaveProcessed = true;
}
}
}
}
Notes:
Google search results appear inside a div with the id, "search".
Best add the // #run-at document-end directive to this kind of script.
The current script's#match directive is overly broad, the script will fire on every web page!
You probably want to restrict it to:
// #match http://www.google.com/*
// #match http://google.com/*
There is no need or point to wrapping the code in an anonymous function, like: (function() { ... })(); .
I found that some scripts although really simple wouldn't run in chrome, however I did find a chrome extension that fully supports greasemonkey scripts, it's called Tampermonkey