jsdom_patches.js
7.64 KB
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
// Fix things that JSDOM doesn't do quite right.
'use strict';
var _Object$assign = require('babel-runtime/core-js/object/assign')['default'];
var _Number$isFinite = require('babel-runtime/core-js/number/is-finite')['default'];
var DOM = require('./index');
var Fetch = require('../fetch');
var resourceLoader = require('jsdom/lib/jsdom/browser/resource-loader');
var Utils = require('jsdom/lib/jsdom/utils');
var URL = require('url');
var createHTMLCollection = require('jsdom/lib/jsdom/living/html-collection').create;
DOM.HTMLDocument.prototype.__defineGetter__('scripts', function () {
var _this = this;
return createHTMLCollection(this, function () {
return _this.querySelectorAll('script');
});
});
// Default behavior for clicking on links: navigate to new URL if specified.
DOM.HTMLAnchorElement.prototype._eventDefaults = _Object$assign({}, DOM.HTMLElement.prototype._eventDefaults);
DOM.HTMLAnchorElement.prototype._eventDefaults.click = function (event) {
var anchor = event.target;
if (!anchor.href) return;
var window = anchor.ownerDocument.defaultView;
var browser = window.browser;
// Decide which window to open this link in
switch (anchor.target || '_self') {
case '_self':
{
// navigate same window
window.location = anchor.href;
break;
}
case '_parent':
{
// navigate parent window
window.parent.location = anchor.href;
break;
}
case '_top':
{
// navigate top window
window.top.location = anchor.href;
break;
}
default:
{
// open named window
browser.tabs.open({ name: anchor.target, url: anchor.href });
break;
}
}
browser.emit('link', anchor.href, anchor.target || '_self');
};
// Attempt to load the image, this will trigger a 'load' event when succesful
// jsdom seemed to only queue the 'load' event
DOM.HTMLImageElement.prototype._attrModified = function (name, value, oldVal) {
if (name === 'src' && value && value !== oldVal) resourceLoader.load(this, value);
DOM.HTMLElement.prototype._attrModified.call(this, name, value, oldVal);
};
// Implement getClientRects
DOM.HTMLElement.prototype.getClientRects = function () {
var style = this.style;
if (style && style.display === 'none') {
return [];
}
return [{
bottom: 0,
height: 0,
left: 0,
right: 0,
top: 0,
width: 0
}];
};
Object.defineProperty(DOM.HTMLElement.prototype, 'offsetHeight', {
get: function get() {
return 0;
}
});
Object.defineProperty(DOM.HTMLElement.prototype, 'offsetWidth', {
get: function get() {
return 0;
}
});
// Implement insertAdjacentHTML
DOM.HTMLElement.prototype.insertAdjacentHTML = function (position, html) {
var parentNode = this.parentNode;
var container = this.ownerDocument.createElementNS('http://www.w3.org/1999/xhtml', '_');
container.innerHTML = html;
switch (position.toLowerCase()) {
case 'beforebegin':
{
while (container.firstChild) parentNode.insertBefore(container.firstChild, this);
break;
}
case 'afterbegin':
{
var firstChild = this.firstChild;
while (container.lastChild) firstChild = this.insertBefore(container.lastChild, firstChild);
break;
}
case 'beforeend':
{
while (container.firstChild) this.appendChild(container.firstChild);
break;
}
case 'afterend':
{
var nextSibling = this.nextSibling;
while (container.lastChild) nextSibling = parentNode.insertBefore(container.lastChild, nextSibling);
break;
}
}
};
// Implement documentElement.contains
// e.g., if(document.body.contains(el)) { ... }
// See https://developer.mozilla.org/en-US/docs/DOM/Node.contains
DOM.Node.prototype.contains = function (otherNode) {
// DDOPSON-2012-08-16 -- This implementation is stolen from Sizzle's
// implementation of 'contains' (around line 1402).
// We actually can't call Sizzle.contains directly:
// * Because we define Node.contains, Sizzle will configure it's own
// "contains" method to call us. (it thinks we are a native browser
// implementation of "contains")
// * Thus, if we called Sizzle.contains, it would form an infinite loop.
// Instead we use Sizzle's fallback implementation of "contains" based on
// "compareDocumentPosition".
return !!(this.compareDocumentPosition(otherNode) & 16);
};
// Support for opacity style property.
Object.defineProperty(DOM.CSSStyleDeclaration.prototype, 'opacity', {
get: function get() {
var opacity = this.getPropertyValue('opacity');
return _Number$isFinite(opacity) ? opacity.toString() : '';
},
set: function set(opacity) {
if (opacity === null || opacity === undefined || opacity === '') this.removeProperty('opacity');else {
var value = parseFloat(opacity);
if (isFinite(value)) this._setProperty('opacity', value);
}
}
});
// Wrap dispatchEvent to support _windowInScope and error handling.
var jsdomDispatchEvent = DOM.EventTarget.prototype.dispatchEvent;
DOM.EventTarget.prototype.dispatchEvent = function (event) {
// Could be node, window or document
var document = this._ownerDocument || this.document || this;
var window = document.defaultView;
// Fail miserably on objects that don't have ownerDocument: nodes and XHR
// request have those
var browser = window.browser;
browser.emit('event', event, this);
var originalInScope = browser._windowInScope;
try {
// The current window, postMessage and window.close need this
browser._windowInScope = window;
// Inline event handlers rely on window.event
window.event = event;
return jsdomDispatchEvent.call(this, event);
} finally {
delete window.event;
browser._windowInScope = originalInScope;
}
};
// Fix resource loading to keep track of in-progress requests. Need this to wait
// for all resources (mainly JavaScript) to complete loading before terminating
// browser.wait.
resourceLoader.load = function (element, href, callback) {
var _this2 = this;
var document = element.ownerDocument;
var window = document.defaultView;
var tagName = element.tagName.toLowerCase();
var loadResource = document.implementation._hasFeature('FetchExternalResources', tagName);
var url = resourceLoader.resolveResourceUrl(document, href);
if (loadResource) {
(function () {
// This guarantees that all scripts are executed in order, must add to the
// JSDOM queue before we add to the Zombie event queue.
var enqueued = _this2.enqueue(element, url, callback && callback.bind(element));
var request = new Fetch.Request(url);
window._eventQueue.http(request, function (error, response) {
// Since this is used by resourceLoader that doesn't check the response,
// we're responsible to turn anything other than 2xx/3xx into an error
if (error) enqueued(new Error('Network error'));else if (response.status >= 400) enqueued(new Error('Server returned status code ' + response.status + ' from ' + url));else response._consume().then(function (buffer) {
response.body = buffer;
enqueued(null, buffer);
});
});
})();
}
};
// Fix residual Node bug. See https://github.com/joyent/node/pull/14146
var jsdomResolveHref = Utils.resolveHref;
Utils.resolveHref = function (baseUrl, href) {
var pattern = /file:?/;
var protocol = URL.parse(baseUrl).protocol;
var original = URL.parse(href);
var resolved = URL.parse(jsdomResolveHref(baseUrl, href));
if (!pattern.test(protocol) && pattern.test(original.protocol) && !original.host && resolved.host) return URL.format(original);else return URL.format(resolved);
};
//# sourceMappingURL=jsdom_patches.js.map