refresh page when dom is loaded [duplicate] - greasemonkey

This question already has answers here:
How to reload a page using JavaScript
(12 answers)
Closed 3 years ago.
I am trying to figure out how to refresh the page after the dom loads. If the dom loads and there is not a specific text on the page, it refreshes and keeps looping till that text is found.
// ==UserScript==
// #name My Fancy New Userscript
// #namespace http://use.i.E.your.homepage/
// #version 0.1
// #description enter something useful
// #match http://stackoverflow.com/questions/8192126/clicking-a-button-on-a-page-using-a-greasemonkey-userscript-in-chrome/8192413#8192413
// #copyright 2012+, You
// #require http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js
// ==/UserScript==
function available() {
var nodeList = document.querySelectorAll('.table');
if (nodeList[0].innerHTML.indexOf( "Not available." ) != -1) {
Location.reload();
else {
alert("Hello! I am an alert box!!");
}
}
}
$(function() {
available();
});

To reload the page with javascript:
Location.reload();
You'll need some way of checking for your bit of text as well.
Without seeing your DOM structure I can't give an accurate answer to that aspect.

Location must be lower case.
location.reload();
By the way, passing a true as a param means that the page will load from the server instead than loading from caché.

Related

Puppeteer: How to get new page object after form submission in evaluate?

In Puppeteer if an evaluate clicks a link or submits a form so that a new page is loaded, the page object is no longer actual and we get:
UnhandledPromiseRejectionWarning: Error: Execution context was destroyed, most likely because of a navigation.
Sometimes we just cannot predict what the address of that new page will be because the code in the page is too complex. So we cannot just grab the address in the DOM and load a new page in nodejs. It might even be a POST request.
How can we get the new page object that was created? Where is it?
Also, if I understand correctly the new page object might not be created when we leave the evaluate, the page might finish loading after returning from evaluate. So maybe the right question is, How do we take control of all current pages at any time? Is there a list/array of them somewhere?
If we suspect that the page might be gone we can use browser.pages() and pick the one we believe is the new page.
If we deal with many pages it will require some custom matching, but if we know there was only one page we can just grab the last valid page in the list.
So I wrote this to deal with this issue:
async function doStuff(browser, page){
await page.evaluate(() => { ... });
// At this point we suspect that the evaluate might have navigated outside and that the page object is no longer usable
page = await getPage(browser, page);
// Now we know that if there is a valid page somewhere we have it in page
var htmlSize = ( await page.content() ).length; // we can use page safely
}
async function getPage(browser, page){
// Return current page, or last one if previous one was destroyed by navigation
try {
var domSize = ( await page.content() ).length;
if(domSize > 0) return page;
}catch(e){}
const pagesList = await browser.pages();
const pagesListLen = pagesList.length;
for( var i=pagesList.length ; i>=0 ; i-- ){
try{
var domSize = ( await pagesList[i].content() ).length;
if(domSize > 0) return pagesList[i];
}catch(e){}
}
return page; // return invalid page object anyway
}
NOTE 1: if what we do in evaluate takes a while to load a new page we might want to put a loop with a sleep and call getPage every time until page has what we want.
NOTE 2: I personally put domSize > 500 instead of domSize > 0 because it prevents accidentally returning valid but empty pages. You have to adjust to what makes sense for you.

Aurelia popup when refreshing the page not working

