Add dynamic div-layers (overlay) with a Greasemonkey script? - javascript

I am new to this so please be kind (;
I'm trying to use Greasemonkey to add div-layers and I just can't get it to work properly.
My final goal is to let the user draw a window on the screen (or make two clicks) and everything but this area should kind of fade out (added dark div-layers).
But, for now I just wanted to add a visible layer to every site. Here is my first try (which did not work at all) :
var CSSNJE = '#Test_divnje {height:100px; width:100px; background-color:red;
position:absolute; top: 200px; left: 400px; z-index:2147483647}';
var CSSNJE = '<style type="text/css">'+ CSSNJE +'</style>';
document.write(CSSNJE);
var DIVNJE = '<DIV id="Test_divnje"></DIV>';
document.write(DIVNJE);
I Googled this piece of code, which works for some pages but not many:
makeLayer('LYR1',400,250,100,100,'red',1,2147483647);
function makeLayer(id,L,T,W,H,bgColor,visible,zIndex) {
if (document.getElementById) {
if (document.getElementById(id)) {
alert ('Layer with this ID already exists!');
return;
}
var ST = 'position:absolute'
+'; left:'+L
+'; top:'+T
+'; width:'+W
+'; height:'+H
+'; clip:rect(0,'+W+','+H+',0)'
+'; visibility:'
+(null==visible || 1==visible ? 'visible':'hidden')
+(null==zIndex ? '' : '; z-index:'+zIndex)
+(null==bgColor ? '' : '; background-color:'+bgColor);
var LR = '<DIV id='+id+' style="'+ST+'"></DIV>'
if (document.body) {
if (document.body.insertAdjacentHTML)
document.body.insertAdjacentHTML("BeforeEnd",LR);
else if (document.createElement
&& document.body.appendChild) {
var newNode = document.createElement('div');
newNode.setAttribute('id',id);
newNode.setAttribute('style',ST);
document.body.appendChild(newNode);
}
}
}
}
First I thought the z-index of my div-layer was too low and my div-layer was just behind the visible layers (that's why my index is so high right now) but using a higher index did not help.
I also tried do use position:fixed because I read that this would maybe help, but it didn't.
How can I make an overlay that works?

Since you are starting out, use jQuery and (in this case) jQuery-UI. It makes coding vastly simpler, and will save you a ton of grief from trying to "reinvent the wheel" the hard way.
In jQuery-UI, two-thirds of what the question asks for is accomplished in 1 line of code:
$("#dialog").dialog ( {modal: true} );
Note that this is drag-able and sizable, right out of the box!
With Greasemonkey on Firefox, there is almost no cost to using jQuery, and jQuery-UI, either. The scripts are downloaded one time (when the script is installed or edited) and then run from the local machine. It's nice and fast.
Here is a complete Greasemonkey script that adds "a layer" with a re-sizable window to Stack Overflow pages:
// ==UserScript==
// #name _Add a User-interactive layer to a web page.
// #namespace _pc
// #include http://stackoverflow.com/*
// #require http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js
// #require http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js
// #resource jqUI_CSS http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/jquery-ui.css
// #resource IconSet1 http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/images/ui-icons_222222_256x240.png
// #resource IconSet2 http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/images/ui-icons_454545_256x240.png
// #grant GM_addStyle
// #grant GM_getResourceText
// #grant GM_getResourceURL
// ==/UserScript==
//--- Add our custom dialog using jQuery. Note the multi-line string syntax.
$("body").append (
'<div id="gmOverlayDialog"> \
Resize with the control in the lower-left, or by dragging any edge.<br><br> \
\
Click the x, or press the Escape key to close. \
</div> \
'
);
//--- Activate the dialog.
$("#gmOverlayDialog").dialog ( {
modal: true,
title: "Click and drag here.",
zIndex: 83666 //-- This number doesn't need to get any higher.
} );
/**********************************************************************************
EVERYTHING BELOW HERE IS JUST WINDOW DRESSING (pun intended).
**********************************************************************************/
/*--- Process the jQuery-UI, base CSS, to work with Greasemonkey (we are not on a server)
and then load the CSS.
*** Kill the useless BG images:
url(images/ui-bg_flat_0_aaaaaa_40x100.png)
url(images/ui-bg_flat_75_ffffff_40x100.png)
url(images/ui-bg_glass_55_fbf9ee_1x400.png)
url(images/ui-bg_glass_65_ffffff_1x400.png)
url(images/ui-bg_glass_75_dadada_1x400.png)
url(images/ui-bg_glass_75_e6e6e6_1x400.png)
url(images/ui-bg_glass_95_fef1ec_1x400.png)
url(images/ui-bg_highlight-soft_75_cccccc_1x100.png)
*** Rewrite the icon images, that we use, to our local resources:
url(images/ui-icons_222222_256x240.png)
becomes
url("' + GM_getResourceURL ("IconSet1") + '")
etc.
*/
var iconSet1 = GM_getResourceURL ("IconSet1");
var iconSet2 = GM_getResourceURL ("IconSet2");
var jqUI_CssSrc = GM_getResourceText ("jqUI_CSS");
jqUI_CssSrc = jqUI_CssSrc.replace (/url\(images\/ui\-bg_.*00\.png\)/g, "");
jqUI_CssSrc = jqUI_CssSrc.replace (/images\/ui-icons_222222_256x240\.png/g, iconSet1);
jqUI_CssSrc = jqUI_CssSrc.replace (/images\/ui-icons_454545_256x240\.png/g, iconSet2);
GM_addStyle (jqUI_CssSrc);
//--- Add some custom style tweaks.
GM_addStyle ( ' \
div.ui-widget-overlay { \
background: red; \
opacity: 0.6; \
} \
' );

Related

Code working in browser console but not in tampermonkey

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.

How to make a GreaseMonkey script affect elements in a page before they're displayed?

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

Replace text with link to that text?

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

How to change the opacity of a text in search box?

http://i.stack.imgur.com/P3ZTz.jpg
You guys have any idea,if so can you please give me an example? (I'am a novice)
Thank you
Credit goes to Krowe.
// ==UserScript==
// #name Tamper with Google Results
// #namespace http://superuser.com/users/145045/krowe
// #version 0.1
// #description This just modifies google results to exclude certain things.
// #match http://*.google.com
// #match https://*.google.com
// #copyright 2014+, KRowe
// ==/UserScript==
function GM_main () {
window.onload = function () {
var targ = window.location;
if(targ && targ.href && targ.href.match('https?:\/\/www.google.com/.+#q=.+') && targ.href.search("/+-torrent/+-watch/+-download")==-1) {
targ.href = targ.href +"+-torrent+-watch+-download";
}
};
}
//-- This is a standard-ish utility function:
function addJS_Node(text, s_URL, funcToRun, runOnLoad) {
var D=document, scriptNode = D.createElement('script');
if(runOnLoad) scriptNode.addEventListener("load", runOnLoad, false);
scriptNode.type = "text/javascript";
if(text) scriptNode.textContent = text;
if(s_URL) scriptNode.src = s_URL;
if(funcToRun) scriptNode.textContent = '(' + funcToRun.toString() + ')()';
var targ = D.getElementsByTagName('head')[0] || D.body || D.documentElement;
targ.appendChild(scriptNode);
}
addJS_Node (null, null, GM_main);
Using (-) sign I can exclude unwanted results,but dont want the other users become aware of it.If someone searches Google or any other search engine this phrase(-torrent-download-watch) should be automatically and invisibly added
edit- how can I use css to add a blank white layer on top of the unwanted text and sync them in the textarea?
For example : http://i.stack.imgur.com/uAz0i.jpg
No, you can't change opacity for partial content.
However you can hide the input box and place a overlay div, which can mimic as a textbox, that can be then further styled with different text colors.
Take a hint from following post:
How do I make a div element editable (like a textarea when I click it)?
You can use color to change to color of the text.
color:rgb(255,0,0); //red
color:rgba(255,0,0,0.5); //half opaque red.
The first three numbers are color, the fourth is opacity.

Replace Facebook thumbnails in a RSS Reader (InoReader)

I'm looking to create a Greasemonkey script that will replace Facebook thumbnails in InoReader or any other RSS reader. Previously I had been successfully using the script below in Google Reader, but it doesn't work in InoReader, Feedly, or any non-Google RSS Reader.
// ==UserScript==
// #id greader-facebookurlreplacer
// #name Google Reader - Facebook URL Replacer
// #version 1.1
// #namespace
// #author
// #description
// #include https://www.google.com/reader/*
// #include https://www.feedspot.com/*
// ==/UserScript==
document.getElementById("chrome").addEventListener("DOMNodeInserted", function (e) {
if (e.target.tagName && e.target.tagName == "DIV" && /entry\s?/.test(e.target.className)) {
var t = e.target.getElementsByTagName("img");
for (var n in t) {
var r = t[n];
if (/.*akamaihd\.net.*_s\.\w+$/.test(r.src)) {
r.style.width = r.style.height = "inherit";
r.src = r.src.replace(/_s\.(\w+)$/, "_n.$1")
}
}
}
}, false)
I also tried using the following code retrieved from a similar post on stackoverflow, but it doesn't work either in InoReader.
$("img[src^='https://fbcdn-photos-a.akamaihd.net']")
.each(function()
{
this.src = this.src.replace(/(\/[^/]*)s\.jpg$/, '/s720x720$1n.jpg');
});​
Any help would be greatly appreciated.
DOMNodeInserted is deprecated. Don't use that approach anymore. Best to use a utility like waitForKeyElements.
After that, it's just a matter of finding the right jQuery selector for the images, and then the right regex to convert the src to the one for the larger image size. (But note that some sites deliberately make the regex approach impossible.)
For the sample RSS feed you listed, on inoreader.com, we can use Firebug to determine a CSS/jQuery path to the thumbnails of:
#reader_pane div.article_full_contents div.article_content a.underlink img
For the src changes/regex, see the code.
Here's how to replace the images, for that feed, on that reader:
// ==UserScript==
// #name _InoReader thumbnail replacer
// #include http://www.inoreader.com/*
// #require http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/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 (
"#reader_pane div.article_full_contents div.article_content a.underlink img",
swapOutFbcdnThumnails
);
function swapOutFbcdnThumnails (jNode) {
/*-- Change src from:
https://fbcdn-photos- ... _s.jpg
to:
https://fbcdn-sphotos- ... _n.jpg
*/
var newSrc = jNode[0].src.replace (/fbcdn\-photos\-/, "fbcdn-sphotos-");
newSrc = newSrc.replace (/_s\.jpg$/, "_n.jpg");
jNode[0].src = newSrc;
}

Categories