Skip to content

Commit

Permalink
Added a lot of options
Browse files Browse the repository at this point in the history
  • Loading branch information
KittyGiraudel committed Apr 13, 2016
1 parent 0957408 commit 2d6a7b1
Show file tree
Hide file tree
Showing 5 changed files with 162 additions and 51 deletions.
65 changes: 44 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,47 @@ iframify(HTMLElement, [options])

Where options is an object where keys can be:

* `styles` *(string)*: extra styles to be injected in a `<style>` tag in the `<head>`;
* `htmlAttr` *(object)*: an object of attributes to pass to the `<html>` element;
* `bodyAttr` *(object)*: an object of attributes to pass to the `<body>` element.
* **`styles`**
**Type:** `string`
**Default:** none
**Description:** Extra styles to be injected in a `<style>` tag in the `<head>`.
**Example:** `.component { color: red }`

* **`htmlAttr`**
**Type:** `object`
**Default:** none
**Description:** An object of attributes to pass to the `<html>` element.
**Example:** `{ class: 'no-js', 'data-foo': 'bar' }`

* **`bodyAttr`**
**Type:** `object`
**Default:** none
**Description:** An object of attributes to pass to the `<body>` element.
**Example:** `{ class: 'body', id: 'top' }`

* **`stylesSelector`**
**Type:** `string`
**Default:** `link[rel*=stylesheet], style`
**Description:** The selector to use to define what styles to import.
**Example:** `link[rel*=stylesheet]:not([href$="styleguide.css"]), style`

* **`metaCharset`**
**Type:** `string`
**Default:** the one in the outer document (if any).
**Description:** The string representation of the charset `<meta>` tag to import.
**Example:** `<meta charset="utf-8" />`

* **`metaViewport`**
**Type:** `string`
**Default:** the one in the outer document (if any).
**Description:** The string representation of the viewport `<meta>` tag to import.
**Example:** `<meta name="viewport" content="width=device-width, initial-scale=1">`

* **`sizingTimeout`**
**Type:** `number`
**Default:** `500`
**Description:** Number of milliseconds to wait before sizing the height of the iframe based on its content. Can be useful when injecting asynchronously loaded content.
**Example:** `1000`

## Examples

