xpath greasemonkey - javascript

I am trying to modify gmail in a greasemonkey script. Using xpather i can get the xpath expression for the part i am trying to hide. But using following snippet i can not get a match. alert function is never called. Can anyone point me to what am i doing wrong?
var allLinks, thisLink;
allLinks = document.evaluate(
"//html/body/div[1]/div/div/div[1]/div/div[3]/div[1]/div[2]/div[2]/div[1]/div[1]",
document,
null,
XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
null);
for (var i = 0; i < allLinks.snapshotLength; i++) {
thisLink = allLinks.snapshotItem(i);
alert("found");
}
#Alan Storm
I installed firebug tested the script using console it works but still i can not get it to work under greasemonkey. Greasemonkey still not giving me an alert box. I also tried adding a on load event listener that did not helped either.

First, a general debugging tip, then a stab at your problem.
Remember that Greasemonkey scripts are just javascript, and you can still use all the Javascript tools avaiable to you to debug your problem. Open up gmail, fire up Firebug, and try running your javascript code directly on the command line (click the upward circle arrow to the right of the console line for a bigger typing area).
When I did the above with your javascript snippet, allLinks.snapshotLength was evaluating to 0, indicating that your xpath expression didn't match anything. This is odd, because when I used XPath Checker, it matched the logo.
Digging in a bit deeper, it looks like gmail's main document is a number of iframes, and the iframes contain the actual application elements. Specifically, there's a frame with an ID of "canvas_frame" which contains the actual DOM for the application interface. When I try
canvas = window.frames[document.getElementById('canvas_frame').name].document;
allLinks = canvas.evaluate(
"//html/body/div[1]/div/div/div[1]/div/div[3]/div[1]/div[2]/div[2]/div[1]/div[1]",
canvas,
null,
XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
null);
I get a response with a length of 1, which may suit your needs better.
Finally, this isn't required, but your xPath expression looks a little fragile. If gmail changes the document structure even slightly (say, with a wrapper div), your program will break. Consider something like this instead.
<!--
all divs on the page that contains an h1 element
that contains the text "Gmail Logo"
-->
//div[contains(./h1,"Gmail Logo")]

Related

CKEditor: How to insert anchor tag into document?

