3

I'm trying to use Polymer in a chrome extension. The overall goal is to leverage styling encapsulation so my content scripts run isolated from the CSS of the page being visited.

Beginning with a custom element in my-element.html

I'm using Vulcanize like so:

vulcanize -o build.html my-element.html

If I try something like this in my content script:

// content_script.js
$.get(chrome.extension.getURL('build.html'), function(data) {
  var html = document.createElement('div');
  html.innerHTML = data;
  document.body.appendChild(html);

  var custom = document.createElement('my-element');
  document.body.appendChild(custom);
});

build.html loads ok, but my-element is not working. It just creates an empty tag with none of my shadow DOM contents.

I see a couple potential problems with what I'm doing:

  1. I'm loading the polymer stuff into a div. Does it need to be loaded directly into body? If so, how is this done?
  2. I'm assuming loading build.html with ajax will work in the first place. Is this an incorrect assumption?
anderspitman
  • 9,230
  • 10
  • 40
  • 61
  • Just curious: why would you use Polymer in a Chrome extension? Since it's Chrome, couldn't you just use custom elements and shadow DOM out of the box? – MaxArt Aug 01 '14 at 22:58
  • 2
    Yes I could, and if it comes down to it I'll try that next, but Polymer adds a lot of sugar and nice-to-haves. And I figure it makes more sense to learn polymer since it's more production ready where native web components are still possibly quite a ways out. – anderspitman Aug 01 '14 at 23:00
  • 6
    There's an outstanding chrome bug which prevents content scripts from registering custom elements: https://code.google.com/p/chromium/issues/detail?id=390807 – ebidel Aug 02 '14 at 00:40
  • Bummer. So if I want CSS isolation in a chrome extension are iframes my only route currently? Or is there another reasonable avenue? – anderspitman Aug 02 '14 at 00:49
  • There is another way, check out my solution in the following post http://stackoverflow.com/questions/30022350/registering-a-custom-element-from-a-chrome-extension/30034988#30034988 – dipole_moment May 04 '15 at 16:29

2 Answers2

1

Edit: While the method below does work, I don't think I can recommend it except for projects very limited in scope -- single domain target or simple widget.


My guess is that Chrome blocking registerElement() for extensions is causing you issues. Injecting an HTML file which then calls polymer.js seems to put the library in context of the host page rather than the content script.

Here's a proof of concept I hacked together from their tutorial:

manifest.json

{
    "name": "polymer-test",
    "version": "0.0.1",
    "manifest_version": 2,
    // CSP might be overkill
    "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",
    "content_scripts": [
        {
            "js": [
                "contentscript.js"
            ],
            "matches": [
                "<all_urls>"
            ]
        }
    ],
    "web_accessible_resources": [
        "counter.html",
        "polymer.html",
        "polymer.js"
    ]
}

contentscript.js

document.body.insertAdjacentHTML('beforeend', '<div>'
    // polymer.html throws an error w/o layout.html -- not a big deal
    + '<link rel="import" href="'+chrome.extension.getURL('/polymer.html')+'">'
    + '<link rel="import" href="'+chrome.extension.getURL('/custom.html')+'">'
    + '<my-counter counter="1">Points</my-counter>'
+ '</div>');

counter.html

<polymer-element name="my-counter" attributes="counter">
    <template>
        <style></style>
        <div id="label"><content></content></div>
        Value: <span id="counterVal">{{counter}}</span><br>
        <button on-tap="{{increment}}">Increment</button>
    </template>
    <script>
        Polymer({
            counter: 0, // Default value
            counterChanged: function() {
                this.$.counterVal.classList.add('highlight');
            },
            increment: function() {
                this.counter++;
            }
        });
    </script>
</polymer-element>
awdyson
  • 243
  • 3
  • 12
  • Check out: http://stackoverflow.com/questions/30022350/registering-a-custom-element-from-a-chrome-extension/30034988#30034988 – dipole_moment May 04 '15 at 16:30
0

I recently created Boundary, a CSS+JS library to solve problems just like this. Boundary creates elements that are completely separate from the existing webpage's CSS.

Take creating a dialog for example. After installing Boundary, you can do this in your content script

var dialog = Boundary.createBox({
    "id": "yourDialogID"
});

Boundary.loadBoxCSS("#yourDialogID", "style-for-elems-in-dialog.css");

Boundary.appendToBox(
    "#yourDialogID",
    "<button id='submit_button'>submit</button>"
);

Boundary.find("#submit_button").click(function() {
  // find() function returns a regular jQuery DOM element
  // so you can do whatever you want with it.
  // some js after button is clicked.
});

Elements within #yourDialogID will not be affected by the existing webpage.

Hope this helps. Please let me know if you have any question.

https://github.com/liviavinci/Boundary

Livia Zhang
  • 193
  • 1
  • 7
  • Please **clearly disclose** that this is your own creation, and include a minimal example in the answer. Otherwise this may be considered spam/link-only/self-promotion. – Xan Oct 17 '14 at 18:24
  • And if you can make a good answer according to these hints, put it in the main question: http://stackoverflow.com/questions/12783217/how-to-really-isolate-stylesheets-in-the-google-chrome-extension – Xan Oct 17 '14 at 18:25
  • @Xan Mmm I saw your comment about removing the code snippet in my previous answer. I guess I misunderstood you when you said minimal example. What counts as a minimal example? – Livia Zhang Oct 17 '14 at 19:04
  • I mean just the formatting tag that adds "Run code snippet". I edited your other post to take it out. – Xan Oct 17 '14 at 19:05
  • @Xan got it! I thought the snippet tag was for stackoverflow to recognize code :p – Livia Zhang Oct 17 '14 at 19:09
  • Multiline code is formatted just using the right amount of indent (4 spaces normally), and the syntax highlight normally comes from question tags. – Xan Oct 17 '14 at 19:10