Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@ Styles are not added on `require`, but instead on call to `use`/`ref`. Styles ar

Note: Behavior is undefined when `unuse`/`unref` is called more often than `use`/`ref`. Don't do that.

#### Iframe support
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might need more general header here


Each `use/ref` call can also take an optional `DOMElement` parameter to tell `style-loader` where to append the resulting link/style tag(s) to (for usage with Iframes etc.):

```javascript
var iframe = document.getElementsByTagName('iframe')[0];
style.use(iframe.contentDocument.head); // = style.ref(iframe.contentDocument.head);
style.unuse(); // = style.unref();
```

### Options

#### `insertAt`
Expand Down
42 changes: 22 additions & 20 deletions addStyles.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ var stylesInDom = {},
singletonCounter = 0,
styleElementsInsertedAtTop = [];

module.exports = function(list, options) {
module.exports = function(list, options, parentElement) {
if(typeof DEBUG !== "undefined" && DEBUG) {
if(typeof document !== "object") throw new Error("The style-loader cannot be used in a non-browser environment");
}
Expand All @@ -33,8 +33,11 @@ module.exports = function(list, options) {
// By default, add <style> tags to the bottom of <head>.
if (typeof options.insertAt === "undefined") options.insertAt = "bottom";

// If no `parentElement` was supplied (via `use()` call first parameter), default to document <head>.
if (typeof parentElement === "undefined") parentElement = getHeadElement();

var styles = listToStyles(list);
addStylesToDom(styles, options);
addStylesToDom(styles, parentElement, options);

return function update(newList) {
var mayRemove = [];
Expand All @@ -46,7 +49,7 @@ module.exports = function(list, options) {
}
if(newList) {
var newStyles = listToStyles(newList);
addStylesToDom(newStyles, options);
addStylesToDom(newStyles, parentElement, options);
}
for(var i = 0; i < mayRemove.length; i++) {
var domStyle = mayRemove[i];
Expand All @@ -59,7 +62,7 @@ module.exports = function(list, options) {
};
}

function addStylesToDom(styles, options) {
function addStylesToDom(styles, parentElement, options) {
for(var i = 0; i < styles.length; i++) {
var item = styles[i];
var domStyle = stylesInDom[item.id];
Expand All @@ -69,12 +72,12 @@ function addStylesToDom(styles, options) {
domStyle.parts[j](item.parts[j]);
}
for(; j < item.parts.length; j++) {
domStyle.parts.push(addStyle(item.parts[j], options));
domStyle.parts.push(addStyle(item.parts[j], parentElement, options));
}
} else {
var parts = [];
for(var j = 0; j < item.parts.length; j++) {
parts.push(addStyle(item.parts[j], options));
parts.push(addStyle(item.parts[j], parentElement, options));
}
stylesInDom[item.id] = {id: item.id, refs: 1, parts: parts};
}
Expand All @@ -99,20 +102,19 @@ function listToStyles(list) {
return styles;
}

function insertStyleElement(options, styleElement) {
var head = getHeadElement();
function insertStyleElement(styleElement, parentElement, options) {
var lastStyleElementInsertedAtTop = styleElementsInsertedAtTop[styleElementsInsertedAtTop.length - 1];
if (options.insertAt === "top") {
if(!lastStyleElementInsertedAtTop) {
head.insertBefore(styleElement, head.firstChild);
parentElement.insertBefore(styleElement, parentElement.firstChild);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's an overlap with #135 here.

} else if(lastStyleElementInsertedAtTop.nextSibling) {
head.insertBefore(styleElement, lastStyleElementInsertedAtTop.nextSibling);
parentElement.insertBefore(styleElement, lastStyleElementInsertedAtTop.nextSibling);
} else {
head.appendChild(styleElement);
parentElement.appendChild(styleElement);
}
styleElementsInsertedAtTop.push(styleElement);
} else if (options.insertAt === "bottom") {
head.appendChild(styleElement);
parentElement.appendChild(styleElement);
} else {
throw new Error("Invalid value for parameter 'insertAt'. Must be 'top' or 'bottom'.");
}
Expand All @@ -126,26 +128,26 @@ function removeStyleElement(styleElement) {
}
}

function createStyleElement(options) {
function createStyleElement(parentElement, options) {
var styleElement = document.createElement("style");
styleElement.type = "text/css";
insertStyleElement(options, styleElement);
insertStyleElement(styleElement, parentElement, options);
Copy link

@worldsense-tms worldsense-tms Sep 30, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe you need to call parentElement.ownerDocument.createElement() instead of document.createElement(). One alternative is to call adoptNode.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, probably better change this.

return styleElement;
}

function createLinkElement(options) {
function createLinkElement(parentElement, options) {
var linkElement = document.createElement("link");
linkElement.rel = "stylesheet";
insertStyleElement(options, linkElement);
insertStyleElement(linkElement, parentElement, options);
return linkElement;
}

function addStyle(obj, options) {
function addStyle(obj, parentElement, options) {
var styleElement, update, remove;

if (options.singleton) {
var styleIndex = singletonCounter++;
styleElement = singletonElement || (singletonElement = createStyleElement(options));
styleElement = singletonElement || (singletonElement = createStyleElement(parentElement, options));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When parentElement changes, the singletonElement should perhaps change as well?

update = applyToSingletonTag.bind(null, styleElement, styleIndex, false);
remove = applyToSingletonTag.bind(null, styleElement, styleIndex, true);
} else if(obj.sourceMap &&
Expand All @@ -154,15 +156,15 @@ function addStyle(obj, options) {
typeof URL.revokeObjectURL === "function" &&
typeof Blob === "function" &&
typeof btoa === "function") {
styleElement = createLinkElement(options);
styleElement = createLinkElement(parentElement, options);
update = updateLink.bind(null, styleElement);
remove = function() {
removeStyleElement(styleElement);
if(styleElement.href)
URL.revokeObjectURL(styleElement.href);
};
} else {
styleElement = createStyleElement(options);
styleElement = createStyleElement(parentElement, options);
update = applyToTag.bind(null, styleElement);
remove = function() {
removeStyleElement(styleElement);
Expand Down
4 changes: 2 additions & 2 deletions useable.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ module.exports.pitch = function(remainingRequest) {
"var dispose;",
"var content = require(" + loaderUtils.stringifyRequest(this, "!!" + remainingRequest) + ");",
"if(typeof content === 'string') content = [[module.id, content, '']];",
"exports.use = exports.ref = function() {",
"exports.use = exports.ref = function(parentElement) {",
" if(!(refs++)) {",
" exports.locals = content.locals;",
" dispose = require(" + loaderUtils.stringifyRequest(this, "!" + path.join(__dirname, "addStyles.js")) + ")(content, " + JSON.stringify(query) + ");",
" dispose = require(" + loaderUtils.stringifyRequest(this, "!" + path.join(__dirname, "addStyles.js")) + ")(content, " + JSON.stringify(query) + ", parentElement);",
" }",
" return exports;",
"};",
Expand Down