@@ -88,7 +88,7 @@ exports.renderFragment = function render(input) {
88
88
function renderNode ( rootNode ) {
89
89
let createdPromises = [ ] ;
90
90
91
- stubMissingDocumentMethods ( rootNode ) ;
91
+ var document = getDocument ( rootNode ) ;
92
92
93
93
recurseTree ( rootNode , ( foundNode ) => {
94
94
if ( foundNode . tagName ) {
@@ -99,7 +99,7 @@ function renderNode(rootNode) {
99
99
Object . setPrototypeOf ( foundNode , customElement ) ;
100
100
if ( customElement . createdCallback ) {
101
101
createdPromises . push ( new Promise ( ( resolve ) => {
102
- resolve ( customElement . createdCallback . call ( foundNode , rootNode ) ) ;
102
+ resolve ( customElement . createdCallback . call ( foundNode , document ) ) ;
103
103
} ) ) ;
104
104
}
105
105
}
@@ -111,11 +111,46 @@ function renderNode(rootNode) {
111
111
112
112
/**
113
113
* If rootNode is not a real document (e.g. while rendering a fragment), then some methods such as
114
- * createElement are not available. In this case, we proxy these through to the real page document,
115
- * to pretend that you're always rendering your content within a full document.
114
+ * createElement are not available. This method ensures you have a document equivalent object: if
115
+ * you call normal document methods on it (createElement, querySelector, etc) you'll get what you
116
+ * expect.
117
+ *
118
+ * That means methods independent of page hierarchy, especially those that are only present on
119
+ * the true document object (createElement), should be called on the real document, and methods that
120
+ * care about document hierarchy (querySelectorAll, getElementById) should be scope to the given node.
116
121
*/
117
- function stubMissingDocumentMethods ( rootNode ) {
118
- var document = rootNode . ownerDocument ;
119
-
120
- if ( ! rootNode . createElement ) rootNode . createElement = document . createElement . bind ( document ) ;
122
+ function getDocument ( rootNode ) {
123
+ // Only real documents have a null ownerDocument
124
+ if ( rootNode . ownerDocument === null ) return rootNode ;
125
+
126
+ else {
127
+ let document = rootNode . ownerDocument ;
128
+
129
+ var documentMethods = [
130
+ 'compatMode' ,
131
+ 'createTextNode' ,
132
+ 'createComment' ,
133
+ 'createDocumentFragment' ,
134
+ 'createProcessingInstruction' ,
135
+ 'createElement' ,
136
+ 'createElementNS' ,
137
+ 'createEvent' ,
138
+ 'createTreeWalker' ,
139
+ 'createNodeIterator' ,
140
+ 'location' ,
141
+ 'title' ,
142
+ 'onabort' ,
143
+ 'onreadystatechange' ,
144
+ 'onerror' ,
145
+ 'onload' ,
146
+ ] ;
147
+
148
+ documentMethods . forEach ( ( propertyName ) => {
149
+ var property = document [ propertyName ] ;
150
+ if ( typeof ( property ) === 'function' ) property = property . bind ( document ) ;
151
+ rootNode [ propertyName ] = property ;
152
+ } ) ;
153
+
154
+ return rootNode ;
155
+ }
121
156
}
0 commit comments