I have done something like this a long time ago where I captured the alerts and prevented the default browser based alert box from popping up and replaced it with a modal of one kind or another. However its been so long since I have done that, and I can't find any reference from old code of mine how I did it, nor can I find anything relevant via google currently. So.. I am hoping someone here can aid me in this and help me out. I havent tried anything yet so save yourself the question of what did I try. Other than spending the last hour or so googling different phrases for any snipplet of code that resembles whats in my blurry memory I've come up empty handed. I know, this is kind of a poor quality question to, but at the same time I am sure others would appreciate knowing the answer as well.
All I want to do in my case is capture the event that would trigger the alert() box and pass the message that was in it to another variation of notification. Currently I am doing some work in appmobi with a couple others and I want to take alert() capture it then use
AppMobi.notification.alert(message,title,buttontext); as the default action for alert()
You can simply overwrite the alert method:
window.alert = function(msg) {
// whatever you want to do with 'msg' here
};
Note that this won't have the blocking behavior of a regular alert
window.alert = function(message,title,buttontext) {
AppMobi.notification.alert(message,title,buttontext);
};
As others have pointed out, it can be overridden - just remember that AppMobi.notification.alert expects three arguments. I would not be surprised if it has fallback defaults, but better safe than sorry:
//alert is a native code function that we may need elsewhere
window.legacyAlert = window.alert;
window.alert = function(_msg) {
AppMobi.notification.alert(_msg, 'Alert', 'OK');//or whatever
};
This overrides the method globally. Alternatively you may require for it to be overridden only in some parts of your code using closures:
alert('this is a vanilla js alert');
(function(alert) {
alert('this alert has been overridden');
})(AppMobi.notification.alert);
alert('this is another vanilla js alert');
Fiddled
Related
I have an idea for a game where people can type in some simple instructions for their character like player.goLeft() or player.attackInFront() and for that I have people type their code into a text box and then I parse it into eval(). This works well but it also allows people to change their own character object by typing things like player.health = Infinity; or something similar. I have a list of functions I want to allow people to use, but I am unsure how to restrict it to only use them.
I understand that the whole point of not letting people use eval is to avoid accidental cross-site scripting but I am unsure on how else to do this. If you have a suggestion please leave a comment about that.
I asked some people around on what to do and most suggested somehow changing scope(which is something I was not able to figure out) or to add some odd parameter to each function in my code that would be required to be a specific string to execute any function, but that seems hacky and since I am making the game in browser with p5js it would be easy to just inspect element and see what the password is.
basically every character has variable called "instruction" which is just a string of javascript. Then every frame of the game I execute it by doing eval(playerList[i].instruction);
tl;dr, how can I only allow specific function to be executed and not allow any others?
EDIT: I forgot to mention that I also am planning to provide player with information so that people can made code that would adapt to the situation. For example there will be parameter called vision that has vision.front and vision.left etc. These variables would just say if there is an enemy, wall, flower, etc around them in a grid. Some people suggested that I just replace some functions with key words but then it compromises the idea of using if statements and making it act differently.
EDIT 2: Sorry for lack of code in this post, but because of the way I am making it, half of the logic is written on server side and half of it works on client side. It will be a little large and to be completely honest I am not sure how readable my code is, still so far I am getting great help and I am very thankful for it. Thank you to everybody who is answering
Do NOT use eval() to execute arbitrary user input as code! There's no way to allow your code to run a function but prevent eval() from doing the same.
Instead, what you should do is make a map of commands the player can use, mapping them to functions. That way, you run the function based on the map lookup, but if it's not in the map, it can't be run. You can even allow arguments by splitting the string at spaces and spreading the array over the function parameters. Something like this:
const instructions = {
goLeft: player.goLeft.bind(player),
goRight: player.goRight.bind(player),
attackInFront: player.attackInFront.bind(player)
};
function processInstruction(instruction_string) {
const pieces = instruction_string.split(' ');
const command = pieces[0];
const args = pieces.slice(1);
if (instructions[command]) {
instructions[command](...args);
} else {
// Notify the user their command is not recognized.
}
};
With that, the player can enter things like goLeft 5 6 and it will call player.goLeft(5,6), but if they try to enter otherFunction 20 40 it will just say it's unrecognized, since otherFunction isn't in the map.
This issue sounds similar to the SQL Injection problem. I suggest you use a similar solution. Create an abstraction layer between the users input and your execution, similar to using parameters with stored procedures.
Let the users type keywords such as 'ATTACK FRONT', then pass that input to a function which parses the string, looks for keywords, then passes back 'player.attackInFront()' to be evaluated.
With this approach you simplify the syntax for the users, and limit the possible actions to those you allow.
I hope this isn't too vague. Good luck!
From your edit, it sounds like you're looking for an object-oriented approach to players. I'm not sure of your existing implementation needs, but it would look like this.
function Player() {
this.vision = {
left: '',
// and so on
}
}
Player.prototype.updateVisibilities = function() {
// to modify the values of this.visibility for each player
}
Player.prototype.moveLeft = function() {
}
Don't give the user an arbitrary interface (such as an input textfield that uses eval) to modify their attributes. Make a UI layer to control this logic. Things like buttons, inputs which explicitly run functions/methods that operate on the player. It shouldn't be up to the player as to what attributes they should have.
This may be a quite naive question but I really need some help.
Prior to writing this post, I was programming on JSBin. Turns out without me realizing, I ran a setInterval loop prompting for userInput and it kept on looping, making me unable to click anywhere to change the code to fix the loop. It kept on repeating and repeating. It got to the point where I had to refresh and lose all my hard-written-code (I was not logged in, so my code was not saved)! I want to avoid that next time.
So, my question is how do I stop any such kind of setInterval Loops, so that I am able to access my code and change it and re-run it. Below is a code that demonstrates my issue, if you try running it on JSBin.com (obviously, it is not the code I wrote before). As you can see, I can not click on my code to change it (or save it) in any way, which means I lose all my code!
This may seem like a useless question, but I really want to know ways to fix it and perhaps fixing it from the developer tools will help me be familiar with the overwhelming set of tools it has :P. So please help me if you know a solution.
Thank you for taking your time to help me! I appreciate it.
setInterval(demo,1);
function demo()
{
var name = prompt("Enter your name: ");
}
Another option is to search the developer tools "Elements" panel for the iframe (this should be doable even if the main document is unresponsive due to prompt's blocking) - then, just right click the iframe element and remove it, no need to type any Javascript. (or, if you want you can select the iframe with querySelector and remove it, eg document.querySelector('iframe').remove())
That's kind of a hack and should only be used in cases like the one exposed in OP but,
About all implementations use integers as timerid that just get incremented at every call.
So what you can do, is to clear all timeouts that were created on the page.
To do so you need to first get to which timerid we are, then call cleatTimeout or clearInterval (they do the same) in a loop until you reach the last call:
function stopAllTimers() {
const timerid = setTimeout(_=>{}); // first grab the current id
let i=0;
while(i < timerid) {
clearTimeout(i); // clear all
i++;
}
};
btn.onclick = stopAllTimers;
// some stoopid orphan intervals
setInterval(()=>console.log('5000'), 5000);
setInterval(()=>console.log('1000'), 1000);
setInterval(()=>console.log('3000'), 3000);
const recursive = () => {
console.log('recursive timeout');
setTimeout(recursive, 5000);
};
recursive();
<button id="btn">stop all timeouts</button>
Assuming the dev tools are closed, hit esc and f12 nearly simultaneously. This should open the dev tools. If it doesn't keep trying until it does.
Once they are open, hit esc and f8. Again, retry til it halts javascript execution at some arbitrary point in the code.
In the "sources" tab locate the generated script for what you wrote (offhand I don't know how it would look like from within JSBin) and literally delete the var name = prompt("Enter your name: "); line. Hitting f8 again will continue execution as if the "new" code is running. This should free you up to copy/paste your code from the site itself before you refresh the page
Take the following html:
<div id="somediv" style="display:none;"></div>
<script>
document.getElementById("somediv").style.display = 'none';
</script>
somediv is already hidden, some javascript runs, effectively doing nothing. I need code that detects when style.display has been used in javascript, regardless of if style was changed or not.
I've tried MutationObserver:
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutationRecord) {
alert(mutationRecord.target.id);
});
});
observer.observe(document.getElementById("somediv"), { attributes : true, attributeFilter : ['style'] });
The above only triggers if there was a style change. I need it to trigger regardless if there was a style change or not.
So I did come up with an answer. The way it works, is you grab every script tag, replace .style.display with your own function, and finally replace the DOM (which is the real trick):
//loop through <script> tags
$('script').each(function(){
var scripthtml = $(this).html();
if (scripthtml.indexOf('style.display') != -1){
scripthtml = scripthtml.replace(/.style.display = 'none'/g, ".customdisplay('none')");
scripthtml = scripthtml.replace(/.style.display = "none"/g, '.customdisplay("none")');
scripthtml = scripthtml.replace(/.style.display ='none'/g, ".customdisplay('none')");
scripthtml = scripthtml.replace(/.style.display ="none"/g, '.customdisplay("none")');
scripthtml = scripthtml.replace(/.style.display='none'/g, ".customdisplay('none')");
scripthtml = scripthtml.replace(/.style.display="none"/g, '.customdisplay("none")');
$(this).replaceWith('<script>' + scripthtml + '</script>');
}
});
Now here is my .style.display replacement function:
HTMLElement.prototype.customdisplay = function(showhide){
//insert whatever code you want to execute
this.style.display = showhide;
alert('Success! .style.display has been detected!');
};
.replaceWith is what actually changes the DOM. The only thing this script doesn't do, is it isn't able to look through included javascript files. Thank you all for your comments <3.
UPDATE:
When using replaceWith to add the script tag, ipad/iphone/ipod will execute the script tag a second time. to prevent this double execution, you need to do this:
$(this).replaceWith('<script>if (1==0){' + scripthtml + '}</script>');
Your functions will be valid, but anything outside of the function will not be executed.
I don't think you fully realise what you are asking for, but here is a short description of closest options I am aware of:
https://blog.sessionstack.com/how-javascript-works-tracking-changes-in-the-dom-using-mutationobserver-86adc7446401
Basically, MutationObserver is the major improvement over past here that is closest to what you want and supported in modern browsers. But the whole point of all this is it listens to changes.
You are basically asking to detect even non-changes. I don't see you getting out of this problem other than:
Writing a wrapper for the ways you use to change this in code and then instead of calling the change call the wrapper. Simple, easy, requires refactoring all the calls in code.
Overwriting the actual functions that make a change. This saves you the refactor but you are playing with fire here. Rewriting a well-known function on a global level means a PERMANENT source of problems to you and all developers who work on the project.
Polling - in short calling over and over on some element to check properties. Not only it detects changes with a lag of 0 to the polling interval it also uses resources and if you want to monitor everything you will have to write a recursion that descends through the current DOM from the top to each node and check it. You are gonna kill the performance with this. How hard I can't tell but I suspect either polling interval will be long thus increasing the detection lag or your performance will dive down like a gray falcon.
I have 1 big question for you:
What led you to the state where you need this?
You basically want the ability for a program to detect when it is using a specific part of itself (be that as it is, a core part, one implemented by the browser).
This sounds similar to request: hey whenever I change or not change a value in any variable in my code I should be able to react to it.
I am not trying to sound like Naggin Nancy here but instead encourage you to question train of thought that led to this being something you need and figure out whether you want to sink further time into this, because I don't think you are getting that what you desire easily and I suspect it came to be due to poor design decisions in the past.
i try to figure out a greasemonkey script that replaces every onmousedown on a site with an ondblclick. And i want it to constantly update, like every 1,5 Seconds, because the page refreshes using AJAX.
This is the script i came up with, but it doesn't seem to be working.
window.setInterval(document.body.innerHTML= document.body.innerHTML.replace('onmousedown','ondblclick');,1500);
The page it should work with is internal use only. But a good example would be the google search, where onmousedown is used for the links of the results to swap out the URL before you click it.
I also tried it without the semicolon after the document.body.innerHTML.replace.
I'm really new to JavaScript, but since i'm the only one in the company who can code, this one is stuck with me.
Any help would be appreciated.
Also, a small "side question"
Do i have to use #exclude, or is it enough to only use #include internal.companysite.tld* so it will only work on this site ?
A direct answer: you need to supply a function to setInterval - and it's best to set a variable so that you can later cancel it with clearInterval() if necessary.
function myF(){document.body....;}
var myIntv = setInterval(myF, 1500);
You could also do it using an anonymous function in one line as you're trying to do... do that this way:
var myIntv = setInterval(function(){document.body....;}, 1500);
I wouldn't suggest this as the solution to your problem. What it sounds like you want to do is manipulate the active DOM - not really change the UI. You likely need something like this:
var objs = document.getElementsBy__(); // ById/ByName/etc - depends on which ones you want
for (var i in objs){objs[i].ondblclick = objs[i].onmousedown;objs[i].onmousedown = undefined;} // just an example - but this should convey the basic idea
Even better, if you can use jQuery, then you'll be able to select the proper nodes more easily and manipulate the event handlers in a more manageable way:
$(".class.for.example").each(function(){this.ondblclick = this.onmousedown;this.onmousedown = undefined;}); // just an example - there are multiple ways to set and clear these
Hi this may be a silly question, but I can't find the answer anywhere.
I'm writing a chrome extension, all I need is to read in the html of the current page so I can extract some data from it.
here's what I have so far:
<script>
window.addEventListener("load", windowLoaded, false);
function windowLoaded() {
alert(document.innerHTML)
});
}
</script>
Can anybody tell me what I'm doing wrong?
thanks,
function windowLoaded() {
alert('<html>' + document.documentElement.innerHTML + '</html>');
}
addEventListener("load", windowLoaded, false);
Notice how windowLoaded is created before it is used, not after, which won't work.
Also notice how I am getting the innerHTML of document.documentElement, which is the html tag, then adding the html source tags around it.
I'm writing a chrome extension, all I need is to read in the html of
the current page so I can extract some data from it.
I think an important answer here is not the correct code to use to alert the innerHTML but how to get the data you need from what's already been rendered.
As pimvdb pointed out, your code isn't working because of a typo and needing document.documentElement.innerHTML, something you can diagnose in the Chrome console (Ctrl+Shift+I). But that's secondary to why you'd want the inner HTML in the first place. Whether you're looking for a certain node, specific text, how many <div> elements exist, the value of an ID, etc., I'd heavily recommend the use of a library like jQuery (vanilla JS works, but it can be verbose and unwieldy). Instead of reading in all the HTML and parsing it with string functions or regex, you probably want to take advantage of all the DOM parsing functionality already available to you.
In other words, something like this:
$("#some_id").val(); // jQuery
document.getElementById("some_id").value; // vanilla JS
is probably way safer, easier and more readable than something eminently breakable like this (probably a bit off here, but just to make a point):
innerHTML.match(/<[^>]+id="some_id"[^>]+value="(.*?)"[^>]*?>/i)[1];
Use document.documentElement.outerHTML. (Note that this is not supported in Firefox; irrelevant in your case.) However, this is still not perfect as it doesn't return nodes outside the root element (!doctype and possibly some comments or processing instructions). The document.innerHTML property is, AFAIK, specified in HTML5 specification, but currently not supported in any browser.
Just FYI, navigating to view-source:www.example.com also displays the entire markup (Chrome & Firefox). But I don't know whether you can work with it somehow.
window.addEventListener("load", windowLoaded, false);
function windowLoaded() {
alert(document.documentElement.innerHTML);
}
You had a } with no purpose, and the }); should just be }. These are syntax errors.
Also, it's document.documentElement.innerHTML, since it's not a property of document.