Chrome Extension - Change styles.CSS var not working

Viewed 526

Sorry, I messed that up. I did not update the manifest from the last post and I forgot the content.js, that is how the Change button was sending the value and the page was getting the new style attribute value from the one entered in the text field and then to the content.js, existing content.js file added below.


I have a styles.css that changes the web page and is loaded from the popup but want to change a variable in the styles.css from the data entered at the popup.

I've added a content.js file and I can now pass a value from the Popup and it adds a new style attribute to the page but it's not updating the --ptwidth in the styles.css file. I think I need to have it in the styles.css to give the correct location and add the !important option.

I tried to ask this question before an it was closed\linked to one about webpage DOMs and don't have the reputation to post a comment and not sure I should ask my questions there if I could:

How to access the webpage DOM rather than the extension page DOM?


The styles.css injection works using the Wider button and the --ptwidth var is passed the value given (310) in the styles.CSS, at the very least I'd like to be able to enter a new value in the textbox and then use the existing Wider button to load the updated styles.css but it would be nice to have it auto update and maybe even use the slider.

The change button moves the new value entered in the text field to the content.js file and it then adds the new style attribute but it's not working. The insertCSS on the Wider button works but the info it adds is different.

Content.js adds the Style attribute section and the insertCSS adds the :root section that works.

Added by Content.js No Work: enter image description here

Added by insertCSS Works and adds these two: enter image description hereenter image description here

Columns before: enter image description here

Columns after: enter image description here

Rule before using the working Wider button with insertCSS: enter image description here

Rules after the insertCSS injections of styles.css: insertCSS

Popup: enter image description here

manifest:

{
  "manifest_version": 3,
  "name": "Hellper",
  "description": "Extension",
  "version": "0.1",

  "icons": { "16": "logo_16_T.png",
             "48": "logo_48_T.png",
            "128": "logo_128_T.png" 
           },

  "action": {
    "default_icon": "logo_16_T.png",
    "default_popup":"popup.html"
            },

  "permissions": ["scripting", "tabs", "activeTab", "content.js"],
  "host_permissions": ["<all_urls>"],
  
  "content_scripts": [{
    "js": ["jquery-2.2.0.min.js", "popup.js"],
    "matches": ["https://www.google.com/*",
                "https://en.wikipedia.org/*",
                "https://stackoverflow.com/*"]
  }]
}

popup.html:

<!doctype html>
<html>
  <head>
    <title>Popup</title>
  </head>
  <body>
    <input id="button1" type=button value=clickme>
    <button class="format">Wider</button>
    <button class="reset">Reset</button>
        <script src="jquery-2.2.0.min.js"></script>
        <script src="popup.js"></script>
      <!--
        <h2>Background Color</h2>
      <input type="color" id="color-changer" />
      <h2>Rotate Page</h2>
      <input type="range" min="0" max="360" step="1" value="0" id="rotate" />
      -->
    <h1>New Width</h1>
    <p>
      <input type="text" id="newWidth" value="120"/>
      <input type="submit" id="btnChange" value="Change"/>
    </p>
  <div class="form-group">
    <lable for="slider">Project/Task Width</lable>
    <input type="range" min="0" max="999" step="1" value="160" id="slider" />
  </div>
  </body>
</html>

styles.css:

:root {
    --ptwidth: 310px
}

