-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathiframify.js
121 lines (106 loc) · 3.33 KB
/
iframify.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
(function (global) {
var metaViewport = document.querySelector('meta[name="viewport"]');
var metaCharset = document.querySelector('meta[charset]');
var metaViewportStr = metaViewport && metaViewport.outerHTML || '';
var metaCharsetStr = metaCharset && metaCharset.outerHTML || '';
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.
*
* @param {HTMLElement} node
* @param {Object} options
* @return {String}
*/
function getIframeContentForNode (node, options) {
return '<!doctype html>' +
'<html ' + options.htmlAttr + '>' +
'<head>' +
options.metaCharset +
options.metaViewport +
options.stylesheets +
options.headExtra +
'</head>' +
'<body ' + options.bodyAttr + '>' +
node.innerHTML +
options.bodyExtra +
'</body>' +
'</html>';
}
/**
* Format an object of attributes into a HTML string
*
* @param {Object} attrObj
* @return {String}
*/
function formatAttributes (attrObj) {
var attributes = [];
for (var attribute in attrObj) {
attributes.push(attribute + '="' + attrObj[attribute] + '"');
}
return attributes.join(' ');
}
/**
* Get document height (stackoverflow.com/questions/1145850/)
*
* @param {Document} doc
* @return {Number}
*/
function getDocumentHeight (doc) {
doc = doc || document;
var body = doc.body;
var html = doc.documentElement;
return Math.max(
body.scrollHeight, body.offsetHeight,
html.clientHeight, html.scrollHeight, html.offsetHeight
);
}
function getOptions (options) {
var opts = options || {};
opts.htmlAttr = formatAttributes(opts.htmlAttr || {});
opts.bodyAttr = formatAttributes(opts.bodyAttr || {});
opts.sizingTimeout = opts.sizingTimeout || 500;
opts.stylesheets = getStylingNodes(opts.stylesSelector || 'link[rel*=stylesheet], style');
opts.metaCharset = opts.metaCharset || metaCharsetStr;
opts.metaViewport = opts.metaViewport || metaViewportStr;
opts.headExtra = opts.headExtra || '';
opts.bodyExtra = opts.bodyExtra || '';
return opts;
}
/**
* Transform a collection of nodes into an iframe version of themselves
* including all the styles they need to perform correctly.
*
* @param {HTMLElement} nodes
* @param {Object} options
* @return undefined
*/
function iframify (node, options) {
options = getOptions(options);
var iframe = document.createElement('iframe');
iframe.srcdoc = getIframeContentForNode(node, options);
node.parentNode.replaceChild(iframe, node);
setTimeout(function () {
var iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
iframe.height = getDocumentHeight(iframeDocument);
}, options.sizingTimeout);
return iframe;
}
global.iframify = iframify;
}(window));