-
Notifications
You must be signed in to change notification settings - Fork 2
/
ssr.js
126 lines (112 loc) · 3.93 KB
/
ssr.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
122
123
124
125
126
window.ssrify = function(upgrade) {
var shadowStyleList = [];
var shadowStyleMap = {};
function removeScripts(container) {
var scripts = container.querySelectorAll('script');
[].slice.call(scripts).forEach(function(el) {
el.remove();
});
}
function removeImports(container) {
var imports = container.querySelectorAll('link[rel=import]');
[].slice.call(imports).forEach(function(el) {
el.remove();
});
}
function replaceStyles(container) {
var styles = container.querySelectorAll('style');
[].slice.call(styles).forEach(function(el) {
var style = shadowStyleMap[el.textContent];
if (!style) {
style = el;
shadowStyleMap[style.textContent] = style;
style.index = shadowStyleList.length;
style.setAttribute('shadow-style', style.index);
shadowStyleList.push(style);
}
var shadowStyle = document.createElement('shadow-style');
shadowStyle.setAttribute('index', style.index);
el.parentNode.replaceChild(shadowStyle, el);
});
}
function replaceShadowRoot(el, clonedEl) {
if (el.shadowRoot) {
var shadowRoot = document.createElement('shadow-root');
for (var e=el.shadowRoot.firstChild; e; e=e.nextSibling) {
shadowRoot.appendChild(e.cloneNode(true));
}
removeImports(shadowRoot);
replaceStyles(shadowRoot);
replaceShadowRoots(el.shadowRoot, shadowRoot);
clonedEl.insertBefore(shadowRoot, clonedEl.firstChild);
}
}
function replaceShadowRoots(container, clonedContainer) {
var elements = container.querySelectorAll('*');
var clonedElements = clonedContainer.querySelectorAll('*');
[].slice.call(elements).forEach(function(el, i) {
replaceShadowRoot(el, clonedElements[i]);
});
return clonedContainer;
}
function insertBase(doc, clonedDoc) {
if (!doc.querySelector('base[href]')) {
var base = document.createElement('base');
base.href = doc.baseURI;
var head = clonedDoc.querySelector('head');
head.insertBefore(base, head.firstChild);
}
}
function openDocument(doc) {
var uri = "data:text/html," + encodeURIComponent(doc.outerHTML);
var newWindow = window.open(uri);
}
function insertShadowStyles(doc, list) {
var template = document.createElement('template');
template.setAttribute('shadow-styles', '');
list.forEach(function(style) {
template.content.appendChild(style);
});
doc.querySelector('head').appendChild(template);
}
function registerShadowRoot() {
var t = document.querySelector('template[shadow-styles]');
var shadowStyles = t && t.content.children;
var proto = Object.create(HTMLElement.prototype);
proto.createdCallback = function() {
var parent = this.parentNode;
if (parent) {
var shadowRoot = parent.createShadowRoot();
var child;
while ((child = this.firstChild)) {
if (child.localName == 'shadow-style') {
child.remove();
child = shadowStyles[child.getAttribute('index')].cloneNode(true);
}
shadowRoot.appendChild(child);
}
this.remove();
}
};
document.registerElement('shadow-root', {prototype: proto});
}
function insertShadowRootRegistration(clonedDoc, upgrade) {
var script = document.createElement('script');
var openComment = upgrade ? '' : '/* Uncomment to upgrade:\n';
var closeComment = upgrade ? '' : '\n*/';
script.textContent =
openComment + '(' +
registerShadowRoot.toString() +
')();' + closeComment;
clonedDoc.querySelector('head').appendChild(script);
}
var doc = document.documentElement;
var clonedDoc = doc.cloneNode(true);
replaceShadowRoots(doc, clonedDoc);
removeImports(clonedDoc);
removeScripts(clonedDoc);
insertBase(doc, clonedDoc);
insertShadowStyles(clonedDoc, shadowStyleList);
insertShadowRootRegistration(clonedDoc, upgrade);
openDocument(clonedDoc);
};