I'm trying to create a to-do extension for firefox and I need to trigger a function when the delete button is clicked (line 8).
function viewPrevious(){
var prom = browser.storage.sync.get(null);
prom.then((res) => {
var text = '<ul class="list-group list-group-flush">';
var i;
for (i = 0; i < res.todos.length; i+=4) {
text+='<ul class="list-group list-group-flush"><li class="list-group-item">'+res.todos[i]+' '+res.todos[i+1]+' '+res.todos[i+2]+'</li>';
text+='<button type="button" class="btn btn-primary" onClick="myFunc" id='+i+'">Delete</button>';
}
text+='</ul>';
document.getElementById("oldTodos").innerHTML = text;
window.onload=function(){
console.log("KKOO");
var promii = browser.storage.sync.get(null);
promii.then((res) => {
for(i=0;i<res.todos.length;i+=4){
console.log("redda");
document.getElementById(i.toString()).addEventListener('click',function(){
console.log('kjk'+i);
var removingItem = browser.storage.sync.remove(i);
removingItem.then(function(){
viewPrevious();
});
});
}
});
}
});
}
I have added the onClick="myFunc" in line 8 and the function is,
function myFunc(){
console.log("ABC");
}
when I run this and click the button it gives me the following error
Content Security Policy: The page’s settings blocked the loading of a resource at self (“script-src”). Source: onclick attribute on BUTTON element.
I tried using meta tags and giving script-src 'unsafe-inline', but it also did not work. And I dont have a good idea about this content security policy
Is there any another way for making this work or am I doing something wrong?
Your issue here is the HTML onclick attribute. To do this correctly, you need to use addEventListener like you are on the later click listener.
// Untested, but it should put you on the correct path
var ul = document.createElement('ul');
ul.classList.add('list-group', 'list-group-flush');
var i;
for (i = 0; i < res.todos.length; i+=4) {
// I'm ignoring <ul class="list-group list-group-flush"> from your example, because
// this doesn't look like you intend to be nesting lists
var li = document.createElement('li';
li.classList.add('list-group-item');
// In your example, you had left an open XSS vulnerability by simply
// concatenating user todos with your markup, textContent is much safer
li.textContent = res.todos[i]+' '+res.todos[i+1]+' '+res.todos[i+2];
ul.appendChild(li);
var button = document.createElement('button');
button.classList.add('btn', 'btn-primary');
button.addEventListener('click', myFunc);
button.id = i;
ul.appendChild(button);
}
document.getElementById("oldTodos").innerHTML = '';
document.getElementById("oldTodos").appendChild(ul);
Related
I am currently learning js and I'm making a chrome extension.
After finishing the tutorial, I want to add more features for the extension. And I did it!
You can see down below, I added buttons to delete the corresponding list.
What I added
However, when i deploy the extension, it couldn't work. And i found out that the problem is chrome extensions don't allow you to have inline JavaScript.
And i have no idea how to convert the code to plain js.
Here is my code which will render the list of items in the form of html.
<ul id="uls"></ul>
const ulElement = document.getElementById('uls');
function render(lists) {
let listItems = ''
for (let i = 0; i < lists.length; i++) {
listItems += `
<li>
<button class='remove_data ${i}' onclick=getValue(this)>x</button>
<a target='_blank' href='${lists[i]}'>
${lists[i]}
</a>
</li>
`
}
ulElement.innerHTML = listItems;
}
This is the js code that make the delete function.
const buttons = document.getElementsByClassName('remove_data');
let myWebsites = []
function getValue(element) {
index = parseInt(element.className.split(' ')[1])
deleteItem(index)
function deleteItem(index) {
myWebsites.splice(index, 1)
localStorage.setItem('myWebsites', JSON.stringify(myWebsites));
render(myWebsites);
}
These code works fine in my live server. However, it couldn't work in chrome extension as there is onclick=getValue(this) in the html.
Can someone tell me how to convert it to js? Appreciate your help!
It's because you're using the onclick attribute, which uses inline JavaScript.
You can parse the HTML, then use addEventListener to add a click event listener to the button:
const ulElement = document.getElementById('uls');
function render(lists) {
uiElement.innerHTML = '';
for (let i = 0; i < lists.length; i++) {
let li = document.createElement('li');
li.innerHTML = `<li>
<button class='remove_data ${i}'>x</button>
<a target='_blank' href='${lists[i]}'>
${lists[i]}
</a>
</li>`;
li.querySelector('button').addEventListener('click', function(){
getValue(this);
}
`
}
}
Note: this is my first project, sorry if this is obvious, I've looked everywhere and can't find it
I'm working on a website that would serve as a better UI then file explorer/VLC, so I've made a button where you can upload all your video files. With those file, my Javascript has a for loop to create a button for each individual video found in that directory, then it puts the name of the file in the button. And all that works, now what I'm struggling with is creating an onclick event that gets the ID of the button that was pressed. I'm really struggling on doing this so any help would be appreciated.
My javascript:
var animepaths = [];
var animenames = [];
//FILE UPLOADING
const fileSelector = document.getElementById('file-selector');
fileSelector.addEventListener('change', (event) => {
const fileList = event.target.files;
filesLoop(fileList)
});
//loops through every file found in the directory
//and saves the path and file name to local storage
function filesLoop(files){
for(var x = 0; x < files.length; x++){
animepaths.push(files[x].webkitRelativePath)
animenames.push(files[x].name)
}
printOnScreen(animenames, animepaths)
}
//Creating a button with an H2 tag inside
//Then display it on screen in the container (display grid)
function printOnScreen(animenames, animepaths){
for(var x = 0; x < animenames.length; x++){
const elem = document.createElement('button');
elem.classList.add("grid-item");
const elemtext = document.createElement('h2')
elemtext.innerHTML = animenames[x]
elemtext.classList.add("grid-innertext")
elem.appendChild(elemtext)
document.getElementById('container').appendChild(elem);
}
}
If you have more than 1 button you should identify the group of buttons via a class not an id.
in your case it's even easier, as you create the button pro grammatically, so we could create the event there ...
//your function and some of my code
function printOnScreen(animenames, animepaths){
for(var x = 0; x < animenames.length; x++){
createAndAppendButton(animenames[x], animepaths[i]);
}
}
function createAndAppedButton(name, path) {
let button = document.createElement('button');
button.classList.add("grid-item");
button.innerText = name
document.getElementById('container').appendChild(button);
button.addEventListener("click", function() {
//do something with the path, which is accessible her
console.log(path)
});
}
As you can see I removed your h1, as H1 cannot be a child of the button-tag
In any DOM event handler, the element that triggered the event is available within the handler via the this keyword. Therefore, to get the id of the button that triggered the event, you'd just use: this.id.
Here's an example:
document.querySelector("button").addEventListener("click", function(){
console.log("The button's id is: " + this.id);
});
<button id="btn">Click Me</button>
Maybe you can use something like:
function onClick(animenameId) {
...
// your magic here
...
}
function printOnScreen(animenames, animepaths){
...
elem.onclick = onClick(animenames[x]);
...
}
What do you think?
I tried to run script with greasemonkey on web whatsapp. But not work so well.
the code need to open new windows and refresh it with content:
[1st part:]
var list = main[0].getElementsByClassName("msg");
var i;
for (i = 0; i < list.length; i++) {
list[i].innerHTML += '<button type="button" class="addButton" onclick="javascript:addNewMsg(this.parentElement)">Add</button>';
}
[2nd part:]
document.body.innerHTML += '<div style="position:absolute;bottom:20px;right:20px;z-index:80;border:1px black solid"><button type="button" id="startButton" onclick="javascript:us_openWAwindows()">Start</button></div>';
The button not working (not open new windows)..
Thx for the help.
edit: cleaned the code for presenting only the issue.
It would appear you can't use onclick attributes on this page due to its Content Security Policy.
Please try using event listeners you are attaching in JavaScript, not embedded JS code in HTML.
1) For creating the "Add" buttons it would probably be best to create it totally in JS and set all attributes there, because from first glace it looks to me like there can be multiple and you are creating and deleting them again depending on what the user does.
for (i = 0; i < list.length; i++) {
var btn = document.createElement("button");
btn.setAttribute("type", "button");
btn.setAttribute("class", "addButton");
btn.addEventListener("click", function() {
addNewMsg(this.parentElement);
});
btn.innerHTML = "Add";
list[i].appendChild(btn);
}
2) For the "Start" button which is created only once we can keep the HTML if you want and use its ID to reference it (although you could also use the same approach as I did above):
document.body.innerHTML += '<div style="position:absolute;bottom:20px;right:20px;z-index:80;border:1px black solid"><button type="button" id="startButton">Start</button></div>';
document.getElementById("startButton").addEventListener("click", us_openWAwindows);
(Note that I removed the onclick attribute from both.)
I do not have access to the HTML of the pages (they are program-built dynamically).
I do have access to the JS page it is linked to.
For example I can do somethin like this and it works:
window.onload=function(){
var output = document.getElementById('main_co');
var i=1;
var val="";
while(i<=1)
{ if(!document.getElementById('timedrpact01'+i))
{
var ele = document.createElement("div"); ele.setAttribute("id","timedrpact01"+i);
ele.setAttribute("class","inner");
ele.innerHTML=" Hi there!" ;
output.appendChild(ele);
I would like to use this basis insert a button that would allow to switch from one CSS set (there are several files invoked) to another _another path.
Many thanks
The external stylesheets are referenced using link, as in:
<link rel="stylesheet" href="http://example.com/path-to-css">
So, get hold of the appropriate link element using:
var css = document.getElementsByTagName("link")[0];
Here, we got hold of the first link available by specifying the [0] index.
Then, overwrite the href attribute to point it to the new path.
css.setAttribute("href", "http://example.com/path-to-css");
window.onload=function(){
var output = document.getElementById('main_co');
var i=1;
var val="";
//switch all the href's to another path
var switchStyleSheet = function() {
var links = document.getElementsByTagName("link");
for(var i=0; lkC = links.length; i < lkC; i++)
links[0].href = links[0].href.replace('path_to_file', '_path_to_file');
};
while(i<=1) //while is not required here, if i is 1
{
if(!document.getElementById('timedrpact01'+i)) {
var ele = document.createElement("div"); ele.setAttribute("id","timedrpact01"+i);
ele.setAttribute("class","inner");
ele.innerHTML=" Hi there!" ;
var button = document.createElement('button');
if(button.addEventListener) {
button.addEventListener('click', switchStyleSheet);
}
else {
button.attachEvent('click', switchStyleSheet);
}
output.appendChild(button);
output.appendChild(ele);
}
}
}
I have a list of href / text that I need to make anchors for and then display those anchors. Everything is fine until I actually click any of the anchors. They each only open a tab for the last href. I.e. if the href of the last element in the list is href_n, then every anchor links to href_n, even if the 'href' attribute is different.
//Current basic setup:
loop through list:
anchor = doc.create('a')
divElem = doc.create('div')
anchor.setAttribute('class', 'foo')
anchor.setAttribute('href', 'bar')
anchor.innerHTML = 'mytext'
anchor.addEventListener('click', function() {chrome.tabs.create({url: 'myurl'})});
divElem.appendChild(anchor)
container.appendChild(anchor)
Previously I tried using .onClick, but I kept having a problem with the event listener trying to just attach to the url. I am very amenable to a cleaner solution though that involves something simpler than an eventlistener.
Thanks much.
You mostly just need to change your click handler to not use variables that are not still valid. Here's sample code:
var urlList = [
"aaaa",
"bbbb",
];
var textList = [
"text1",
"text2"
];
function createAnchors(urls, text, container) {
for (var i = 0; i < urls.length; i++) {
var a = document.createElement("a");
var div = document.createElement("div");
a.href = urls[i];
a.innerHTML = text[i];
a.className = "foo";
a.addEventListener("click", function() {
chrome.tabs.create({url: this.href});
return(false);
});
div.appendChild(a);
container.appendChild(div);
}
}
The issue is that any variables in your event listener function are not evaluated until the click. So, in this case, you can avoid using them by just getting the url directly from the clicked link.
I hope you also realize that older versions of IE don't support addEventListener. This mozilla page shows you how you can handle that in the Internet Explorer section.
You need to create a closure:
var urls = [];
for(var i=0;i<urls.length;i++){
anchor.addEventListener('click',
(function(url) {
return function() {
chrome.tabs.create({url: url})
}
})(urls[i])
);
}