On the surface this should be easy:
CKEDITOR.instances[Object.keys(CKEDITOR.instances)[0]].insertHtml( html );
...where html is a string of an actual HTML tag. Sadly, however, this doesn't work. When I click the button on my page that calls this code, nothing happens. It doesn't appear anywhere in the document at all, not even in Source mode.
I tried using insertElement:
var element = CKEDITOR.dom.element.createFromHtml( html );
CKEDITOR.instances.editor1.insertElement( element );
...and all it did was stick a little red flag in the document that was nothing; if I saved the document and reloaded it, it was gone.
The goal is to insert:
<a name="something"></a>
But the only thing that works is insertText() and that turns it into "safe" text, i.e. the < and > turn into lt; and gt;.
Help please? :)
I guess you used the code from the CKEDITOR Documentation (https://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-insertElement)
You probably ran into an issue, which says, that empty anchors show
a little red flag in the editor
(https://dev.ckeditor.com/ticket/14689). Unfortunately there seems to
be no way of CKEDITOR from doing this.
Empty Links are removed from
CKEDITOR automatically. You can add data-cke-survive="true" so these
links aren't removed,
Regards

Chrome extension breaks DOM

I'm making a Chrome extension that replaces certain text on a page with new text and a link. To do this I'm using document.body.innerHTML, which I've read breaks the DOM. When the extension is enabled it seems to break the loading of YouTube videos and pages at codepen.io. I've tried to fix this by excluding YouTube and codepen in the manifest, and by filtering them out in the code below, but it doesn't seem to be working.
Can anyone suggest an alternative to using document.body.innerHTML or see other problems in my code that may be breaking page loads? Thanks.
var texts=["some text","more text"];
if(!window.location.href.includes("www.google.com")||!window.location.href.includes("youtube.com")||!window.location.href.includes("codepen.io")){
for(var i=0;i<texts.length;i++){
if(document.documentElement.textContent || document.documentElement.innerText.includes(texts[i])){
var regex = new RegExp(texts[i],'g');
document.body.innerHTML = document.body.innerHTML.replace(regex,
"<a href='https://www.somesite.org'>replacement text</a>");
}
}
}
Using innerHTML to do this is like using a shotgun to do brain surgery. Not to mention that this can even result in invalid HTML. You will end up having to whitelist every single website that uses any JavaScript at this rate, which is obviously not feasible.
The correct way to do it is to not touch innerHTML at all. Recursively iterate through all the DOM nodes (using firstChild, nextSibling) on the page and look for matches in text nodes. When you find one, replace that single node (replaceChild) with your link (createElement), and new text nodes (createTextNode, appendChild, insertBefore) for any leftover bits.
Essentially you will want to look for a node like:
Text: this is some text that should be linked
And programmatically replace it with nodes like:
Text: this is
Element: a href="..."
Text: replacement text
Text: that should be linked
Additionally if you want to support websites that generate content with JavaScript you'll have to run this replacement process on dynamically inserted content as well. A MutationObserver would be one way to do that, but bear in mind this will probably slow down websites.

How can you see which Javascript script generated a certain html line?

I have some crazy app done almost 100% by manipulating the DOM and I find myself in the unfortunate position of changing something in it. As there are probably around 100 different scripts that do God knows what, I have no clue in which file should I look to make my changes. So, I want to ask, is there a way (using Firebug maybe or something similar) to know where a specific piece of html was generated? I'm a C developer, so I'm not very good at this, it drives me crazy.
Are all the elements added at the page load, or partially in the response to the user input? (clicking etc.)
for stuff added with the response to your actions, you can use Firebug's "Break On Next" button in the "Script" tab. To active BON you have to click it, or, in just-shipped Firebug 1.10.0a8, use keyboard shortcut ALT-CTRL-B (useful when you have event listeners bound to mouse movements). Then, when any piece of JS is going to be executed in reaction to your click etc., you will hit a breakpoint.
for stuff added at page load time, you may use the trick of extending the native functions (this might sound crazy - yeah it is, don't do it in production!) like appendChild, insertBefore, replaceChild. Just insert the appropriate code at the very top of your main HTML file, so all the code below will "see" the change.
Unfortunately, this does not work in Firefox due to a bug. But works in Opera and I guess in Chrome as well.
When you extend the native function, you can inject any code before really adding the node to the page. For instance, call console.log or create a breakpoint, to inspect the current page state. You can try playing with breakpoints to see the available variables properties inside those function to adjust what you push to console.log.
For this code:
<!doctype html>
<html>
<head>
<script type="text/javascript">
// this should work in Firefox but it does not -- https://bugzilla.mozilla.org/show_bug.cgi?id=618379
// works at least in Opera, probably Chrome too
Node.prototype._appendChild = Node.prototype.appendChild;
Node.prototype.appendChild = function(child) {
console.log("appending " + child + " to " + this);
return this._appendChild(child); // call the original function with the original parameters
}
// this works in Firefox
document._createElement = document.createElement;
document.createElement = function(tagName){
console.log("creating " + tagName);
return this._createElement(tagName);
}
</script>
</head>
<body>
<script type="text/javascript">
var p = document.createElement("p");
p.appendChild( document.createTextNode("abc"));
document.body.appendChild(p);
</script>
</body>
</html>
Opera outputs:
creating p appendChild.html:14
appending [object Text] to [object HTMLParagraphElement] appendChild.html:7
appending [object HTMLParagraphElement] to [object HTMLBodyElement] appendChild.html:7
To overcome the weakness of Firefox (that you can't override appendChild), you may use the trick: place the code below instead in the top of your HTML
<script>
Node.prototype._appendChild = function(child) {
console.log("appending " + child + " to " + this);
return this.appendChild(child)
};
</script>
and then, use Fiddler proxy by creating auto-responders (WMV tutorial, 9.9 MB) where you manually replace all calls to .appendChild with ._appendChild (you can use Notepad++ for "find replace in all opened files"). Creating auto-responders and hand-tampering requests can be mundane, but it's extremely powerful. To quickly create auto-responder rule, load the page when Fiddler is active, then drag'n'drop files as in the picture below. For each file, right click and choose "Generate File" from menu (this will put a file on the desktop) or create a file by yourself in different location. (it's good to open Fiddler-generated files and remove response headers from them; BTW "Generate file" puts real contents only if the response header was 200, so make sure to load the page with CTRL-F5 to skip the cache).
In Chrome you can inspect an element and right click on it. This menu gives you some options to break when something below the element is changed or when it's own attributes change. Maybe one of those breakpoints will find what you are looking for?
Assuming you've got access to the raw (hopefully un-minified/obfuscated) JS files, maybe just search them for text strings related to DOM manipulation and/or attributes of the node you're trying to find the creation of? I'd try things like "appendChild" "createElement" and the node's ID/class names.
You could also set break points all over the script files, and step through them as the page loads to help you narrow down where to look. Might help to start by just "pausing" the JS execution and stepping through from the very beginning.
If you can share the code (a link to the live site would do fine) I'd be happy to take a look.
If you are using the jQuery framework in your javascript to make the DOM changes then you may find the fireQuery plugin for FireBug in the firefox browser may get you the information you need.
Example:
It adds additional information to the standard HTML view by superimposing additional jquery element information to the display to provide a deeper insight into how your javascript is amending the page content.
I hope that helps you out.

replace text function not working in explorer

I have a js replace function to replace text next to two radio buttons on a pre set form.
Script is as follows.
document.body.innerHTML=document.body.innerHTML.replace("Payment by <b>Moneybookers</b>
e-wallet<br>","");
document.body.innerHTML=document.body.innerHTML.replace("Maestro, Visa and other credit/debit cards by <b>Moneybookers</b>","Pago con Diners Club, Mastercard o Visa");}onload=x;
The script works fine in Chrome and Firefox, however, the script is not actioned in Explorer.
I believe it has something to do with there being , / - within the text I am replacing? When I use the function to replace text with no , / - in the text - it works fine in explorer, however, for example when I try to replace text.. - "Maestro, Visa and other credit/debit cards by Moneybookers" this does not work in explorer.. I'm assuming because of the coma and forward slash. Honestly I've tried everything but just can not get this to work. Any help would be greatly appreciated!!
Not sure whether it's related (I'm a Mac user without IE) but you shouldn't use multiline strings. Use \n instead.
What is returned by innerHTML varies from one browser to an other, because there is no standard about it (the content will be the same, but the way it's displayed can be different). Doing replace like that is likely to fail on some browser. You should just take an other approach to do your replace.
A better approach would be to wrap the text you want to replace with a span, this way you can more easily target the content you want to replace.
<span id="thatFirstThing">Payment by <b>Moneybookers</b>e-wallet<br></span>
An after you can do
document.getElementById("thatFirstThing").innerHTML = "";
P.S.: Doing innerHTML replace on the body also has a huge side-effect. Since you are replacing the content of your hole page. All the event handler that where bind on your page will disappear.
Edit: If you can't modify the HTML page, it's a little bit more tricky, because the DOM is not well adapted to do such thing. What you could do is to target parent element by navigating through the DOM with document.getElementById and childNodes. And once you have your parent element just write the new content you want, without doing replace.
In the end it would look something like this :
document.getElementById("someSection").childNodes[0].childNodes[1].childNodes[0].innerHTML = "";

IE7 display oddity (example attached)

I'm working on a Javascript-based replacement for a Flash applet. The site is having rendering problems only in IE, where it exhibits a behavior that has me at wit's end.
http://janetalasher.com/new/content/portfolio/artcloth/ (This is the page)
What does IE do that's so strange (in this case only)? If you look in Firefox, you'll see a table of images on the right which has the thumbnails. IE6 and IE7 don't show this... unless you are in print preview. It's not a CSS glitch - I've disabled all stylesheets and the error still occurs. I'd provide more relevant source code, but I don't even know where the problem is. The .js files that I suspect (if it's any help) are:
/common/gallery/display.js
/common/gallery/loader.js
Okay - update: It is definitely rendering properly in print preview mode only. Can someone please explain to me in what world this happens? The div is present in the normal mode, but the table won't render. Using the IE developer toolbar confirms it and all the cells are present.
Try adding semi-colons here:
function loadGallery(xml)
{
thumbpath = $(xml).find("thumbpath").attr('dir') // add here
imagepath = $(xml).find("imagepath").attr('dir') // here
detailpath = $(xml).find("detailpath").attr('dir') // and here
cSheet = contactSheet(xml);
$('.contactSheet')[0].appendChild(cSheet);
display($(cSheet).find('img')[0]);
}
Also, on this line:
jQuery.get('/new/content/portfolio/artcloth/gallery.xml' , 'xml' , function(data) { loadGallery(data); } ) // missing one here too
Actually, your Javascript files are missing semi-colons on the end too. Make sure you go through each file and add one to the end of each line.
Javascript does not actually require them, but for the sake of sanity and knowing exactly what your code is going it is a good idea to put them in. For example:
return
1
Can become:
return;
1;
Which returns nothing at all, not exactly the desired effect.
According to Microsoft Script Editor, there's an error inside jQuery caused by this line:
$('#lower').css('padding-left' , paddingLeft - (lowerRightProtrusion < 0 ? 0 : lowerRightProtrusion) + "px");
Since lowerRightProtrusion is NaN, and NaN < 0 calculates to false, you're actually setting padding-left to "NaNpx". Does not compute ;)
See my previous answer for info about MS Script Editor:
Using the IE8 'Developer Tools' to debug earlier IE versions
It would seem that IE is not picking up the styles. If I open the page in chrome, the "float:left" style appears on the description div. however, in IE this is not the case.
You currently have your includes in a div in the body of the document. If it is possible try moving these into the head. I'm talking about the link and script tags directly descendant of div id="pageHead".
(I am using IE6 and the developer toolbar to get this information)
In /common/css/generic.css:
div#information
{
margin-left:188px;
m\argin-left:94px; <------ not sure if that would cause this, but thought i would point it out
}

Categories