.quixote .qx-grid .editor_grid tbody tr td input, .quixote .qx-grid .editor_grid tbody tr td .input-group {
    /*max-width: 450px !important;
    min-width: 450px !important;*/
    max-width: var(--ptwidth) !important;
    min-width: var(--ptwidth) !important;

popup.js:

$(document).ready(function() {
    $('.reset').click(function() {
    chrome.tabs.query({currentWindow: true, active: true}, function (tabs){
    var activeTab = tabs[0];
            chrome.scripting.removeCSS({
                target: { tabId: activeTab.id },
                files: ["styles.css"]
    });
   });
    })

    $('.format').click(function() {
    chrome.tabs.query({currentWindow: true, active: true}, function (tabs){
    var activeTab = tabs[0];
            chrome.scripting.insertCSS({
                target: { tabId: activeTab.id, allFrames: true },
                files: ["styles.css"]
            });
    /*chrome.tabs.sendMessage(activeTab.id, {"buttonclicked": "wider"});*/
   });
    })
})

$(function(){
    var width = $('#newWidth').val();
    $('#newWidth').on("change paste keyup", function(){
      width = $(this).val();
    });
    $('#btnChange').click(function(){
      chrome.tabs.query({currentWindow: true, active: true}, function (tabs){
        chrome.tabs.sendMessage(tabs[0].id, {todo: "changeWidth", sliderWidth: width})
      });
    });
});

content.js

let root = document.documentElement;

chrome.runtime.onMessage.addListener(
    function(request, sender, sendResponse) {
      if( request.todo == "changeWidth"){
        var updateWidth = request.sliderWidth;
        root.style.setProperty('--ptwidth', updateWidth + "px");
//      start();
      }
    });
2 Answers

It seems like there is still some work to do on this extension. I will try to provide only a solution to what was asked an leave the rest for you to work on.


Issues I will try to address

  1. You shouldn't be reusing popup.js as a content script. You should create a separate file instead of having one script be both injected into the webpage and also being used in the popup window.

  2. You are also sending messages from the popup window without anything listening for the messages. This also would be solved by creating a separate content script that listens for these messages.


Partial solution

I edited the manifest.json and popup.js as well as created a new file content.js.

New manifest.json

  • changed "popup.js" to "content.js"
{
  "manifest_version": 3,
  "name": "Hellper",
  "description": "Extension",
  "version": "0.1",

  "icons": { "16": "logo_16_T.png",
             "48": "logo_48_T.png",
            "128": "logo_128_T.png" 
           },

  "action": {
    "default_icon": "logo_16_T.png",
    "default_popup":"popup.html"
            },

  "permissions": ["scripting", "tabs", "activeTab"],
  "host_permissions": ["<all_urls>"],
  
  "content_scripts": [{
    "js": ["jquery-2.2.0.min.js", "content.js"],
    "matches": ["https://www.google.com/*",
                "https://en.wikipedia.org/*",
                "https://stackoverflow.com/*"]
  }]
}

New popup.js

  • only edited the last function block
  • added a listener for the slider changes
  • coupled the values in the text box and slider, so when one changes, the other changes as well
  • changed the message parameter from "sliderWidth" to "newWidth" to make it more general
  • moved retrieval of the width value into the listeners so the new changed value can be sent along
  • I also suggest removing the change button entirely because the other listeners make it unnecessary
// Unchanged
$(document).ready(function () {
  $(".reset").click(function () {
    chrome.tabs.query({ currentWindow: true, active: true }, function (tabs) {
      var activeTab = tabs[0];
      chrome.scripting.removeCSS({
        target: { tabId: activeTab.id },
        files: ["styles.css"],
      });
    });
  });

  $(".format").click(function () {
    chrome.tabs.query({ currentWindow: true, active: true }, function (tabs) {
      var activeTab = tabs[0];
      chrome.scripting.insertCSS({
        target: { tabId: activeTab.id, allFrames: true },
        files: ["styles.css"],
      });
      /*chrome.tabs.sendMessage(activeTab.id, {"buttonclicked": "wider"});*/
    });
  });
});

// Changed
$(function () {
  // text input listener
  $("#newWidth").on("change paste keyup", function () {
    const width = $(this).val();
    // update slider
    $("#slider").val(width);
    chrome.tabs.query({ currentWindow: true, active: true }, function (tabs) {
      chrome.tabs.sendMessage(tabs[0].id, { todo: "changeWidth", newWidth: width });
    });
  });
  // listener for change button press
  // button might not be needed anymore because of the text input listener above
  $("#btnChange").click(function () {
    const width = $("#newWidth").val();
    // update slider
    $("#slider").val(width);
    chrome.tabs.query({ currentWindow: true, active: true }, function (tabs) {
      chrome.tabs.sendMessage(tabs[0].id, { todo: "changeWidth", newWidth: width });
    });
  });
  // listener for slider changes
  $("#slider").on("input", function () {
    const width = $("#slider").val();
    // update text box
    $("#newWidth").val(width);
    chrome.tabs.query({ currentWindow: true, active: true }, function (tabs) {
      chrome.tabs.sendMessage(tabs[0].id, { todo: "changeWidth", newWidth: width });
    });
  });
});

New content.js

  • created this script to listen for messages sent from the popup and make the changes to the CSS based on the message
$(document).ready(function () {
  // listen for messages sent to the tab the content script is running in
  chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
    // check to see if the message received is something that needs to be acted on
    if (request.todo === "changeWidth") {
      // pull the width data from the message
      const newWidth = request.newWidth;
      // set the style attribute of :root to override the styles.css value for --ptwidth
      document.documentElement.style.setProperty("--ptwidth", newWidth + "px");
    }
    // send a response to avoid errors in popup.js
    sendResponse("Width updated");
  });
});

