My extension not working properly [duplicate] - javascript

I have created a JavaScript variable and when I click on the button it should increment by 1, but its not happening.
Here's manifest.json.
{
"name":"Facebook",
"version":"1.0",
"description":"My Facebook Profile",
"manifest_version":2,
"browser_action":{
"default_icon":"google-plus-red-128.png",
"default_popup":"hello.html"
}
}
Here is the code for the html page
<!DOCTYPE html>
<html>
<head>
<script>
var a=0;
function count()
{
a++;
document.getElementById("demo").innerHTML=a;
return a;
}
</script>
</head>
<body>
<p id="demo">=a</p>
<button type="button" onclick="count()">Count</button>
</body>
</html>
I want the extension to show me the value of a and increment it by one each time I click on the extension or the button

Your code is not working because it violates the default Content Security Policy. I've created a screencast of one minute to show what's wrong:
First, I've shown how to debug the problem. Right-click on your popup button, and click on "Inspect popup". After doing that, you will see the following error message:
Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self' chrome-extension-resource:".
This explains that your code is not working, because it violates the default CSP: Inline JavaScript will not be executed. To solve the problem, you have to remove all inline JavaScript from your HTML file, and put it in a separate JS file.
The result is shown below:
hello.html (popup page)
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<p id="demo">=a</p>
<button type="button" id="do-count">Count</button>
<script src="popup.js"></script>
</body>
</html>
popup.js
var a=0;
function count() {
a++;
document.getElementById('demo').textContent = a;
}
document.getElementById('do-count').onclick = count;
Note that I've replaced innerHTML with textContent. Learn to use textContent instead of innerHTML when you intend to change the text. In this simple example it does not matter, but in more complex applications, it might become a security issue in the form of XSS.

Change your onclick:
onclick="count"
Or change your count function to something like this:
function count()
{
var demo = document.getElementById("demo");
return function() {
demo.innerHTML = ++a;
}
}
Here is a nice demo I put together:
Code (this assumes that you add id="the_button" to your button):
window.onload = function () {
var button = document.getElementById("the_button");
button.onclick = count();
function count() {
var a = 0;
var demo = document.getElementById("demo");
return function () {
demo.innerHTML = ++a;
}
}
}
Demo: http://jsfiddle.net/maniator/ck5Yz/

Related

How to get a list of Javascript functions in a specific <script> tag

Using the HTML below, how can I get a list of the functions in the <script> tag that is IN the #yesplease div. I don't want any other functions from other script tags. I don't want any global functions or native functions. What I'd like is an array with "wantthis1" and "wantthis2" only in it. I'm hoping not to have to use regex.
I am going to be emptying and filling the #yesplease div with different strings of html (including new script tags with new functions), and I need to make sure that I delete or "wantthis1 = undefined" each function in the script tag before filling it, programmatically, since I won't know every function name. (I don't want them to remain in memory)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script>
function dontCare() {
// don't care
}
</script>
</head>
<body>
<div id="notthisone">
<p>
Hello
</p>
<script>
function dontwantthis () {
// nope
}
</script>
</div>
<div id="yesplease">
<p>
Hello again
</p>
<script>
function wantthis1 () {
// yes
}
function wantthis2 () {
// yes
}
</script>
</div>
<script>
// this function can be called by whatever, but this will look to
// see if functions exist, then call them, otherwise do something
// else
function onSaveOrWhatever () {
if (wantThis1 !== "undefined") {
wantThis1();
}
else {
// do something else (won't get called with above example)
}
if (wantThis3 !== "undefined") {
wantThis3();
}
else {
// do something else (will get called with above example)
}
}
</script>
</body>
</html>
Take innerHTML of all script tags you need
Create an iframe
Get a list of built-in functions of iframe.contentWindow object
Write the content of the script to the iframe created
Get a new list of the functions of iframe.contentWindow object
Find new functions added to the new list
Somehow it doesn't work in stack snippets but it works in Codepen link
var code = document.querySelector("#target script").innerHTML;
var iframe = document.createElement("iframe");
document.body.appendChild(iframe);
var builtInFunctions = getFunctionsOfWindowObject();
var html = `<html><head><script>${code}</script></head><body /></html>`;
iframe.srcdoc = html;
var allFunctions = getFunctionsOfWindowObject();
var result = allFunctions.filter(function(n) {
return builtInFunctions.indexOf(n) < 0;
});
console.log(result);
function getFunctionsOfWindowObject() {
var functions = [];
var targetWindow = iframe.contentWindow;
for (var key in targetWindow) {
if (
targetWindow.hasOwnProperty(key) &&
typeof targetWindow[key] === "function"
) {
functions.push(key);
}
}
return functions;
}
iframe {
display: none;
}
<div id="target">
<script>
function wantthis1() {}
function wantthis2() {}
</script>
</div>
The are a few ways to solve this problem
Architect your application. Use react or vue (or even jquery) to add more control to your code/dom
AST parsing, which would be overkill
Hack it
If you hack it, the problem that you will face is that you are adding functions to global scope. This is shared by everyone, so you can't really monitor it in a nice way.
You can however take advantage of javascript singlethreadedness, and know that things won't happen in the background while you are doing monitoring tasks.
<script>
// take a cache of what is present before your script
window.itemsPresentBeforeScript = {};
foreach (var item in window) {
window.itemsPresentBeforeScript[item] = window[item];
}
</script>
<script> .... your other script </script>
<script>
// use your first cache to see what changed during the script execution
window.whatWasAddedInTheLastScript = {};
foreach (var item in window) {
if (!window.itemsPresentBeforeScript[item]) {
window.whatWasAddedInTheLastScript[item] = window[item];
}
}
delete window.itemsPresentBeforeScript;
// not you have a global list of what was added and you can clear it down when you need to
</script>

