-1

EDIT -- I provided a streamlined code below as well as an issue reported to the console.

Original content starts here -- I'm trying to get a simple chrome extension to inject into roll20's text area. I've tried a number of ways of selecting the elements in question. I know this is possible because Beyond20 does it. Regardless, all attempts have failed. The objects always return null. Even:

const foo = document.querySelector('#textchat-input');

alert(foo);

My most recent attempts:

index.html

<div id="test">
<button id="myButton">Press me</button>
</div>
<script src="libs/jquery-3.4.1.min.js" charset="UTF-8"></script>
<script src="script.js"></script>

script.js

document.querySelector("button#myButton").addEventListener("click", postToChat);

function postToChat(){

  const message = "testing";
  const chatInputElement = document.querySelector('#textchat-input textarea');
  const chatButtonElement = document.querySelector('#textchat-input .btn');
  
   if (chatInputElement && chatButtonElement) {
    const activeText = chatInputElement.value;
    chatInputElement.value = message;
    chatButtonElement.click();
    if (activeText) setTimeout(() => chatInputElement.value = activeText, 10);
  }
  
}

EDIT---Let me try to simplify the code to hone in on what I'm struggling with.

document.querySelector("button#myButton").addEventListener("click", postToChat);

function postToChat(){

  const message = "testing";
  const chatInputElement = document.querySelector('#textchat-input textarea');
  const chatButtonElement = document.querySelector('#textchat-input .btn');
  
   if(chatInputElement==null){alert("chatinputnull");}
   if(chatButtonElement==null){alert("chatButtonElementnull");}
   
}

Both alerts fire.

Also this error:

Content Security Policy blocks inline execution of scripts and stylesheets The Content Security Policy (CSP) prevents cross-site scripting attacks by blocking inline execution of scripts and style sheets. To solve this, move all inline scripts (e.g. onclick=[JS code]) and styles into external files. ⚠️ Allowing inline execution comes at the risk of script injection via injection of HTML script elements. If you absolutely must, you can allow inline script and styles by: adding unsafe-inline as a source to the CSP header adding the hash or nonce of the inline script to your CSP header. 1 directive Directive Element Source Location Status script-src-elem app.roll20.net/:6 blocked Learn more: Content Security Policy - Inline Code

EDIT 2 -- someone marked this as a duplicate while linking to multiple answers that don't solve the problem. The solution is an issue of scope. I will post a solution below.

manifest.json

{
    "name": "Charms Check Roll20 Extension",
    "version": "0.0.1",
    "description": "A pre-alpha attempt to create a roll20 plugin for Charms Check",
    "content_scripts": [
        {
            "matches": ["https://app.roll20.net/editor/"],
            "js": ["script.js"],
            "run_at": "document_end"
        }
    ],
    "manifest_version": 3,
    "author": "MrLiioadin"
}

script.js

window.setTimeout(test, 5000); //ensures page is fully loaded before executing functions

function test (){
    postToChat("Charms Check Extension is ready");
}

const postToChat = (msg) => {
  const chatInputElement = document.querySelector('#textchat-input textarea'),
    chatButtonElement = document.querySelector('#textchat-input .btn');
    
  if (chatInputElement && chatButtonElement) {
    const activeText = chatInputElement.value;
    chatInputElement.value = msg;
    chatButtonElement.click();
    if (activeText) setTimeout(() => chatInputElement.value = activeText, 10);
  }
}

Delete index.html

mrliioadin
  • 17
  • 4
  • 2
    `document.querySelector('#textchat-input');` is looking for a DOM element with the ID "textchat-input". You don't have one of those, so it's returning null. (Incidentally: you'll find it much much easier to debug things if you use `console.log` isntead of `alert`) – Daniel Beck Sep 30 '22 at 16:50
  • 1
    You're also trying to read input from what would need to be an `input` field (because you're using its `value`) but chatButtonElement is supposed to be a child element of it (based on the `#textchat-input .btn` selector). Inputs can't contain other elements. – Daniel Beck Sep 30 '22 at 16:53
  • 1
    Also you're reading `chatInputElement.value`, then trying to write the exact same value back to the exact same place, but inside a timeout for no reason. – Daniel Beck Sep 30 '22 at 16:54
  • 1
    And `chatButtonElement.click()` won't result in anything because there's no click event attached to that element. – Daniel Beck Sep 30 '22 at 16:55
  • Within roll20 the HTML is:
    – mrliioadin Sep 30 '22 at 17:59
  • Also, the if statement never runs on the above code because the chatInputElement and chatButtonElement are both null. I should probably simplify the code to avoid distraction. Essentially, we're not even getting that far to find other problems. – mrliioadin Sep 30 '22 at 18:01
  • I copied the HTML you included above into a fiddle: https://jsfiddle.net/ht8sdonx/1/ In the fiddle, none of your queries are returning null against that html. – lukenetsurfer Sep 30 '22 at 18:44
  • How are you running your JS queries? Are you just pasting them into the console and hitting 'enter'? – lukenetsurfer Sep 30 '22 at 18:47
  • Everything works in JSFiddle. It doesn't work when it's run as a chrome extension on roll20. The chrome extension has three files: manifest.json, index.html, script.js. The latter two are posted in full above. – mrliioadin Oct 01 '22 at 13:23

1 Answers1

0

I put together a fiddle with your example:

https://jsfiddle.net/96sungy7/

document.querySelector("button#myButton").addEventListener("click", postToChat);
document.querySelector("#textchat-input .btn").addEventListener("click", exampleClickHandler);

function postToChat(){
    console.log('Executing postToChat!');

  const message = "testing";
  const chatInputElement = document.querySelector('#textchat-input textarea');
  const chatButtonElement = document.querySelector('#textchat-input .btn');

  if (chatInputElement && chatButtonElement) {
    const activeText = chatInputElement.value;
    console.log(`activeText: ${activeText}`);
    
    chatInputElement.value = message;
    chatButtonElement.click();
    if (activeText) setTimeout(() => chatInputElement.value = activeText, 500);
  }
 
}

function exampleClickHandler() {
    const textAreaValue = document.querySelector('#textchat-input textarea').value;
    console.log(`Executing the exampleClickHandler. Textarea has value: ${textAreaValue}`);
}
#textchat-input {
  border: 1px solid black;
  padding: 10px;
  margin-bottom: 20px;
}
<div id="textchat-input">
  <textarea></textarea>
  <button class="btn">Example button</button>
</div>

<button id="myButton">Press me</button>

It seems like everything is working in your example, although I noticed that the time you passed to setTimeout is very short (only 10 milliseconds), such that testing flickers in and out so fast you might not see it. I bumped up the timeout to 500 milliseconds, so that it's a little more obvious that the text has changed.

Also, I added an exampleClickHandler so that you can see what's happening when you call chatButtonElement.click().

lukenetsurfer
  • 84
  • 1
  • 5
  • Thanks! I'm also getting this to work in jsfiddle but not in roll20 and it's not entirely clear why. I do know that "const chatInputElement = document.querySelector('#textchat-input textarea');" returns null. It's like it's not quite able to read document. But, I'm fairly sure this is the same process Beyond20 uses. – mrliioadin Sep 30 '22 at 17:57