Expand All @@ -30,26 +68,11 @@ var iframes = Array.prototype.map.call(components, iframify);
```

```js
// <html> attributes
// With options
var component = document.querySelector('.component');
var iframe = iframify(component, {
htmlAttr: { class: 'no-js', 'data-foo': 'bar' }
});
```

```js
// <body> attributes
var component = document.querySelector('.component');
var iframe = iframify(component, {
bodyAttr: { class: 'body', id: 'top' }
});
```

```js
// Extra styles
var component = document.querySelector('.component');
var iframe = iframify(component, {
styles: '.my-custom { content: ""; }'
styles: '.component { color: red; }',
metaViewport: '<meta name="viewport" content="width=device-width">'
});
```

Expand Down
72 changes: 42 additions & 30 deletions iframify.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,26 @@
/**
* iframify is a script that replaces a node with a dynamically generated iframe
* verson of itself, including all its necessary styles to perform correctly.
*
* It can be useful when working with a styleguide displaying components, in
* order to replicate element queries on a component level.
*
* For instance:
*
* var componentContainers = document.querySelectorAll('.styleguide-component-container')
* Array.prototype.forEach.call(componentContainers, iframify)
*
* Demo:
*
* http://codepen.io/HugoGiraudel/pen/vGWpyr
*/

(function (global) {
var metaViewport = document.querySelector('meta[name="viewport"]');
var metaCharset = document.querySelector('meta[charset]');
var stylesheets = Array.prototype.map.call(
document.querySelectorAll('link[rel*=stylesheet], style'),
function (stylesheet) { return stylesheet.outerHTML; }
).join('');
var queryCache = {};

/**
* Get the styling nodes to inject in the head of the embedded document
*
* @param {String} selector
* @return {String}
*/
function getStylingNodes (selector) {
if (typeof queryCache[selector] === 'undefined') {
queryCache[selector] = Array.prototype.map.call(
document.querySelectorAll(selector),
function (stylesheet) {
return stylesheet.outerHTML;
}
).join('');
}

return queryCache[selector];
}

/**
* Get the content for the iframified version of a node.
Expand All @@ -32,14 +31,14 @@
*/
function getIframeContentForNode (node, options) {
return '<!doctype html>' +
'<html ' + formatAttributes(options.htmlAttr) + '>' +
'<html ' + options.htmlAttr + '>' +
'<head>' +
(metaCharset ? metaCharset.outerHTML : '') +
(metaViewport ? metaViewport.outerHTML : '') +
(stylesheets.length ? stylesheets : '') +
(options.styles ? '<style>' + options.styles + '</style>' : '') +
options.metaCharset +
options.metaViewport +
options.stylesheets +
options.styles +
'</head>' +
'<body ' + formatAttributes(options.bodyAttr) + '>' +
'<body ' + options.bodyAttr + '>' +
node.innerHTML +
'</body>' +
'</html>';
Expand All @@ -52,7 +51,6 @@
* @return {String}
*/
function formatAttributes (attrObj) {
attrObj = attrObj || {};
var attributes = [];

for (var attribute in attrObj) {
Expand All @@ -79,6 +77,19 @@
);
}

function getOptions (options) {
var opts = options || {};
opts.htmlAttr = formatAttributes(opts.htmlAttr || {});
opts.bodyAttr = formatAttributes(opts.bodyAttr || {});
opts.sizingTimeout = opts.sizingTimeout || 500;
opts.styles = (opts.styles ? '<style>' + opts.styles + '</style>' : '');
opts.stylesheets = getStylingNodes(opts.stylesSelector || 'link[rel*=stylesheet], style');
opts.metaCharset = opts.metaCharset || metaCharset.outerHTML;
opts.metaViewport = opts.metaViewport || metaViewport.outerHTML;

return opts;
}

/**
* Transform a collection of nodes into an iframe version of themselves
* including all the styles they need to perform correctly.
Expand All @@ -88,7 +99,8 @@
* @return undefined
*/
function iframify (node, options) {
options = options || {};
options = getOptions(options);

var iframe = document.createElement('iframe');
var html = getIframeContentForNode(node, options);
iframe.srcdoc = html;
Expand All @@ -108,7 +120,7 @@
setTimeout(function () {
var iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
iframe.height = getDocumentHeight(iframeDocument);
}, 500);
}, options.sizingTimeout);

return iframe;
}
Expand Down
4 changes: 4 additions & 0 deletions tests/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,7 @@
color: rgb(0, 42, 0);
}
}

.component--test-15 {
color: deeppink;
}
24 changes: 24 additions & 0 deletions tests/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,30 @@
</div>
</div>
</div>

<div class="test test-13">
<div class="iframify">
<div class="component component--test-13">
<p class="component__element">Custom meta charset import.</p>
</div>
</div>
</div>

<div class="test test-14">
<div class="iframify">
<div class="component component--test-14">
<p class="component__element">Custom meta viewport import.</p>
</div>
</div>
</div>

<div class="test test-15">
<div class="iframify">
<div class="component component--test-15">
<p class="component__element">Custom styles selector.</p>
</div>
</div>
</div>
</div>

<script src="../iframify.js"></script>
Expand Down
48 changes: 48 additions & 0 deletions tests/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -198,4 +198,52 @@ describe('iframify', function () {
done();
};
});

it('should allow passing a custom meta charset', function (done) {
var test = document.querySelector('.test-13 > .iframify');
var iframe = iframify(test, {
metaCharset: '<meta charset="utf-16">'
});

iframe.onload = function () {
var iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
var meta = iframeDocument.querySelector('meta[charset]');
var actual = meta.getAttribute('charset');
var expected = 'utf-16';
expect(actual).to.be.equal(expected);
done();
};
});

it('should allow passing a custom meta viewport', function (done) {
var test = document.querySelector('.test-14 > .iframify');
var iframe = iframify(test, {
metaViewport: '<meta name="viewport" content="initial-scale=1">'
});

iframe.onload = function () {
var iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
var meta = iframeDocument.querySelector('meta[name="viewport"]');
var actual = meta.getAttribute('content');
var expected = 'initial-scale=1';
expect(actual).to.be.equal(expected);
done();
};
});

it('should allow passing a custom styles selector', function (done) {
var test = document.querySelector('.test-15 > .iframify');
var iframe = iframify(test, {
stylesSelector: 'style'
});

iframe.onload = function () {
var iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
var component = iframeDocument.querySelector('.component');
var actual = iframe.contentWindow.getComputedStyle(component).getPropertyValue('color');
var expected = 'rgb(0, 0, 0)';
expect(actual).to.be.equal(expected);
done();
};
});
});

0 comments on commit 2d6a7b1

Please sign in to comment.