I would like to use Readability's javascript to clean up news articles, then download the generated article. What this entails is being able to execute their js code:
window.baseUrl = 'https://www.readability.com';
window.readabilityToken = '';
var s = document.createElement('script');
s.setAttribute('type','text/javascript');
s.setAttribute('charset','UTF-8');
s.setAttribute('src', baseUrl + '/bookmarklet/read.js');
document.documentElement.appendChild(s);
in an environment different from a traditional web browser. For example, this is possible to do by executing the above code on a site using Firebug; I would like to emulate that functionality through Java (without a browser). One of the problems I see here is the "window" object, which may not be present when accessing pages programmatically.
Any hints on whether this is possible and how to implement?
Take a look at a headless browser, such as EnvJS.
Related
Ultimatly what I want to do is look for, is the text It's just you! or It's not just you! within the container ID of: '< div id="container">' within the source of the resulting page of isup.me/echelonservices.co.uk.
I have found a way to do this now, but cannot point the Java to the correct site. What I have done is use the following URL: isup.me/echelonservices.co.uk. However, I am having problems doing this. Can someone let me know of a way of either using Javascript or another script source that can be used, without hosting the webpage from webserver. So running the webpage from local client computer.
Here is my last attempt I have come up with and failed miserably so far:
<script type="text/javascript">
//Specify where the sctipt should be running the code against.
window.location.protocol = "http"
window.location.host = "isup.me/echelonservices.co.uk"
//Look for the Class ID and output to a variable.
element = document.getElementById('container');
var Status = element.textContent || element.innerText;
//If the "Status" says: UP write UP, DOWN write DOWN and anything else write Status could not be determined!
if (Status=="UP") {document.write('<div style="color:#00BB00;font-family:Arial;font-weight:bold">UP</div>')}
else {if (Status=="DOWN") {document.write('<div style="color:#FF0000;font-family:Arial;font-weight:bold">DOWN</div>')}
else {document.write('<div style="color:#EDA200;font-family:Arial;font-weight:bold">WARNING:<br>Status could not be determined!</div>')};};
</script>
Fortunately, what you're doing isn't possible. JavaScript cannot read data from another domain (unless that domain is set up explicitly to allow it) - even if that domain is localhost. Otherwise, it would be possible to create a web page that loads Facebook in a hidden IFrame and steals a bunch of confidential user data.
What you'll need to do instead is implement this same logic up on your own web server, using the server side programming language of your choice (PHP, Java, C#, etc). You'd initiate an HTTP request to the desired server, parse the results accordingly, and then echo the results to the client. Basically, you're creating a proxy to that service.
If you're trying to do this without using a web server at all, you might want to check into another client-side technology such as WPF, Air, WinForms, Java, etc.
If you are using firefox, element.innerText isn't supported. Use element.innerHTML instead. Also, I'm not sure if this is a typo, but you have an extra closing bracket around your final else statement. I would recommend using a different syntax for your if statements to make them neater:
if (Status=="UP") {
document.write('<div style="color:#00BB00;font-family:Arial;font-weight:bold">UP</div>')
}
else if (Status=="DOWN"){
document.write('<div style="color:#FF0000;font-family:Arial;font-weight:bold">DOWN</div>')
}
else {
document.write('<div style="color:#EDA200;font-family:Arial;font-weight:bold">WARNING <br>Status could not be determined!</div>')
}
I have created a Chrome extension that uses the hotkeys [Alt]+[0...9] only to discover facebook uses the same hotkeys. Is there any way possible my extension could disable facebook's hotkeys so that mine fire alone? I'm fairly certain I have identified the code facebook uses to implement their [Alt]+[0...9] hotkeys:
document.documentElement.onkeydown=function(a){a=a||window.event;var b=a.target||a.srcElement;var c=a.keyCode==13&&!a.altKey&&!a.ctrlKey&&!a.metaKey&&!a.shiftKey&&CSS.hasClass...
This is in a script called from the head of the root document. I have tried the following to disable them:
//contents script:
$().ready( function() {
document.documentElement.onkeydown = '';
});
and even
$().ready( function() {
document.documentElement.onkeydown = function(e){};
});
I am guessing further that the reason neither of these attempts work is because although Chrome extension content scripts share a DOM with any webpage on which they run, perhaps they do not share coding environments? Any insight would be appreciated!
Chrome's Content scripts are executed in a Sandboxed environment [source]. There is no direct way to communicate with the global (window) object.
Another common pitfall is that the developer forgets how/when the script is injected.
By default, the script is injected at a point called "document_idle". At this point, the document is not busy (DOMContentLoaded has fired, window.onload may or may not have fired).
As a result, the functions in the script may be overwritten immediately after declaration.
To inject a small script, I recommend to add the code directly to the Content Script:
var actualCode = '/* Code here (see below for inspiration) */';
var script = document.createElement('script');
script.appendChild(document.createTextNode(actualCode));
(document.head || document.documentElement).appendChild(script);
script.parentNode.removeChild(script);
If you want to make sure that the method is not going to be overwritten, you can use Object.defineProperty, to define an immutable property:
Object.defineProperty(document.documentElement, 'onkeydown', {
value: function() {},
writable: false, /* Cannot be overwritten, default false */
configurable: false, /* Cannot be deleted, or modified */
enumerable: true /* Does not really matter. If true, it's visible in
a for-loop. If false, it's not*/
});
The previously mentioned method is supported in Firefox 4+ and at least Chrome 5+. If you want to also support Firefox 2+ and Chrome 1+, you can play with the __defineSetter__, to prevent onkeydown from being defined:
document.documentElement.__defineSetter__('onkeydown', function(){});
Your intuition is correct, the JavaScript that runs from a content script as part of a Chrome Extension is run in a sandbox that does not have access to the JavaScript that is executed in the containing page.
Per the Chrome doc on Content Scripts:
However, content scripts have some limitations. They cannot:
* Use chrome.* APIs (except for parts of chrome.extension)
* Use variables or functions defined by their extension's pages
* Use variables or functions defined by web pages or by other content scripts
First off, I would recommend that you consider different shortcut keys. Overriding the functionality of existing shortcut keys for your own extension could provide a jarring user experience for someone that is expecting the Facebook shortcut key. Imagine if an extension overrode the ctrl-c and ctrl-p shortcuts that are a part of the desktop OS for copy and paste - I think you would have some upset users that would probably remove the thing that changed the behavior they learned prior.
However, if you are insistent, then here is a workaround to loading JavaScript that will execute in the context of the containing page:
Edit: Updated per comment to reference JS file in a plugin instead of one hosted on the web
First, you will need to create a JavaScript file in your chrome plugin: override-fb-hotkeys.js.
First, you will need to host a JavaScript file somewhere on the web that contains the script that you want to execute in the page, let us say you host it at: http://example.com/override-fb-hotkeys.js.
Then, from your content script, you can insert a script tag into the DOM that references your JavaScript file, something like this:
var script = document.createElement('script');
script.setAttribute("type", "text/javascript");
script.setAttribute("async", true);
script.setAttribute("src", chrome.extension.getURL("override-fb-hotkeys.js")); //Assuming your host supports both http and https
var head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement;
head.insertBefore(script, head.firstChild)
The JavaScript will then be fetched and executed in the context of the containing page, not the sandboxed code from the Chrome plugin.
This is how you can do it using jQuery
Remove all shortcuts for any webpage:
$('[accessKey]').attr('accessKey','')
I'm writing a Chrome userscript to locally auto-save content in a CKEditor. I'm using this CKEditor auto-save plugin as inspiration.
I have written a function that fires every half second (via an interval) to register the CKEditor event handler:
var intervalId = window.setInterval(function() {
if (CKEDITOR) {
window.clearInterval(intervalId);
CKEDITOR.plugins.add("user-script-auto-save", {
init : function(editor) {
editor.on('key', startTimer);
}
});
}
}, 500);
However, it never properly completes, and complains that "CKEDITOR is undefined" on the if (CKEDITOR) statement.
Meanwhile, if I drop into Chrome's console and type CKEDITOR, the console prints out the expected object.
What am I missing? The editor is embedded within an iframe; might that have an impact on scoping? Or am I fighting against Chrome's sandboxing here? And if so, is there some other way I can dig into CKEditor to pull out the content every second or something to do the auto-saves?
I have not yet tried the script in Firefox; that's next on my list.
Worth noting: I'm a long-time JavaScript novice. So I could easily be doing something dumb with scoping or something like that.
According to this little tutorial video on YouTube, all the 3 "devices" are separated from each other in order to prevent XSS attacks from the user script to the browser / website and vice versa. Although the user scripts / content scripts are running in the website's context, they are still kept separated from the actual website script context. You can easily acknowledge this by simply trying to access for example jQuery from a content script. Just as the CKEditor, it will not be available.
So what I've come up with in order to deal with this is using the content script to include external JavaScripts in the head tag. AFAIK, this is not possible for files directly in the extension's root directory, so I've taken a remote server to host my files.
I'm not sure if this is the best approach and I think it is an ugly bypass, possibly way to powerfull and disabled by the Chromium Project some time.
(Edited by OP, so I can select this answer and route karma appropriately)
This answer, combined with some of the suggestions and links in the comments, ended up getting me to where I needed to be.
I ended up with the following function:
var insertScriptIntoDocument = function(scriptUrl, doc) {
// inspired by http://blog.afterthedeadline.com/2010/05/14/how-to-jump-through-hoops-and-make-a-chrome-extension/
var scriptText = doc.createTextNode(
'(function(loc) { \
var embeddedScript = document.createElement("script"); \
embeddedScript.type = "text/javascript"; \
embeddedScript.src = loc; \
document.getElementsByTagName("head")[0].appendChild(embeddedScript); \
})("' + scriptUrl + '");');
var injectorElement = doc.createElement('script');
injectorElement.appendChild(scriptText);
doc.body.appendChild(injectorElement);
};
Usage looks like so:
var embeddedScriptUrl = chrome.extension.getURL("embedded-script.js");
insertScriptIntoDocument(embeddedScriptUrl, document);
For now, I'm executing this from within a Chrome extension, but I suspect that the pattern might work in a GreaseMonkey script deployed via the Chrome TamperMonkey extension provided that the URL of the script to be embedded was hosted somewhere reachable.
FTR, as it turns out, I did not actually need to get to the iframe -- the CKEDITOR variable was defined in the top-level document, but was simply not visible because of the rules of the Chrome sandbox
I have been asked to automate the logging into a webapp(what I assume to be one, that runs a lot of .aspx and .js scripts) that, currently, can only run in IE. Now i am programming in Perl and have tried to use Win32::IE::Mechanize to run the IE browser and log in. What i did was try an extract all the forms from the webapp, and given the users information, fill out the required forms, but this is where the problem arises, when I try and run the subroutine no forms appear......
So then I transitioned into WWW::Mechanize and used the post subroutine(from LWP::UserAgent) which solved the problem for the most part. Now i've run into a problem in the response, from the server, I get this script as the content of the response and I don't know what to do with it.
So my question is: Using Perl how can I go about to manipulate a Javascript functions in a website? Would that even be a valid solution to the problem?
I am open to writing this in other programming languages as well. Thanks in advance for the help!
(So that I can fully log in to the webapp)
Update: The content of the response:
var msgTimerID;
var strForceLogOff = "false";
function WindowOnLoad(){
if ("false" == "true" && "false" == "false")
MerlinSystemMsg("",64);
if ("false"=="true")
msgTimerID = window.setInterval("MerlinSystemMsg(10095,64)", 300000,'javascript');
}
function MyShowModal(){
showModalDialog("", window, strFeatures);}
function clearMsgInterval(){
window.clearInterval(msgTimerID);
}
function WindowOnUnLoad(){
if(top.frames(0).document.getElementById("OPMODE").value =="LOGOFF"){
strFeatures = "width=1,height=1,left=1000,top=1000,toolbar=no,scrollbars=no,menubar=no,location=no,directories=no,status=yes,resizable=1";
window.open("ForceLogOff.aspx","forcelogout",strFeatures);
}
}
window.onbeforeunload = WindowOnUnLoad;
window.onload = WindowOnLoad;
There is also this Frame Title that has the src:
FRAME TITLE="Service Desk Express Navigator" SRC="options_nailogo.aspx" MARGINWIDTH=0 MARGINHEIGHT=0 NORESIZE scrolling=no
Trying to emulate the browser with a fully functioning JS engine is going to be a mighty big task. Instead, I'd suggest that you just try to emulate the actual interaction with the web site and not care what HTML/JS is actually sent back. Your server side code doesn't care how the HTTP submissions take place, only that they do. Admittedly this is more fragile if the forms change a lot, but at least you're not trying to implement a full browser.
So look at modules like LWP::UserAgent, HTTP::Request and HTTP::Response.
I'm copying and pasting my answer to your other duplicate question here
(You should consider deleting one of these?)
That content is the website source :)
How WWW::Mechanize deals with FRAME SRC as a link:
Note that <FRAME SRC="..."> tags are parsed out of the the HTML and
treated as links so this method works with them.
You'll want to use follow_link on that link.
As far as dealing with Javascript, there is support for a Firefox Add-on called MozRepl that you can use in conjunction with WWW::Mechanize::Firefox that I have used in the past to call Javascript code while crawling a page.
Goal: To create a bookmarklet that calls a remote javascript file that opens a popup window. The popup window is functionally similar to what Delicious's bookmarklet does.
Background: Currently, I'm using window.open within this javascript file, however the popup is getting blocked by pretty much every major browser.
The alternative solution to this is very similar to the way Delicious wrote their bookmarklet - calling window.open through a javascript query within the bookmarklet itself. However, I need the ability to modify the other contents of my javascript file in the future without requiring users to continually grab newest releases of the bookmarklet.
What I've determined to be happening: Since the window.open call is not occurring directly as a result of a click by the user, the browser feels this is something that should be blocked. Here's a source on this.
This is the tutorial I referenced most recently in creating the call to the remote js file.
Here is a basic example of what my code is doing; the window.open/popup portion is the only significant part I'm including as it's the only part I feel is causing the complication:
Example of the remote javascript file:
if (typeof jQuery == 'undefined') {
var jQ = document.createElement('script');
jQ.type = 'text/javascript';
jQ.onload=runthis;
jQ.src = 'http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js';
document.body.appendChild(jQ);
} else {
runthis();
}
function runthis() {
window.open('http://www.google.com/', 'a title',
'location=yes,links=no,scrollbars=no,toolbar=no,width=550,height=550');
}
I'd really appreciate any help as this has been stumping me for a while!
An approach that looks better and side-steps the blocking issue is to have the bookmarklet insert an iframe in the page the user is currently viewing. Ended up taking this approach back when I asked this question. Worked out fine.