How do I change innerHTML of loaded page with JQuery

I want my jquery to change text inside blocks with class "ToChange". It works fine inside current html file, but it does not with external html file (that I insert with "load" method). Here is my code:
index.html :
<!DOCTYPE html>
<html lang="en">
<head>
<title>Home page</title>
<script src="jquery-3.1.1.js"></script>
<script>
$(function(){
$('.insert_external').load("external.html");
});
</script>
<script>
$(function(){
length = document.getElementsByClassName("ToChange").length;
for (i = 0; i < length; i++) {
document.getElementsByClassName("ToChange")[i].innerHTML = "New Text";
}
});
</script>
</head>
<body>
<div class="insert_external"></div>
<div class="ToChange">
This changes fine
</div>
<div class="ToChange">
This changes fine too
</div>
</body>
</html>
external.html :
<div class="ToChange">
This text does not change :(
</div>
As result I see 3 strings :
This text does not change :(
New Text
New Text
And I want all of them to be "New Text". Is it possible to do so using only html and js with jquery?
You have to change the html inside load() callback so the new data is here, else it will change in the old DOM since the JS works asynchronously.
You've to wait for the .load() to finish the request :
$('.insert_external').load("external.html", function() {
length = document.getElementsByClassName("ToChange").length;
for (i = 0; i < length; i++) {
document.getElementsByClassName("ToChange")[i].innerHTML = "New Text";
}
});
NOTE : Since you're using jQuery it'll be better to use .each() function instead :
$('.insert_external').load("external.html", function() {
$(".ToChange").each(function(){
$(this).text("New Text");
})
})
Hope this helps.
The function updating the text is running before the new content is actually loaded, because the load-function works asynchronously. You should wait until the new data has loaded. For this, use the callback of the .load()-function.
Try something like that
<script>
$(function(){
$('.insert_external').load("external.html",function(){
setText();
});
});
</script>
<script>
$(function(){
function setText(){
length = document.getElementsByClassName("ToChange").length;
for (i = 0; i < length; i++) {
document.getElementsByClassName("ToChange")[i].innerHTML = "New Text";
}
}
});
</script>
You just have to set a callback function when completed.

.innerHTML: Cannot set property 'innerHTML' of null

First, I am completely new to coding and have been using self-teaching tools to learn Javascript in my free time. I've learned enough to start building my own projects. My first attempt is to build a randomizer (in this case, random restaurant names). The Javascript works through my tests in the console as do the buttons. However, I cannot seem to get the .innerHTML to work and I'm not sure what I'm missing. I've done several searches here and none of the solutions I've found seem to be working.
The error I'm getting is listed in the title and it is appearing at line 29.
Here is Javascript:
var randomRestaurant = {
restaurantName: [],
findRestaurant: function() {
var restaurantName = Math.random();
if (restaurantName < 0.20) {
this.restaurantName.push("China Taste");
}
else if (restaurantName < 0.40) {
this.restaurantName.push("Pizza Johns");
}
else if (restaurantName < 0.60) {
this.restaurantName.push("Liberatore's");
}
else if (restaurantName < 0.80) {
this.restaurantName.push("Bill Bateman's");
}
else {
this.restaurantName.push("R&R Taqueria");
}
},
clearRestaurant: function() {
randomRestaurant.restaurantName.splice(0, 1);
}
};
var randomRestaurantButton = document.getElementById('randomRestaurantName');
randomRestaurantButton.addEventListener('click', function() {
randomRestaurant.findRestaurant();
document.getElementById("restaurantNameDisplay").innerHTML = randomRestaurant.restaurantName[0]; //<--line 29
});
var randomRestaurantButton = document.getElementById('refreshRestaurant');
randomRestaurantButton.addEventListener('click', function() {
randomRestaurant.clearRestaurant();
randomRestaurant.findRestaurant();
document.getElementById("restaurantNameDisplay").innerHTML = randomRestaurant.restaurantName[0];
});
And here is my HTML:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div><h1>Random Restaurant!</h1>
<button id="randomRestaurantName">Click me for a random restaurant!</button>
</div>
<br>
<h2="restaurantNameDisplay"></h2="restaurantNameDisplay">
<div>
<br>
<button id="refreshRestaurant">Nah. Give me another one.</button>
</div>
</body>
<script src="script.js"></script>
</html>
Thanks for your help and hopefully it's not due to something stupid like a typo.
There are some problems here.
the h2 tag id should be
<h2 id="restaurantNameDisplay"></h2>
your buttons are set on the same variable name, change the second to
var refreshRestaurantButton = document.getElementById('refreshRestaurant');
refreshRestaurantButton.addEventListener('click', function () {
randomRestaurant.clearRestaurant();
randomRestaurant.findRestaurant();
document.getElementById("restaurantNameDisplay").innerHTML = randomRestaurant.restaurantName[0];
});
If it's still not working, you should call your script after the page load event.
so insert your javascript code to a function (e.g. "myFunc()") and change your html body tag to:
body onload="myFunc()">
Most probably this line <h2="restaurantNameDisplay"></h2="restaurantNameDisplay"> should be
<h2 id="restaurantNameDisplay"></h2>

"getElementsByTagName(...)[0]" is undefined?

I have the following code, which basically toggles through a bunch of images.
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
var num = 1;
img = document.getElementsByTagName("img")[0];
hbutton = document.getElementsByTagName("h1")[0];
hbutton.onclick = function() {
num += 1;
img.src = num + ".jpg";
}
</script>
</head>
<body>
<h1>Press Here!</h1>
<img src = "1.jpg"></img>
</body>
</html>
For some reason, when I run it, nothing happens, because of the following error as displayed by my Firebug console.
hbutton is undefined
---
hbutton.onclick = function() {
When I run just the JS after the page has loaded however, it works perfectly fine!!! Why is this?
Your code is executing before the h1 tag is defined. You must run it in an onload handler or put it just before /body
JavaScript is interpreted top-to-bottom. So at the place where your <script> executes, no h1 tags are known yet.
Try putting the <script>-Tag to the bottom of your page. Otherwise, if you need the script at the beginning of the page, an onLoad-Handler might help:
<script type="text/javascript">
function onLoadHandler() {
// your original javascript code here...
}
</script>
<body onload="onloadHandler()">
<!-- HTML Code here-->
When you put it in the header, your h1 is not loaded yet. hbutton becomes undefined, not an object. Then when you try to set .onclick, it breaks because you cant set properties of something undefined. When you put the code in the body, your h1 is already loaded, so the code works as you expected it to.
You can fix this by leaving your code at the top, but only calling it after an onload event.
The head gets executed before the dom is loaded. Put it on the button of the page or put an onload function in the body tag.
It cannot find document.getElementsByTagName("img") when the Document isnt ready yet, because it is simply not there yet.
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
function onDocumentReady(){
var num = 1;
img = document.getElementsByTagName("img")[0];
hbutton = document.getElementsByTagName("h1")[0];
hbutton.onclick = function() {
num += 1;
img.src = num + ".jpg";
}
}
</script>
</head>
<body onload="onDocumentReady()">
<h1>Press Here!</h1>
<img src = "1.jpg"></img>
</body>
</html>
or simply do this:
<!DOCTYPE html>
<html>
<head></head>
<body>
<h1>Press Here!</h1>
<img src = "1.jpg"></img>
<script type="text/javascript">
var num = 1;
img = document.getElementsByTagName("img")[0];
hbutton = document.getElementsByTagName("h1")[0];
hbutton.onclick = function() {
num += 1;
img.src = num + ".jpg";
}
</script>
</body>
</html>
The problem is that the script is being executed immediately it is encountered during page load.
Since it's at the top of the page, in the header, this means that it is executed before the page has loaded the <h1> element (or any of the rest of the body).
Therefore, when it asks for getElementsByTagName('h1'), there aren't any matching elements at that moment in time.
You need to either:
* move the code to the end of the script.
* or wrap it in a function, and trigger the function to execute when the page has finished loading -- ie use the onload method.

How do you execute a dynamically loaded JavaScript block?

I'm working on a web page where I'm making an AJAX call that returns a chunk of HTML like:
<div>
<!-- some html -->
<script type="text/javascript">
/** some javascript */
</script>
</div>
I'm inserting the whole thing into the DOM, but the JavaScript isn't being run. Is there a way to run it?
Some details: I can't control what's in the script block (so I can't change it to a function that could be called), I just need the whole block to be executed. I can't call eval on the response because the JavaScript is within a larger block of HTML. I could do some kind of regex to separate out the JavaScript and then call eval on it, but that's pretty yucky. Anyone know a better way?
Script added by setting the innerHTML property of an element doesn't get executed. Try creating a new div, setting its innerHTML, then adding this new div to the DOM. For example:
<html>
<head>
<script type='text/javascript'>
function addScript()
{
var str = "<script>alert('i am here');<\/script>";
var newdiv = document.createElement('div');
newdiv.innerHTML = str;
document.getElementById('target').appendChild(newdiv);
}
</script>
</head>
<body>
<input type="button" value="add script" onclick="addScript()"/>
<div>hello world</div>
<div id="target"></div>
</body>
</html>
You don't have to use regex if you are using the response to fill a div or something. You can use getElementsByTagName.
div.innerHTML = response;
var scripts = div.getElementsByTagName('script');
for (var ix = 0; ix < scripts.length; ix++) {
eval(scripts[ix].text);
}
While the accepted answer from #Ed. does not work on current versions of Firefox, Google Chrome or Safari browsers I managed to adept his example in order to invoke dynamically added scripts.
The necessary changes are only in the way scripts are added to DOM. Instead of adding it as innerHTML the trick was to create a new script element and add the actual script content as innerHTML to the created element and then append the script element to the actual target.
<html>
<head>
<script type='text/javascript'>
function addScript()
{
var newdiv = document.createElement('div');
var p = document.createElement('p');
p.innerHTML = "Dynamically added text";
newdiv.appendChild(p);
var script = document.createElement('script');
script.innerHTML = "alert('i am here');";
newdiv.appendChild(script);
document.getElementById('target').appendChild(newdiv);
}
</script>
</head>
<body>
<input type="button" value="add script" onclick="addScript()"/>
<div>hello world</div>
<div id="target"></div>
</body>
</html>
This works for me on Firefox 42, Google Chrome 48 and Safari 9.0.3
An alternative is to not just dump the return from the Ajax call into the DOM using InnerHTML.
You can insert each node dynamically, and then the script will run.
Otherwise, the browser just assumes you are inserting a text node, and ignores the scripts.
Using Eval is rather evil, because it requires another instance of the Javascript VM to be fired up and JIT the passed string.
The best method would probably be to identify and eval the contents of the script block directly via the DOM.
I would be careful though.. if you are implementing this to overcome a limitation of some off site call you are opening up a security hole.
Whatever you implement could be exploited for XSS.
You can use one of the popular Ajax libraries that do this for you natively. I like Prototype. You can just add evalScripts:true as part of your Ajax call and it happens automagically.
For those who like to live dangerously:
// This is the HTML with script element(s) we want to inject
var newHtml = '<b>After!</b>\r\n<' +
'script>\r\nchangeColorEverySecond();\r\n</' +
'script>';
// Here, we separate the script tags from the non-script HTML
var parts = separateScriptElementsFromHtml(newHtml);
function separateScriptElementsFromHtml(fullHtmlString) {
var inner = [], outer = [], m;
while (m = /<script>([^<]*)<\/script>/gi.exec(fullHtmlString)) {
outer.push(fullHtmlString.substr(0, m.index));
inner.push(m[1]);
fullHtmlString = fullHtmlString.substr(m.index + m[0].length);
}
outer.push(fullHtmlString);
return {
html: outer.join('\r\n'),
js: inner.join('\r\n')
};
}
// In 2 seconds, inject the new HTML, and run the JS
setTimeout(function(){
document.getElementsByTagName('P')[0].innerHTML = parts.html;
eval(parts.js);
}, 2000);
// This is the function inside the script tag
function changeColorEverySecond() {
document.getElementsByTagName('p')[0].style.color = getRandomColor();
setTimeout(changeColorEverySecond, 1000);
}
// Here is a fun fun function copied from:
// https://stackoverflow.com/a/1484514/2413712
function getRandomColor() {
var letters = '0123456789ABCDEF';
var color = '#';
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
<p>Before</p>

Categories