Hopefully that get you on the right track for finishing your extension!

Don't forget to check out the developer documentation for Chrome extensions. There are several useful posts for teaching how to accomplish the various parts of an extension.

[1] Message Passing: https://developer.chrome.com/docs/extensions/mv3/messaging/

[2] Content Scripts: https://developer.chrome.com/docs/extensions/mv3/content_scripts/

I got this working by using the chrome.scripting.insertCSS to replace the --ptwidth value after the styles.css has been injected. So far everything works with just the popup.js and no need for the content.js file.

I use this to load the styles.css with it's default value.

chrome.tabs.query({currentWindow: true, active: true}, function (tabs){
  var activeTab = tabs[0];
    chrome.scripting.insertCSS({
      target: { tabId: activeTab.id, allFrames: true },
    files: ["styles.css"]
    });
});

Then this when I get a new value from the textbox or slider.

  chrome.tabs.query({currentWindow: true, active: true}, function (tabs){
    var activeTab = tabs[0];
    //alert(readsavewidth);
    $("#slider").val(readsavewidth);
    $("#newWidth").val(readsavewidth);
  chrome.scripting.insertCSS({
    target: { tabId: activeTab.id, allFrames: true },
    css: `:root { --ptwidth: ${readsavewidth + "px"} }`
  });
  });
});

I also used the chrome.storage.local to set and get the last value used.

$(function () {
  // text input listener
  $("#newWidth").on("change paste keyup", function () {
    width = $(this).val();
            //Save it to the localStorage variable which will always remember what you store in it
            chrome.storage.local.set({'savewidth': width});
    // update slider
    $("#slider").val(width);
      chrome.tabs.query({currentWindow: true, active: true}, function (tabs){
        var activeTab = tabs[0];
      chrome.scripting.insertCSS({
        target: { tabId: activeTab.id, allFrames: true },
        css: `:root { --ptwidth: ${width + "px"} }`
      });
    });
  });
  // listener for slider changes
  $("#slider").on("input", function () {
    width = $("#slider").val();
    // update text box
    $("#newWidth").val(width);
        chrome.tabs.query({currentWindow: true, active: true}, function (tabs){
            var activeTab = tabs[0];
        chrome.scripting.insertCSS({
            target: { tabId: activeTab.id, allFrames: true },
            css: `:root { --ptwidth: ${width + "px"} }`
        });
    });

    //Pull text from user inputbox
    var data = width;
    //Save it to the localStorage variable which will always remember what you store in it
      chrome.storage.local.set({'savewidth': data});
  });
});

Then I get the value when the popup opens and it then overights the --ptwidth value using the chrome.scripting.insertCSS funtion.

chrome.storage.local.get('savewidth', function (result) {
  readsavewidth = result.savewidth;

  chrome.tabs.query({currentWindow: true, active: true}, function (tabs){
    var activeTab = tabs[0];
    //alert(readsavewidth);
    $("#slider").val(readsavewidth);
    $("#newWidth").val(readsavewidth);
  chrome.scripting.insertCSS({
    target: { tabId: activeTab.id, allFrames: true },
    css: `:root { --ptwidth: ${readsavewidth + "px"} }`
  });
  });
});
Related