As we know, we can put a pop up asking if we are sure about refreshing the page when we click the refresh button on the browser. Usually it is done by adding an event listener on onbeforeunload.
However, in my Aurelia application, I try to do that but it's not working.
let's say this is my app.js ( root ModelView )
export class App {
this.refreshClicked = () =>{ return "Are you sure you want to exit?"; };
attached(){
window.addEventListener("onbeforeunload", this.refreshClicked);
}
But it is not working, however, if we replace the return statement to console.log("clicked") I can see that the listener works without any problem.
Any help?
First of all, if you are adding event handler through window.addEventListener, you don't use on prefix in that case. So it's either:
attached() {
window.addEventListener('beforeunload', this.refreshClicked);
}
or an older, not recommended, syntax:
attached() {
window.onbeforeunload(this.refreshClicked);
}
Second, you'll need to set the returnValue property on Event object and also return the same string value to support more browsers. To learn more about this event (and various browser quirks), check out its MDN page.
Your refreshClicked should look like this:
this.refreshClicked = e => {
const confirmation = 'Are you sure you want to exit?';
e.returnValue = confirmation;
return confirmation;
};

How to replace, remove or intercept jQuery's ready event from a Greasemonkey script? [duplicate]

This question already has answers here:
Changing Javascript on an HTML page out of my control [duplicate]
(2 answers)
Closed 4 years ago.
There's a website I use written in some mighty fine javascript. Hardly any globals, closures everywhere and it uses strict mode. This is making it really hard to inject my own functionality into the website.
The website client objects are initialised in a jQuery.ready() call:
$(window).ready(function () {
var a, b, c, d;
// Setup global data [...]
// Setup configuration [...]
a = GlobalFoo.ConstructorA();
b = GlobalFoo.ConstructorB(a);
// Really wish I could put stuff here
c = GlobalFoo.ConstructorC(a, b);
d = GlobalFoo.ConstructorD(b, c);
// etc.
});
How can I, for example, replace b.someMethod() with my own code before the other constructors are called?
Can I stop the ready event from happening or replace it with my own code? Since it's quite small I can just duplicate a modified version in my code.
After a bit more searching I found this wonderful page by dindog. There is also this page on the GreaseSpot wiki describing #run-at.
#run-at allows your userscript to run before all other code. The beforescriptexecute event allows you to check each script before it executes. You can then skip or modify it.
My final solution is:
// ==UserScript==
// #name ...
// #description ...
// #namespace ...
// #include ...
// #version 1
// #run-at document-start
// #grant none
// ==/UserScript==
(function (w) {
// Remove the current jQuery ready code
function pre_script_execute_handler (e) {
var target = e.target;
if (target.innerHTML.indexOf("$(window).ready(") != -1) {
console.log('Removed ready');
e.preventDefault();
e.stopPropagation();
addReady();
}
}
w.addEventListener('beforescriptexecute', pre_script_execute_handler);
// Add new jQuery ready code
function addReady () {
console.log('Adding new ready');
w.$(window).ready(function () {
console.log('Our ready called');
});
}
}) (unsafeWindow);

requirejs load script progress

Risking of asking a stupid question I will give it a try though.
Is it possible to display a progress indicator while RequireJs is loading dependencies?
For example:
require(['jquery'], function($) {
// Well, jQuery loaded in quite some time due to a low-speed connection
//
// Or maybe I wanted to show an overlay to prevent user of clicking on UI widgets until the load is complete
});
I don't want to start modifying the RequireJS source if there's some plugin out there which didn't show up in my Google searches.
Thanks for all your help.
It is possible to display a spinner or progress indicator, but not the bar itself. I could get status of requirejs (currently loading or idle), but not the % of loaded/needed to be loaded modules, because their dependencies are parsed upon every module load, but not at the beginning.
But, anyway, page with, at least, a simple spinner, is much better, than just blank page, while user waits.
No changes to requirejs needed! So..
Assume we have file require.conf.js with
require.config({...})
require(["app"], function () {
// main entry point to your hugde app's code
});
and it is loaded by html using
<script data-main="require.conf" type="text/javascript" src="bower_components/requirejs/require.js"></script>
This is standard requirejs scenario. Let's add the indicator to the
<div id="requirejs-loading-panel">
<div id="requirejs-loading-status"></div>
<div id="requirejs-loading-module-name"></div>
</div>
Ok, let's catch up requirejs's function called require.onResourceLoad and do all the magic needed. It will be called by requirejs upon every module load, passing the requirejs's context with dep tree and all other staff. We will use context to find out, whether requirejs is loading something or not. I did it in scheduled timer call, because onResourceLoad() is called only while loading, not when it is done loading. This code needs to be added to require.js.conf:
require.onResourceLoad = function (context, map, depMaps) {
var loadingStatusEl = document.getElementById('requirejs-loading-status'),
loadingModuleNameEl = document.getElementById('requirejs-loading-module-name');
var panel = document.getElementById('requirejs-loading-panel');
if (loadingStatusEl && loadingModuleNameEl) {
if (!context) { // we well call onResourceLoad(false) by ourselves when requirejs is not loading anything => hide the indicator and exit
panel.style.display = "none";
return;
}
panel.style.display = ""; // show indicator when any module is loaded and shedule requirejs status (loading/idle) check
clearTimeout(panel.ttimer);
panel.ttimer = setTimeout(function () {
var context = require.s.contexts._;
var inited = true;
for (name in context.registry) {
var m = context.registry[name];
if (m.inited !== true) {
inited = false;
break;
}
} // here the "inited" variable will be true, if requirejs is "idle", false if "loading"
if (inited) {
require.onResourceLoad(false); // will fire if module loads in 400ms. TODO: reset this timer for slow module loading
}
}, 400)
if (map && map.name) { // we will add one dot ('.') and a currently loaded module name to the indicator
loadingStatusEl.innerHTML = loadingStatusEl.innerHTML += '.'; //add one more dot character
loadingModuleNameEl.innerHTML = map.name + (map.url ? ' at ' + map.url : '');
}
} else {
}
};
One problem is: we cannot somehow figure out how much modules are needed to load, so we can't compute the actual % of loading progress. But, at least, we can find out, whether we're loading something or not (and event get currently loading module name) and show it to a nervous user
Since v. 2.1.19 RequireJS has onNodeCreated config property. If you assign a function to it, that function will be called each time a <script> element is appended to a document to load a module.
The function will be provided with node, config, moduleName, and url arguments. By attaching event listeners to the node, you can detect when the script has been loaded or failed to be loaded.
Now you can detect when loading process starts and stops and can use that information to notify users:
require.config({
/* ... paths, shims, etc. */
onNodeCreated: function(node, config, moduleName, url) {
console.log('module ' + moduleName + ' is about to be loaded');
node.addEventListener('load', function() {
console.log('module ' + moduleName + ' has been loaded');
});
node.addEventListener('error', function() {
console.log('module ' + moduleName + ' could not be loaded');
});
},
});
For IE < 9 you'd need additional code to attach event listeners.
Note: this only works for modules requested by RequireJS directly. Plugins (requirejs/text and such) each use their own loading mechanism and do not trigger onNodeCreated. Some trigger onXhr and onXhrComplete though, so you can handle them too:
require.config({
/* ... paths, shims, etc. */
config: {
text: {
onXhr: function(xhr, url) {
console.log('file ' + url + ' is about to be loaded');
},
onXhrComplete: function(xhr, url) {
console.log('file ' + url + ' has been loaded');
}
}
}
});
No, this isn't possible. RequrieJs loads the module by creating a new script tag in the DOM and listens to the load event. There are no update events in between start and end loading. So it's not a limitation of requireJs but the DOM.

How to pass a value from to a page in Chrome extension development?

I have a popup, call 'welcome.html', the thing I would like to do is when the user select a text, and click my plugin, it will use some of the page information, and print back to the welcome.html. For example, the web site title, and the text which the user selected and the url. But how can I pass value to that welcome.html? Thank you.
I do a lot of this in my extension as it mines a lot of data enabling the user to easily copy it to their clipboard.
Since you're looking for a lot less data it's even simpler. When your popup is being loaded you can call the following function to retrieve the information you require;
function getData(callback) {
chrome.tabs.getSelected(null, function (tab) {
var data = {
selection: '',
title: tab.title,
url: tab.url
};
/*
* We can't call content scripts on some pages and the process will get
* stuck if we try.
*/
if (tab.url.indexOf('chrome') === 0 ||
tab.url.indexOf('https://chrome.google.com/webstore') === 0) {
callback(data);
} else {
chrome.tabs.sendRequest(tab.id, {}, function (response) {
data.selection = response.selection;
callback(data);
});
}
});
}
Ensure you pass in a callback function which will be called once all the data has been extracted;
getData(function (data) {
console.log('Title: ' + data.title);
console.log('URL: ' + data.url);
console.log('Selected Text: ' + data.selection);
// Display the data instead
});
As you may have noticed the getData function sends a request to the selected tab. A content script will need to be injected in to the page in order for this to work so be sure you've configured your manifest correctly or injected it programmatically prior to calling getData or it won't work. The script that will need to be injected should resemble the following;
(function () {
chrome.extension.onRequest.addListener(function (request, sender,
sendResponse) {
sendResponse({
selection: window.getSelection().toString()
});
});
})();
This simply returns the currently selected text. One concern is that this data look-up could potentially cause a slight pause while the popup is rendered but you should test this yourself and experiment with it but there are solutions.
This should cover all you need to know so good luck and let me know if you need any further help as I'm aware this could be slightly overwhelming if you're new to Chrome extensions.

Resources