Kocal / vue-web-extension

🛠️ A Vue CLI 3+ preset (previously a Vue CLI 2 boilerplate) for quickly starting a web extension with Vue, Babel, ESLint and more!
https://vue-web-extension.netlify.app/
MIT License
1.58k stars 167 forks source link

Overlay over current tab and communicate with content js using vuetify interface #638

Closed sherifmayika closed 3 years ago

sherifmayika commented 3 years ago

Hi Folks, I am trying this project for some time. I am new to vue. After trying some coding I feel at home here. I stopped programming a 8 years ago. Lock down bought me into my old passion.

I am able to create basic extensions using this project. But confused a little on complex projects using vue. I can do it with vanilla js though.

Here is I am stuck at. I want have a popup overlay on the DOM (triggered by popup)which functions on vuetify. (I have added vuetify) Where should place my vue file for the overlay interface and how to run it from content script.

I would be so thankful if anyone can give me a example code.

I know this is not an issue. I hope many others will be benefited.

Thanks in anticipation

sherifmayika commented 3 years ago

`import App from './App.vue'

const child = document.querySelector('body').firstChild const anchor = document.createElement('DIV') anchor.insertBefore(child)

new Vue({ el: anchor, render: (h) => h(App) })`

Tried this code. it works but got origin issue.

ErrorUtils caught an error:

Blocked a frame with origin "https://www.---.com" from accessing a cross-origin frame.
e-roy commented 3 years ago

@sherifmayika if I understand you correctly, you want to have the extension open over top of the web page like a iframe?

You could inject a .js file into the page when icon is clicked which will load the popup.html file.

manifest

remove "default_popup": "popup.html"

add

  "web_accessible_resources": [
      "popup.html"
  ],
  "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",

vue.config.js

change contentScripts to

    contentScripts: {
      entries: {
        'content-script': [
          'src/content-scripts/content-script.js'
        ],
        "inject": [
          "src/inject.js"
        ]
      }
    }

background.js

document.addEventListener('DOMContentLoaded', function () {
  function togglePlugin(tab){
    chrome.tabs.executeScript(tab.id, {
      file: './js/inject.js'
    });
  }
  chrome.browserAction.onClicked.addListener(togglePlugin);
});

inject.js

function toggleVisisbility (node) {
    node.style.display = (node.style.display === 'none' || node.style.display === '') ? 'block' : 'none';
}

function appendIframe(iapp) {
    var frameheader = document.createElement('div');
    frameheader.id = 'popup-app';
    frameheader.style.cssText = 'position:fixed;top:16px;right:21px;display:block;' +
        'width:400px;height:400px;z-index:99999999;';
    var iframe = document.createElement('iframe');
    iframe.style.cssText =
        'position: absolute;' +
        'width:400px;height:400px;z-index:99999999;' +
        'background: #ffffff;';
    iframe.src = chrome.extension.getURL('./popup.html');
    document.body.appendChild(iframe);
    frameheader.appendChild(iframe);
    iapp.appendChild(frameheader);
}

function insertIframe(anchor) {
    let iapp = Array.from(anchor.childNodes).find(function(node){ return node.id === 'popup-app'});
    if (iapp) {
        toggleVisisbility(iapp)
    } else {
        appendIframe(anchor)
    }
}

var extensionOrigin = 'chrome-extension://' + chrome.runtime.id;
if (!location.ancestorOrigins.contains(extensionOrigin)) {
    var anchor = document.getElementById('anchor');
    if (anchor) {
        insertIframe(anchor);
    } else {
        const AppRoot = document.createElement('div', { id: 'anchor' });
        AppRoot.id = 'anchor';
        const body = document.getElementsByTagName('body')[0];
        body.appendChild(AppRoot);
        AppRoot.innerHTML = '';
        insertIframe(AppRoot);
    }
}

I hope this helps, I'm also coming back to an old passion myself :)

grandslammer commented 3 years ago

I have a similar issue that I cannot figure out. I wish to cover the entire webpage with an overlay when I click on the browser action button (no popup).

I have it working as an extension with vanilla JavaScript, and I have also separately built out the UI using regular VueJS app (i.e. a normal webpage). I am not using Vuetify.

I now wish to migrate my webpage UI over to an extension, using my vanilla JS logic (located in the background.js and content-script.js) files to activate/deactivate the overlay.

At the moment I have the overlay background (which is generated in the content-script.js file) displaying but I cannot figure out how to get my components from my VueJS webpage version onto it.

