Related
I have a custom userscript that I'm running in Chrome and Firefox using Tampermonkey/Greasemonkey.
Is there any way of using this script in IE11? Or is there any plugins for IE11 that does what Tampermonkey/Greasemonkey does?
TrixIE WPF4.5 claims to emulate Greasemonkey on IE11.
Unfortunately, the original Trixie and IE7Pro stopped working around IE8-ish.
I use localStorage to make it work, which is supported by IE8 or later.
Steps:
Run the following code in IE's developer tool when the current window is in the domain where you want the script to run in:
var scriptName = 'Hello world';
function scriptBody(){
//---userscript starts--->
document.body.innerHTML = '<h1>Hello world!</h1>';
//---userscript ends--->
}
var script = scriptBody.toString()
.split('//---userscript starts--->')[1]
.split('//---userscript ends--->')[0];
localStorage.setItem(scriptName, script);
Create a bookmark and modify the URL into:
javascript:(function(){eval(localStorage.getItem('Hello world'));})()
Advantages:
No additional plugin needed.
Almost no script text length limit.
Disadvantages:
Need a user to click on a bookmark to run the script.
Need a reinstall if a user clears the browser cache.
A simple Google Search (I searched "greasemonkey for IE") yields various alternatives available for other browsers:
http://en.wikipedia.org/wiki/Greasemonkey#Equivalents_for_other_browsers
For Internet Explorer, similar functionality is offered by IE7Pro,[19] Sleipnir,[20] and iMacros.
Fiddler supports modifying the response of http requests.
We can use this feature to load userscript in any browser, include IE8.
This is an example:
static function OnBeforeResponse(oSession: Session) {
if (m_Hide304s && oSession.responseCode == 304) {
oSession["ui-hide"] = "true";
}
// match url
if (oSession.fullUrl == "http://apply.ccopyright.com.cn/goadatadic/getR11List.do") {
oSession.utilDecodeResponse();
var script = System.IO.File.ReadAllText("C:\\GitHub\\#selpic\\P660_printer\\Printer\\scripts\\form-save-load.js")
oSession.utilReplaceOnceInResponse("</body>", "<script>"+script+"</script></body>", true);
}
}
doc: Modifying a Request or Response
Just open Developer tools (press F12) and paste your script to Console, and then run it (Ctrl + Enter).
Is it possible, using javascript, to control an overlay firefox extension? I've extracted the contents of the extension and have identified what functions/methods I need to run, but they are not accessible within the scope of the console.
Thanks in advance for any ideas.
Yes it possible to interact with other add-ons, given the right circumstances.
My test case here will be com.googlecode.sqlitemanager.openInOwnWindow(), which is part of the SqliteManager addon.
In newer builds (I'm using Nightly), there is the Browser Toolbox. With it is is as simple as opening a toolbox and executing com.googlecode.sqlitemanager.openInOwnWindow() in the Console.
You may instead use the Browser Console (or any chrome enabled WebDev Console for that matter, e.g. the Console of "about:newtab"). But you need some boilerplate code to first find the browser window. So here is the code you can execute there: var bwin = Services.wm.getMostRecentWindow("navigator:browser"); bwin.com.googlecode.sqlitemanager.openInOwnWindow()
Again, enable chrome debugging. Then open a Scratchpad and switch to Chrome in the Environment menu. Now executing com.googlecode.sqlitemanager.openInOwnWindow() in our Scratchpad will work.
You may of course write your own overlay add-on.
As a last resort, patch the add-on itself.
Bootstrapped/SDK add-ons: you can load XPIProvider.jsm (which changed location recently) and get to the bootstrapped scope (run environment of bootstrap.js) via XPIProvider.bootstrapScopes[addonID], and take it from there (use whatever is in the bootstrap scope, e.g. the SDK loader).
Now about the right circumstances: If and how you can interact with a certain add-on depends on the add-on. Add-ons may have global symbols in their overlay and hence browser window, such as in the example I used. Or may use (to some extend) JS code modules. Or have their own custom loader stuff (e.g. AdBlock Plus has their own require()-like stuff and SDK add-ons have their own loader, which isn't exactly easy to infiltate)...
Since your question is rather unspecific, I'll leave it at this.
Edit by question asker: This is correct, however I figured I'd add an example of the code I ended up using in the end, which was in fact taken directly from mozilla's developer network website:
In my chrome js:
var myExtension = {
myListener: function(evt) {
IprPreferences.setFreshIpStatus(true); // replace with whatever you want to 'fire' in the extension
}
}
document.addEventListener("MyExtensionEvent", function(e) { myExtension.myListener(e); }, false, true);
// The last value is a Mozilla-specific value to indicate untrusted content is allowed to trigger the event.
In the web content:
var element = document.createElement("MyExtensionDataElement");
element.setAttribute("attribute1", "foobar");
element.setAttribute("attribute2", "hello world");
document.documentElement.appendChild(element);
var evt = document.createEvent("Events");
evt.initEvent("MyExtensionEvent", true, false);
element.dispatchEvent(evt);
Update for Firefox 47 and up
Things changed drastically in Firefox 47. This is the new way to access it.
var XPIScope = Cu.import('resource://gre/modules/addons/XPIProvider.jsm');
var addonid = 'Profilist#jetpack';
var scope = XPIScope.XPIProvider.activeAddons.get(addonid).bootstrapScope
Old way for < Firefox 47
Update for methods of today
Typically you will do so like this:
If i wanted to get into AdBlocks scope, I check AdBlock id, it is {d10d0bf8-f5b5-c8b4-a8b2-2b9879e08c5d} so I would go:
var XPIScope = Cu.import('resource://gre/modules/addons/XPIProvider.jsm');
var adblockScope = XPIScope.XPIProvider.bootstrapScopes['{d10d0bf8-f5b5-c8b4-a8b2-2b9879e08c5d}'];
You can now tap into anything there.
Another example, I have an addon installed with id NativeShot#jetpack
I would tap into it like this:
var XPIScope = Cu.import('resource://gre/modules/addons/XPIProvider.jsm');
var nativeshotScope = XPIScope.XPIProvider.bootstrapScopes['NativeShot#jetpack'];
if you do console.log(nativeshotScope) you will see all that is inside.
IE9 Bug - JavaScript only works after opening developer tools once.
Our site offers free pdf downloads to users, and it has a simple "enter password to download" function. However, it doesn't work at all in Internet Explorer.
You can see for yourself in this example.
The download pass is "makeuseof". In any other browser, it works fine. In IE, both buttons do nothing.
The most curious thing I've found is that if you open and close the developer toolbar with F12, it all suddenly starts to work.
We've tried compatibility mode and such, nothing makes a difference.
How do I make this work in Internet Explorer?
It sounds like you might have some debugging code in your javascript.
The experience you're describing is typical of code which contain console.log() or any of the other console functionality.
The console object is only activated when the Dev Toolbar is opened. Prior to that, calling the console object will result in it being reported as undefined. After the toolbar has been opened, the console will exist (even if the toolbar is subsequently closed), so your console calls will then work.
There are a few solutions to this:
The most obvious one is to go through your code removing references to console. You shouldn't be leaving stuff like that in production code anyway.
If you want to keep the console references, you could wrap them in an if() statement, or some other conditional which checks whether the console object exists before trying to call it.
HTML5 Boilerplate has a nice pre-made code for console problems fixing:
// Avoid `console` errors in browsers that lack a console.
(function() {
var method;
var noop = function () {};
var methods = [
'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error',
'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log',
'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd',
'timeStamp', 'trace', 'warn'
];
var length = methods.length;
var console = (window.console = window.console || {});
while (length--) {
method = methods[length];
// Only stub undefined methods.
if (!console[method]) {
console[method] = noop;
}
}
}());
As #plus- pointed in comments, latest version is available on their GitHub page
Here's another possible reason besides the console.log issue (at least in IE11):
When the console is not open, IE does pretty aggressive caching, so make sure that any $.ajax calls or XMLHttpRequest calls have caching set to false.
For example:
$.ajax({cache: false, ...})
When the developer console is open, caching is less aggressive. Seems to be a bug (or maybe a feature?)
This solved my problem after I made a minor change to it. I added the following in my html page in order to fix the IE9 problem:
<script type="text/javascript">
// IE9 fix
if(!window.console) {
var console = {
log : function(){},
warn : function(){},
error : function(){},
time : function(){},
timeEnd : function(){}
}
}
</script>
Besides the 'console' usage issue mentioned in accepted answer and others,there is at least another reason why sometimes pages in Internet Explorer work only with the developer tools activated.
When Developer Tools is enabled, IE doesn't really uses its HTTP cache (at least by default in IE 11) like it does in normal mode.
It means if your site or page has a caching problem (if it caches more than it should for example - that was my case), you will not see that problem in F12 mode. So if the javascript does some cached AJAX requests, they may not work as expected in normal mode, and work fine in F12 mode.
I guess this could help, adding this before any tag of javascript:
try{
console
}catch(e){
console={}; console.log = function(){};
}
If you are using AngularJS version 1.X you could use the $log service instead of using console.log directly.
Simple service for logging. Default implementation safely writes the message into the browser's console (if present).
https://docs.angularjs.org/api/ng/service/$log
So if you have something similar to
angular.module('logExample', [])
.controller('LogController', ['$scope', function($scope) {
console.log('Hello World!');
}]);
you can replace it with
angular.module('logExample', [])
.controller('LogController', ['$scope', '$log', function($scope, $log) {
$log.log('Hello World!');
}]);
Angular 2+ does not have any built-in log service.
If you are using angular and ie 9, 10 or edge use :
myModule.config(['$httpProvider', function($httpProvider) {
//initialize get if not there
if (!$httpProvider.defaults.headers.get) {
$httpProvider.defaults.headers.get = {};
}
// Answer edited to include suggestions from comments
// because previous version of code introduced browser-related errors
//disable IE ajax request caching
$httpProvider.defaults.headers.get['If-Modified-Since'] = 'Mon, 26 Jul 1997 05:00:00 GMT';
// extra
$httpProvider.defaults.headers.get['Cache-Control'] = 'no-cache';
$httpProvider.defaults.headers.get['Pragma'] = 'no-cache';
}]);
To completely disable cache.
It happened in IE 11 for me. And I was calling the jquery .load function.
So I did it the old fashion way and put something in the url to disable cacheing.
$("#divToReplaceHtml").load('#Url.Action("Action", "Controller")/' + #Model.ID + "?nocache=" + new Date().getTime());
I got yet another alternative for the solutions offered by runeks and todotresde that also avoids the pitfalls discussed in the comments to Spudley's answer:
try {
console.log(message);
} catch (e) {
}
It's a bit scruffy but on the other hand it's concise and covers all the logging methods covered in runeks' answer and it has the huge advantage that you can open the console window of IE at any time and the logs come flowing in.
We ran into this problem on IE 11 on Windows 7 and Windows 10. We discovered what exactly the problem was by turning on debugging capabilities for IE (IE > Internet Options > Advanced tab > Browsing > Uncheck Disable script debugging (Internet Explorer)). This feature is typically checked on within our environment by the domain admins.
The problem was because we were using the console.debug(...) method within our JavaScript code. The assumption made by the developer (me) was I did not want anything written if the client Developer Tools console was not explicitly open. While Chrome and Firefox seemed to agree with this strategy, IE 11 did not like it one bit. By changing all the console.debug(...) statements to console.log(...) statements, we were able to continue to log additional information in the client console and view it when it was open, but otherwise keep it hidden from the typical user.
I put the resolution and fix for my issue . Looks like AJAX request that I put inside my JavaScript was not processing because my page was having some cache problem. if your site or page has a caching problem you will not see that problem in developers/F12 mode. my cached JavaScript AJAX requests it may not work as expected and cause the execution to break which F12 has no problem at all.
So just added new parameter to make cache false.
$.ajax({
cache: false,
});
Looks like IE specifically needs this to be false so that the AJAX and javascript activity run well.
What's the simplest way to launch Firefox, load a 3rd party website (which I'm authorised to "automate"), and run some "privileged" APIs against that site? (e.g: nsIProgressListener, nsIWindowMediator, etc).
I've tried a two approaches:
Create a tabbed browser using XULrunner, "plumbing" all the appropriate APIs required for the 3rd party site to open new windows, follow 302 redirects, etc. Doing it this way, it's an aweful lot of code, and requires (afaict) that the user installs the app, or runs Firefox with -app. It's also extremely fragile. :-/
Launch Firefox passing URL of the 3rd party site, with MozRepl already listening. Then shortly after startup, telnet from the "launch" script to MozRepl, use mozIJSSubScriptLoader::loadSubScript to load my code, then execute my code from MozRepl in the context of the 3rd party site -- this is the way I'm currently doing it.
With the first approach, I'm getting lots of security issues (obviously) to work around, and it seems like I'm writing 10x more browser "plumbing" code then automation code.
With the second approach, I'm seeing lots of "timing issues", i.e:
the 3rd party site is somehow prevented from loading by MozRepl (or the execution of the privileged code I supply)???, or
the 3rd party site loads, but code executed by MozRepl doesn't see it load, or
the 3rd party site loads, and MozRepl isn't ready to take requests (despite other JavaScript running in the page, and port 4242 being bound by the Firefox process),
etc.
I thought about maybe doing something like this:
Modify the MozRepl source in some way to load privileged JavaScript from a predictable place in the filesystem at start-up (or interact with Firefox command-line arguments) and execute it in the context of the 3rd party website.
... or even write another similar add-on which is more dedicated to the task.
Any simpler ideas?
Update:
After a lot of trial-and-error, answered my own question (below).
I found the easiest way was to write a purpose-built Firefox extension!
Step 1. I didn't want to do a bunch of unnecessary XUL/addon related stuff that wasn't necessary; A "Bootstrapped" (or re-startless) extension needs only an install.rdf file to identify the addon, and a bootstrap.js file to implement the bootstrap interface.
Bootstrapped Extension: https://developer.mozilla.org/en-US/docs/Extensions/Bootstrapped_extensions
Good example: http://blog.fpmurphy.com/2011/02/firefox-4-restartless-add-ons.html
The bootstrap interface can be implemented very simply:
const path = '/PATH/TO/EXTERNAL/CODE.js';
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
var loaderSvc = Cc["#mozilla.org/moz/jssubscript-loader;1"];
.getService(Ci.mozIJSSubScriptLoader);
function install() {}
function uninstall() {}
function shutdown(data, reason) {}
function startup(data, reason) { loaderSvc.loadSubScript("file://"+path); }
You compile the extension by putting install.rdf and bootstrap.js into the top-level of a new zip file, and rename the zip file extension to .xpi.
Step 2. To have a repeatable environment for production & testing, I found the easiest way was to launch Firefox with a profile dedicated to the automation task:
Launch the Firefox profile manager: firefox -ProfileManager
Create a new profile, specifying the location for easy re-use (I called mine testing-profile) and then exit the profile manager.
Remove the new profile from profiles.ini in your user's mozilla config (so that it won't interfere with normal browsing).
Launch Firefox with that profile: firefox -profile /path/to/testing-profile
Install the extension from the file-system (rather than addons.mozilla.org).
Do anything else needed to prepare the profile. (e.g: I needed to add 3rd party certificates and allow pop-up windows for the relevant domain.)
Leave a single about:blank tab open, then exit Firefox.
Snapshot the profile: tar cvf testing-profile-snapshot.tar /path/to/testing-profile
From that point onward, every time I run the automation, I unpack testing-profile-snapshot.tar over the existing testing-profile folder and run firefox -profile /path/to/testing-profile about:blank to use the "pristine" profile.
Step 3. So now when I launch Firefox with the testing-profile it will "include" the external code at /PATH/TO/EXTERNAL/CODE.js on each start-up.
NOTE: I found that I had to move the /PATH/TO/EXTERNAL/ folder elsewhere during step 2 above, as the external JavaScript code would be cached (!!! - undesirable during development) inside the profile (i.e: changes to the external code wouldn't be seen on next launch).
The external code is privileged and can use any of the Mozilla platform APIs. There is however an issue of timing. The moment-in-time at which the external code is included (and hence executed) is one at which no Chrome window objects (and so no DOMWindow objects) yet exist.
So then we need to wait around until there's a useful DOMWindow object:
// useful services.
Cu.import("resource://gre/modules/Services.jsm");
var loader = Cc["#mozilla.org/moz/jssubscript-loader;1"]
.getService(Ci.mozIJSSubScriptLoader);
var wmSvc = Cc["#mozilla.org/appshell/window-mediator;1"]
.getService(Ci.nsIWindowMediator);
var logSvc = Cc["#mozilla.org/consoleservice;1"]
.getService(Ci.nsIConsoleService);
// "user" code entry point.
function user_code() {
// your code here!
// window, gBrowser, etc work as per MozRepl!
}
// get the gBrowser, first (about:blank) domWindow,
// and set up common globals.
var done_startup = 0;
var windowListener;
function do_startup(win) {
if (done_startup) return;
done_startup = 1;
wm.removeListener(windowListener);
var browserEnum = wm.getEnumerator("navigator:browser");
var browserWin = browserEnum.getNext();
var tabbrowser = browserWin.gBrowser;
var currentBrowser = tabbrowser.getBrowserAtIndex(0);
var domWindow = currentBrowser.contentWindow;
window = domWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem)
.rootTreeItem.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
gBrowser = window.gBrowser;
setTimeout = window.setTimeout;
setInterval = window.setInterval;
alert = function(message) {
Services.prompt.alert(null, "alert", message);
};
console = {
log: function(message) {
logSvc.logStringMessage(message);
}
};
// the first domWindow will finish loading a little later than gBrowser...
gBrowser.addEventListener('load', function() {
gBrowser.removeEventListener('load', arguments.callee, true);
user_code();
}, true);
}
// window listener implementation
windowListener = {
onWindowTitleChange: function(aWindow, aTitle) {},
onCloseWindow: function(aWindow) {},
onOpenWindow: function(aWindow) {
var win = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow);
win.addEventListener("load", function(aEvent) {
win.removeEventListener("load", arguments.callee, false);
if (aEvent.originalTarget.nodeName != "#document") return;
do_startup();
}
};
// CODE ENTRY POINT!
wm.addListener(windowListener);
Step 4. All of that code executes in the "global" scope. If you later need to load other JavaScript files (e.g: jQuery), call loadSubscript explicitly within the null (global!) scope
function some_user_code() {
loader.loadSubScript.call(null,"file:///PATH/TO/SOME/CODE.js");
loader.loadSubScript.call(null,"http://HOST/PATH/TO/jquery.js");
$ = jQuery = window.$;
}
Now we can use jQuery on any DOMWindow by passing <DOMWindow>.document as the second parameter to the selector call!
I am trying to browse a website, however, it only works under Windows and Mac because they use the navigator.platform from JavaScript to find out the architecture I am running on. Of course, they also use the browser's user agent, but that was easy to spoof.
Here is the .js in question: http://pastebin.com/f56fd608d. The code responsible for browser detection is at the top. Is there any way of changing the .js file before the site runs, or something similar, so I can eliminate the check?
Using the JavaScript console yields:
>navigator.platform
Linux i686
Evidently I changed the browser's user agent, but navigator.platform does not seem to take it's value from the user agent.
Maybe someone knows how to change the value returned by navigator.platform, because I hate running Windows under VirtualBox to use this site.
EDIT:
This could be of interest because Linux users might be artificially denied access to websites, and can do nothing about it.
var fakePlatformGetter = function () {
return "your fake platform";
};
if (Object.defineProperty) {
Object.defineProperty(navigator, "platform", {
get: fakePlatformGetter
});
Object.defineProperty(Navigator.prototype, "platform", {
get: fakePlatformGetter
});
} else if (Object.prototype.__defineGetter__) {
navigator.__defineGetter__("platform", fakePlatformGetter);
Navigator.prototype.__defineGetter__("platform", fakePlatformGetter);
}
Since you can't directly set navigator.platform, you will have to be sneaky - create an object that behaves like navigator, replace its platform, then set navigator to it.
var fake_navigator = {};
for (var i in navigator) {
fake_navigator[i] = navigator[i];
}
fake_navigator.platform = 'MyOS';
navigator = fake_navigator;
If you execute this code before the document loads (using GreaseMonkey, an addon or a Chrome extension), then the page will see navigator.platform as "MyOS".
Note: tested only in Chrome.
Provided that the browser you're using supports Object.defineProperty() (it likely does), a more modern way of achieving the same goal is as follows:
Object.defineProperty(navigator, 'platform', {
value: 'my custom value',
configurable: true // necessary to change value more than once
});
This allows you to set it to any custom value you want, and it also allows you to change it as many times as you want without needing to reload the page.
For a Mozilla-based browser, GreaseSpot / Code Snippets # Hijacking browser properties demonstrates how it may be done. This code may be injected from a GreaseMonkey script.
about:config - > general.platform.override
Attempting to change this property (at any time) in Firefox yields:
Error: setting a property that has only a getter
Source File: index.html
Line: 1
So I think you will have a hard time.
I'd try to contact the author about obtaining a fix.