Search code examples
javascripthtmlcsscanvasgoogle-chrome-extension

How to resize chrome popup extension on button click to make it larger by 'x'%


I am trying to make a chrome extensions that I need to be able to resize using settings I included. One of which are + and - buttons to increase and decrease the popup size (and the canvas) from between 50% and 250%. I've tried to adjust the body and html dimensions, I've tried the transform: scale() function, and I reload the CSS in order to get the updated values. I have some success, but the dimensions are never correct. I don't know what to do.

If anyone can get this to work, I will be forever grateful. This has haunted me the last week and I don't think I will get it.

Relevant Javascript methods:

  const refreshCSS = function() 
  {
    // geeksforgeeks.org/how-to-reload-css-without-reloading-the-page-using-javascript/
    let links = document.getElementsByTagName('link');
    for (let i = 0; i < links.length; i++) {
      if (links[i].getAttribute('rel') == 'stylesheet') 
      {
        let href = links[i].getAttribute('href').split('?')[0];
        let newHref = href + '?version=' + new Date().getMilliseconds();
        links[i].setAttribute('href', newHref);
      }
    }
    //location.reload()
  }

  const adjustScreenSize = function(num) // 'num' is the scale to adjust to
  {
    var body = document.getElementsByTagName("body")[0]
    var html = document.getElementsByTagName("html")[0]
    if (num => 0.5 && num <= 2.5)
    {
      html.style.display = "none"
      body.style.width = ""+(224*num)+"px"
      body.style.height = ""+(292*num)+"px"
      html.style.width = ""+(224*num)+"px"
      html.style.height = ""+(292*num)+"px"
        
      localStorage.scale = num
      scale = num
      //html.style.transform = ('scale(' + scale + ')')
      refreshCSS()
      html.style.display = "block"
    }
  }

HTML:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=168, height=219, initial-scale=1.0" id="dimensions">
   <link rel="stylesheet" type="text/css" href="style.css"/>
    <title>Chrome-Extension</title>
  </head>
  <body class="body">
    <canvas id="canvas" width="224px" height="292px"></canvas>
    <button id="plus">+</button>
    <button id="minus">-</button>
    <script src="script.js"></script>
  </body>
</html>

CSS:

html, body {
  display: block;
  justify-content: center;
  align-content: center;
  min-width: 112px;
  min-height: 146px;
  max-width: 560px;
  max-height: 730px;
  width: 224px;
  height: 292px;
}

canvas {
  width: 224px;
  height: 292px;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: -1; /* Make it appear beneath everything */
}

#plus button {
  /* Position doesn't matter, just that it works */
  position: absolute; 
  width: 20px;
  height: 20px;
  top: 25%;
  background-color: rgb(128, 128, 0);
  font-size: 20px;
}

#minus button {
  /* Position doesn't matter, just that it works */
  position: absolute;
  width: 20px;
  height: 20px;
  top: 75%;
  background-color: rgb(128, 128, 0);
  font-size: 20px;
}

Not sure if needed, but this is the manifest file:

{
    "manifest_version" : 2,
    "name" : "Help",
    "version" : "1789.4",
    "description" : "Stackoverflow help request",
    "icons" : {
        "128" : "images/Icon.png",
        "48" : "images/Icon.png",
        "16" : "images/Icon.png"
    },
    "browser_action" : {
        "default_icon" : "images/Icon.png",
        "default_popup" : "index.html"
    },
    "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'"
}

Solution

  • Yes you can do this, but there are a few issues with the original js and CSS. No change needed in the manifest.json or index.html. Here is a working example with modifications to achieve this behavior.

    style.css

    Note in html,body and canvas I have removed all references to width/height as these will be set and changed programmatically. Additionally there was an issue with button selectors, so I have fixed those. I added red background to canvas to enable debugging its size change.

    html, body {
        display: flex;
        justify-content: center;
        align-content: center;
    }
    
    canvas {
        background: red;
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        z-index: -1; /* Make it appear beneath everything */
    }
    
    #plus {
        /* Position doesn't matter, just that it works */
        position: absolute;
        width: 20px;
        height: 20px;
        top: 25%;
        background-color: rgb(128, 128, 0);
        font-size: 20px;
    }
    
    #minus {
        /* Position doesn't matter, just that it works */
        position: absolute;
        width: 20px;
        height: 20px;
        top: 75%;
        background-color: rgb(128, 128, 0);
        font-size: 20px;
    }
    

    script.js

    I changed quite a few things here so instead of explaining what changed, I will walk you through this example, to explain how it works.

    // window zoom parameters
    const minSize = 0.5, maxSize = 2.5, step = 0.1;
    
    // initial window size, at 100%
    const baselineWidthPx = 224, baselineHeightPx = 292;
    
    // start at zoom = 100 %
    let scale = 1;
    
    // DOM selectors
    const minusButton = document.getElementById('minus');
    const plusButton = document.getElementById('plus');
    const canvasElement = document.getElementById('canvas');
    
    /**
     * helper method to resize some DOM element
     */
    const applySize = (elem, width, height) => {
        elem.style.width = `${width}px`;
        elem.style.height = `${height}px`;
    }
    
    /**
     * New implementation for adjusting screen size
     */
    const adjustScreenSize = function (change) {
    
        // clamp the next window size between min and max size
        const newScale = Math.max(Math.min(scale + change, maxSize), minSize);
    
        // if window size should be changed, apply the change
        if (newScale !== scale) {
            const width = Math.round(baselineWidthPx * newScale);
            const height = Math.round(baselineHeightPx * newScale);
    
            // apply the change
            applySize(document.body, width, height);
            applySize(canvasElement, width, height);
    
            // update the scale locally and persist in storage
            localStorage.scale = newScale;
            scale = newScale;
        }
    }
    
    // register click event handlers
    minusButton.addEventListener('click', () => adjustScreenSize(-step));
    plusButton.addEventListener('click', () => adjustScreenSize(+step));
    
    // initialize size of body and canvas
    // should change to use value from localStorage if exist
    applySize(document.body, baselineWidthPx, baselineHeightPx);
    applySize(canvasElement, baselineWidthPx, baselineHeightPx);
    

    The first part of the script defines some configurable options for: min/max screen size, initial size, and scale, etc.

    Notice the implementation of adjustScreenSize has been changed to do the following: compute the new screen size, where the value is clamped between min and max size. If the size should change, then the change is applied to body tag and the canvas (it is not necessary to adjust the <html/> node). For this to work it was necessary to remove the css values of min-width/max-width/min-height/max-height for these nodes. I recommend not setting these in CSS at all as it becomes tricky to debug.

    The last part of the script registers click handlers for the buttons and sets the initial size of the popup. I see the intent is to use localstorage to persist these settings, so adjust the initialization to use the value from there if it exists.

    Note that there is a max allowed size for extension popup. It seems to overflow a bit with these parameters (0.5 - 2.5); I would double check it.