In my vanilla JS version of the extension I have all of my HTML code in the index.html file, and in my VueJS webpage version it is split up into components.

I could provide a bunch of code snippets but frankly I don't know where to start...if anybody thinks they can help me then please ask for which files you would like snippets from, and I will provide them. I greatly appreciate any help I can get. Thank you.

grandslammer commented 3 years ago

Forgetting about the component for a second... If I put a simple Hello World h1 in the template in App.vue, it still doesn't show up. I have narrowed down the issue to being something to do with either the App.vue file, or the main,js file. Most likely App.vue.

App.vue:

<template>
  <!-- <div id="app">
    <div id="nav">
      <router-link to="/">Home</router-link> |
      <router-link to="/about">About</router-link>
    </div>
    <router-view />
  </div> -->
  <p>HELLO WORLD!</p>
</template>

<script>
export default {
  name: "App"
};
</script>

Note that I have commented out the #app div in the template. I have also tried putting the Hello World inside #app. It doesn't display either way.

I haven't changed anything in main.js from the default boilerplate. I don't think I need to.

My code in the content script is referencing index.html in the public folder, and when I make a change index.html and then inspect the iFrame after opening the overlay (which uses my own content script code), the change successfully displays. So I'm pretty confident the issue is somehow related to App.vue.

e-roy commented 3 years ago

If you are doing an overlay, have you set the z-index in the style to something like

z-index:99999999;

grandslammer commented 3 years ago

If you are doing an overlay, have you set the z-index in the style to something like

z-index:99999999;

Thanks for your reply. I have the z-index set to 2147483647 (max 32 bit int value) in the content script when the overlay is generated in there using vanilla JS. When I activate it the overlay background displays as expected - only the content from Vue does not display at all.

From content script (this is executing and the overlay background is displaying correctly):

function buildOverlayiFrame() {
  overlayiFrame = document.createElement("iframe");
  overlayiFrame.src = chrome.extension.getURL("../index.html");
  overlayiFrame.id = "overlayiFrame";
  overlayiFrame.scrolling = "no";
  overlayiFrame.style.border = "none"; // Prevents default iframe border from displaying
  overlayiFrame.style.height = "0";
  overlayiFrame.style.width = "100%";
  overlayiFrame.style.position = "fixed";
  overlayiFrame.style.zIndex = "2147483647"; // max 32 bit int value
  overlayiFrame.style.left = "0";
  overlayiFrame.style.right = "0";
  overlayiFrame.style.bottom = "0"; // Makes it animate to bottom of page instead of top
  overlayiFrame.style.backgroundColor = "rgb(0, 0, 0)"; // Black fallback colour
  overlayiFrame.style.backgroundColor = "rgba(0, 0, 0, 0.9)"; // Black with opacity
  overlayiFrame.style.overflowX = "hidden";
  overlayiFrame.style.overflowY = "hidden";
  overlayiFrame.style.transition = "0.5s"; // Overlay transition animation time

  // Adds to start of body
  document.body.insertAdjacentElement("afterbegin", overlayiFrame);
}

Unless you mean the style elsewhere?

grandslammer commented 3 years ago

Also if I put a h1 inside index.html (public folder) and activate the overlay, the h1 DOES display on it as intended when I activate the overlay.

  <body>
    <div id="app"></div>
    <h1>TEST!</h1>
  </body>
grandslammer commented 3 years ago

I am now thinking that the issue could potentially be related to this: Vue Lifecycle Diagram

However, I am unsure as to how to go about resolving it (I'm still new to Vue).

The overlay could potentially be being created before Vue has a chance to inject itself into the page (my own thinking!)

See also: Vue-nextTick #mounted

Can anyone point me in the right direction?

e-roy commented 3 years ago

I would check into the router also. Without seeing the entire project, it's kind of hard to troubleshoot.

grandslammer commented 3 years ago

I would check into the router also. Without seeing the entire project, it's kind of hard to troubleshoot.

I took a look at the router and it seems to be ok, but I'm new to that also so I cannot say for sure.

I can send the project onto you if you don't mind taking a look at it. Alternatively, I could go through it with you via a screenshare over Discord.

e-roy commented 3 years ago

Sure, I'd be glad to look take a look at it. I've been using VueJS the past 6 months, but still very new using git. It can be a learning experience for both of us :)

grandslammer commented 3 years ago

Sure, I'd be glad to look take a look at it. I've been using VueJS the past 6 months, but still very new using git. It can be a learning experience for both of us :)

Great! Add me on Discord and we can discuss it further there. Username is Grand#5374