Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

inject component css into the window document #15

Open
javadoug opened this issue Feb 3, 2016 · 22 comments
Open

inject component css into the window document #15

javadoug opened this issue Feb 3, 2016 · 22 comments

Comments

@javadoug
Copy link

javadoug commented Feb 3, 2016

The module style imports do not seem to be used in the resulting document, it would be a nice if they did.

@JakeGinnivan
Copy link
Owner

This would be awesome. Not sure how we would achieve this, it kinda needs the style loader to be invoked again to load the styles into the popup.

Any ideas?

For the moment I use the url to load a page with some styles but it's not great.

@donnrriz
Copy link

I was able to do this using webpack and some simple DOM manipulation.
Use etxract-text-webpack-plugin to create a separate css file.
Before you open the new window, copy the css link (s) into the head of the new window

@llamamoray
Copy link

@donnrriz Do you have an example of how you copy the css link into the head of the new window?

@donnrriz
Copy link

Sorry for my late reply.
You could set the popup url to your current url , to avoid cross domain issues. Then, remove any html from the popout using document.documentElement.innerHTML = ''; leaving
Then write in your css using popoutWindow.document.write('');
That's the separate css file.
Ad a div to the body tag (with a id='target'
Then use React DOM to load your component into the loaded div
Hope that helps. Its along the ines of GoldenLayout (https://golden-layout.com)

@donnrriz
Copy link

Sorry my message has the following missing
the popout using document.documentElement.innerHTML = ''; leaving only html head and body tags

@donnrriz
Copy link

Sorry for bombarding you , this is my last post unless you want more information. Actually its pretty easy using React, if you just set the url to the address you are using it'll have the css in the head . Then remove the div used to load the React code - which removes all the content from the body, then load the children from props. Would you like a pull request done ?

@llamamoray
Copy link

@donnrriz no thanks - that's great. Got it working.

@jcabrerazuniga
Copy link

jcabrerazuniga commented Aug 2, 2017

donnrriz, could you please post an example code? I am in the same problem. My react components loose their CSS definitions within the popout

@donnrriz
Copy link

donnrriz commented Aug 4, 2017

Here's what I came up with

    const _CONTAINER_ID = 'popout-content-container'

    popoutWindow = ownerWindow.open(your-path, '_blank', options, '')
    
    const onloadHandler = () => {

     let div = popoutWindow.document.getElementById('app') // the root div of your react view which you replace so you have css but loose any html elements you don't want
     div.parentNode.removeChild(div)
     container = popoutWindow.document.createElement('div')
     container.id = _CONTAINER_ID
     popoutWindow.document.body.appendChild(container)

	// I found it useful to clone my react element to pass in some props like height , width
	// I add a callback after the element is rendered


     ReactDOM.render(cloneElement(your-react-component, {id, data, winId, path, width: win.innerWidth, height: win.innerHeight}), container, () => {
         ownerWindow.postMessage({message: 'My popout opened'}, path)

     })

     }

     popoutWindow.onload = onloadHandler

     popoutWindow.addEventListener('beforeunload', () => {

         ownerWindow.postMessage() // I inform my app when I close a window

    })

@colshacol
Copy link

At my work, we have done it like so:

screen shot 2017-10-04 at 1 30 57 pm

@marchaos
Copy link
Collaborator

marchaos commented Oct 4, 2017

@colshacol Would be interesting to see if that works without a url.

@colshacol
Copy link

@marchaos What exactly do you mean? You gotta have a href to get the file.

A quick alternative would be getting the window object from Popout, importing your styles in text format (<style>.my-class { ... } .my-other-class { ... }</style>, doing something like window.document.head.innerText += stylesString.

Meh, idk. I am much too tired to be prescribing code right now. -_-

@marchaos
Copy link
Collaborator

marchaos commented Oct 4, 2017

@colshacol I mean a url on the popout itself - not sure it will work with about:blank. You're using popout.html.

@calesce
Copy link

calesce commented Nov 8, 2017

Copying the parent's document.styleSheets when the child window is created might be suitable, see this gist from this article.

@kpadala
Copy link

kpadala commented Dec 8, 2017

@colshacol : Do we need to do anything specific to make <link rel=> to work while calling the Popout component. As per the code. I am seeing only the title is getting embedded in the head.

I tried but getting error:ncaught Error: Minified React error #39; visit http://facebook.github.io/react/docs/error-decoder.html?invariant=39&args[]= for the full message or use the non-minified dev environment for full errors and additional helpful warnings. at r (0.js:1) at Object._renderSubtreeIntoContainer (0.js:25) at Object.render (0.js:25) at t.value (0.js:44) at t.value (0.js:44) at t.value (0.js:44) at t.value (0.js:44) at e.notifyAll (0.js:25) at r.close (0.js:25) at r.closeAll (0.js:11)

@chriddyp
Copy link

chriddyp commented Mar 1, 2018

Combining #15 (comment)

Copying the parent's document.styleSheets when the child window is created might be suitable, see this gist from this article.
and #29 (comment),
I successfully injected styles with something like:

function copyStyles(sourceDoc, targetDoc) {
  Array.from(sourceDoc.styleSheets).forEach(styleSheet => {
    if (styleSheet.cssRules) { // for <style> elements
      const newStyleEl = sourceDoc.createElement('style');

      Array.from(styleSheet.cssRules).forEach(cssRule => {
        // write the text of each rule into the body of the style element
        newStyleEl.appendChild(sourceDoc.createTextNode(cssRule.cssText));
      });

      targetDoc.head.appendChild(newStyleEl);
    } else if (styleSheet.href) { // for <link> elements loading CSS from a URL
      const newLinkEl = sourceDoc.createElement('link');

      newLinkEl.rel = 'stylesheet';
      newLinkEl.href = styleSheet.href;
      targetDoc.head.appendChild(newLinkEl);
    }
  });
}
const App = props => {
    return (
        <Popout>
            {
                popoutWindow => {
                    copyStyles(window.document, popoutWindow.document);
                    return (
                        <div>
                            ...
                        </div>
                    );
                }
            }
        </Popout>
    )
}


```

@adamscybot
Copy link

I had success using https://github.com/rmariuzzo/react-new-window.

@msimonian77
Copy link

Unfortunately react-new-window doesn't work in IE11.

@llamamoray
Copy link

@msimonian77 We've moved to https://github.com/Microsoft/react-popout-component which has good cross browser support including IE

@GoChartingAdmin
Copy link

@chriddyp Do you know how to make sure that bootstrap glyphicons also work in the popout window. Currently the copyStyles is working but how do I also include fonts such as glyphicons and awesome-font

@GoChartingAdmin
Copy link

GoChartingAdmin commented Sep 12, 2018

Re-wrote copyStyle to include fonts as well

function copyStyles(sourceDoc, targetDoc) {
	Array.from(sourceDoc.styleSheets).forEach(styleSheet => {
	  if (styleSheet.cssRules) { // for <style> elements
			const newStyleEl = sourceDoc.createElement("style");

			Array.from(styleSheet.cssRules).forEach(cssRule => {
		  // write the text of each rule into the body of the style element
		  newStyleEl.appendChild(sourceDoc.createTextNode(cssRule.cssText));
			});

			targetDoc.head.appendChild(newStyleEl);
	  } else if (styleSheet.href) { // for <link> elements loading CSS from a URL
			const newLinkEl = sourceDoc.createElement("link");

			newLinkEl.rel = "stylesheet";
			newLinkEl.href = styleSheet.href;
			targetDoc.head.appendChild(newLinkEl);
	  }
	});
	Array.from(sourceDoc.fonts).forEach(font => {
		targetDoc.fonts.add(font);
	})
}

Anyone knows how to include global stylesheets?

@mbrevda
Copy link

mbrevda commented Sep 3, 2019

This seems simpler. Is it missing anything?

const copyStyles = (src, dest) => {
  Array.from(src.styleSheets).forEach(styleSheet => {
    dest.head.appendChild(styleSheet.ownerNode.cloneNode(true))
  })
  Array.from(src.fonts).forEach(font => dest.fonts.add(font))
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests