Firefox: run functions from Javascript through an extension - firefox

At the present I'm pasting a Javascript into the console of FF and I'm calling the functions from the console:
function fill (i){
if(i==1){
SINGLE_START();
}
else if(i==2){
DUAL_START();
}
else if(i==3){
INTEGRATED_START();
}
else{
alert("=======================\n Tool Filler\n=======================\n\n1 or 2");
}
}
It is used to scrape the content of the website and e.g. create a file or generate an email from certain parts of the website, e.g.:
function SINGLE_START(){
//Focus:
let d = $(document).activeElement.contentDocument.activeElement.contentDocument.activeElement.contentDocument;
etc.
I thougt, there could be a way to use it through an extension and so I installed Tampermonkey and saved the script as userscript within the extension. But than I have a problem that I'm not able to call the desired function from the script as I need it, not just start the script as the website loads.
Does anyone has an idea how to call the functions one by one from within Tampermonkey (or Greasemonkey), or any other extension?
Thanks in advance!

This is because Tampermonkey scripts run in isolated context. There are two kinds:
1. No special privilegies
If you're not using any special GM functions that are unlocked by #grant GM_doThisAndThat and instead you use #grant none, then what internally happens is something like this:
function TheScript() {
// Here is your script that you added to tampermonkey
}
TheScript();
This if you have a function there, it is only available in the script. You need to explicitly expose it to window context:
function fill (i){
... code here ...
}
window.myFill = fill;
Then in console you write myFill(42) and it will execute.
I would recommend that you avoid assigning fill to window since it's a name that could likely conflict with something, but that's up to you.
2. Special privilegies
If you're using some of the GM features, you need to add #grant unsafeWindow and then assign to unsafeWindow variable. Be careful what you expose like this, you don't want to allow the website to access any of the GM_function features as they could access your private data on other websites and your computer!

Related

Cypress: How to capture text from a selector on one page to use as text on another page

New cypress user here, I am aware that cypress does not handle variables like how testcafe and others do due to the asyn nature of it. Using the example given and what I could find I have this as an example:
cy.get('selector').invoke('text').as('text_needed')
cy.get('#text_needed')
const txtneeded = this.text_needed
cy.log(txtneeded)
This looks at a given selector, takes what it finds and uses it as text and set it as a variable usable at any time in the test and outputs it to the log. The plan is to use that text in a search filter in another page to find the item it references.
The problem is that it fails with Cannot read properties of undefined (reading 'text_needed')
Is this because the content of the selector is not assigned to text properly, the outer html is <a data-v-78d50a00="" data-v-3d3629a7="" href="#">PO90944</a> The PO90944 is what I want to capture.
Your help would be appreciated!
You cannot save an alias and access it via this.* in the same execution context (callback) because it's a synchronous operation and your alias is not yet resolved at this time.
This is a correct way to go:
cy.get('selector').invoke('text').as('text_needed')
cy.get('#text_needed').then(txtneeded => {
cy.log(txtneeded)
})
First, make sure to define it as traditional function, not as an arrow function as this context doesn't work as you'd expect there, more info here.
Next, typically in a single test you should use .then() callback to perform additional actions on elements, and use aliases when you need to share context between hooks or different tests, so please consider the following:
// using aliases together with this within the single test won't work
cy.get(<selector>).invoke('text').as('text_needed')
cy.get('#text_needed').should('contain', 'PO90944') // works fine
cy.log(this.text_needed) // undefined
// this will work as expected
cy.get(<selector>).invoke('text').then(($el) => {
cy.wrap($el).should('contain', 'PO90944'); // works fine
cy.log($el) // works fine
});
Setting alias in beforeEach hook for example, would let you access this.text_needed in your tests without problems.
Everything nicely explained here.
Edit based on comments:
it('Some test', function() {
cy.visit('www.example.com');
cy.get('h1').invoke('text').as('someVar');
});
it('Some other test', function() {
cy.visit('www.example.com');
cy.log('I expect "Example Domain" here: ' + this.someVar);
});
And here's the output from cypress runner:

Cypress command vs JS function

The Cypress documentation suggests that commands are the right way to reuse fragments of code, e.g.
Cypress.Commands.add("logout", () => {
cy.get("[data-cy=profile-picture]").click();
cy.contains("Logout").click();
});
cy.logout();
For simple cases like this, why would I use a command over a plain JS function (and all the nice IDE assistance that comes with it). What are the drawbacks of rewriting the above snippet as
export function logout(){
cy.get("[data-cy=profile-picture]").click();
cy.contains("Logout").click();
}
// and now somewhere in a test
logout();
Based on my experience with Cypress (one year project and several hundred test cases), I can say that a plan JS function is great for grouping cy commands.
From my point of view, a custom cy command may be really useful only if it is incorporated into the chain processing (utilizes the subject parameter or returns a Chainable to be used further in the chain). Otherwise, a plain JS function is preferable due to it simplicity and full IDE support (unless you're using an additional plugin).
If you for any reason need to do something inside the cypress loop, you can always wrap you code by cy.then() in a plain JS function:
function myFunction() {
cy.then(() => {
console.log(("I'm inside the Cypress event loop"))
})
}
Commands are for behavior that is needed across all tests. For example, cy.setup or cy.login. Otherwise, use functions.
See official docs: https://docs.cypress.io/api/cypress-api/custom-commands#1-Don-t-make-everything-a-custom-command

Getting the filename/path from MvvmCross Plugins.DownloadCache

I'm currently using MvvmCross DownloadCache -- and it's working alright -- especially nice when I just need to drop in an Image URL and it automagically downloads / caches the image and serves up a UIImage.
I was hoping to leverage the code for one other use case -- which is I'd like to grab source images from URL's and cache the files on the local file system, but what I really want for this other use case is the image path on the local file system instead of the UIImage itself.
What would help me most if I could get an example of how I might accomplish that. Is it possible to make that happen in a PCL, or does it need to go into the platform specific code?
Thanks -- that works, but just in case anyone else is following along, I wanted to document how I got the Mvx.Resolve<IMvxFileDownloadCache>() to work. In my setup.cs (in the touch project), I had:
protected override void InitializeLastChance ()
{
Cirrious.MvvmCross.Plugins.DownloadCache.PluginLoader.Instance.EnsureLoaded();
Cirrious.MvvmCross.Plugins.File.PluginLoader.Instance.EnsureLoaded();
Cirrious.MvvmCross.Plugins.Json.PluginLoader.Instance.EnsureLoaded();
...
}
But that wasn't enough, because nothing actually registers IMvxFileDownloadCache inside the DownloadCache plugin (which I was expecting, but it's just not the case).
So then I tried adding this line here:
Mvx.LazyConstructAndRegisterSingleton<IMvxFileDownloadCache, MvxFileDownloadCache>();
But that failed because MvxFileDownloadCache constructor takes a few arguments. So I ended up with this:
protected override void InitializeLastChance ()
{
...
var configuration = MvxDownloadCacheConfiguration.Default;
var fileDownloadCache = new MvxFileDownloadCache(
configuration.CacheName,
configuration.CacheFolderPath,
configuration.MaxFiles,
configuration.MaxFileAge);
Mvx.RegisterSingleton<IMvxFileDownloadCache>(fileDownloadCache);
...
}
And the resolve works okay now.
Question:
I do wonder what happens if two MvxFileDownloadCache objects that are configured in exactly the same way will cause issues by stepping on each other. I could avoid that question by changing the cache name on the one I'm constructing by hand, but I do want it to be a single cache (the assets will be the same).
If you look at the source for the plugin, you'll find https://github.com/MvvmCross/MvvmCross/blob/3.2/Plugins/Cirrious/DownloadCache/Cirrious.MvvmCross.Plugins.DownloadCache/IMvxFileDownloadCache.cs - that will give you a local file path for a cached file:
public interface IMvxFileDownloadCache
{
void RequestLocalFilePath(string httpSource, Action<string> success, Action<Exception> error);
}
You can get hold of a service implementing this interface using Mvx.Resolve<IMvxFileDownloadCache>()
To then convert that into a system-wide file path, try NativePath in https://github.com/MvvmCross/MvvmCross/blob/3.2/Plugins/Cirrious/File/Cirrious.MvvmCross.Plugins.File/IMvxFileStore.cs#L27

Prevent re-loading of javascript if functions already exist. Otherwise ensure synchronous loading

Using JQuery.load(), I change the content of my website's mainWindow to allow the user to switch between tabs. For each tab, there is one or multiple scipts that contain functions that are executed once the tab content is loaded.
Obviously when switching to the tab for the first time, the script has to be fetched from the server and interpreted, but this shouldn't happen if the user switches back to the tab later on. So, to put it short:
Load() html
make sure javascript functions exist, otherwise load script and interpret it.
call a a function on the javascript after the DOM is rebuilt.
Step one and two have to be complete before step 3 is performed.
At the moment, I am using nested callbacks to realize this:
function openFirstTab(){
$("#mainWindow").load("firstTab.php", function(){
if(typeof(onloadfFirstTab) != "function"){
jQuery.getScript("assets/js/FirstTab.js", function(){
onloadFirstTab();
});
}
else{
onloadFirstTab();
}
} );
}
but I feel that there should be a better way.
You can't write the code entirely synchronously since you can't load script synchronously after page load ( unless you do a synchronous XHR request and eval the results - not recommended ).
You've got a couple of choices. There are pre-existing dependency management libs like RequireJS which may fit the bill here, or if you just need to load a single file you can do something like this to clean up your code a bit rather than using if/else:
function loadDependencies() {
// For the sake of example, the script adds "superplugin" to the jQuery prototype
return $.getScript( "http://mysite.com/jquery.superplugin.js" );
}
function action() {
// If superplugin hasn't been loaded yet, then load it
$.when( jQuery.fn.superplugin || loadDependencies() ).done(function() {
// Your dependencies are loaded now
});
}
This makes use of jQuery Deferreds/Promises to make the code much nicer.
If you don't want to load the JS more than once and you are going to dynamically load it, then the only way to know whether it's already loaded is to test for some condition that indicates it has already been loaded. The choices I'm aware of are:
The simplest I know of is what you are already doing (check for the existence of a function that is defined in the javascript).
You could also use a property on each tab (using jQuery's .data() that you set to true after you load the script.
You could write the dynamically loaded code so that it knows how to avoid re-initializing itself if it has already been loaded. In that case, you just load it each time, but the successive times don't do anything. Hint, you can't have any statically defined globals and you have to test if it's already been loaded before it runs its own initialization code.
(Haven't tested it yet, so I am not sure if it works, especially since I didn't yet really understand scope in javascript:)
function require(scripts, callback){
var loadCount = 0;
function done(){
loadCount -=1;
if (loadCount==0){
callback();
}
}
for ( var script in scripts){
if (!script.exitsts()){
loadCount +=1;
jQuery.getScript(script.url, done);
}
}
}
This function takes an array of scripts that are required and makes sure all of them are interpreted before it calls the callback().
The "script" class:
function script(url, testFunc){
this.url =url;
this.testFunction = testFunc;
this.exists = function(){
if(typeof(testFunction)=="function"){
return true;
}
else{
return false;
}
}
}
Where the test-function is a function that is defined (only) in the concerned script.
PS:
To enable caching in JQuery and thus prevent the browser from doing a GET request every time getScript() is called, you can use one of the methods that are presented here.
Even though unnecessary GET - requests are avoided, the script is still getting interpreted every time getScript() is called. This might sometimes be the desired behavior. But in many cases, there is no need to re-interpret library functions. In these cases it makes sense to avoid calling getScript() if the required library functions are already available. (As it is done in this example with script.exists().

How to Program xulrunner application to display output file or command line?

My question is in response to this article
https://developer.mozilla.org/En/How_to_check_the_security_state_of_an_XMLHTTPRequest_over_SSL
I have downloaded and configured the xulrunner the only problem I'm getting to run javascript given in the link to display it output. Using xulrunner i want to know how can i produce an output as a headerless command-line program not gui.
var httpRequest = Components.classes["#mozilla.org/xmlextr/xmlhttprequest;1"].createInstance();
// Disable alert popups on SSL error
httpRequest.mozBackgroundRequest = true;
httpRequest.open("GET", "https://developer.mozilla.org/", true);
httpRequest.onreadystatechange = function (aEvt) {
if (httpRequest.readyState == 4) {
// Print security state of request
dumpSecurityInfo(httpRequest.channel);
}
};
httpRequest.send(null);
In the above code taken from the same link i want to see the output of function on my command screen or even a writing the information to file would do.
Do i have to change something in *.xul file extension.? I'm new to using xulrunner some help would be very helpful for me.
To print something to the console you use the dump() function. If your code runs in the context of a window you will need to change browser.dom.window.dump.enabled preference to true. XPCOM components can simply call dump() without changing this preference.

Resources