happy-dom 14.3.9 → 14.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of happy-dom might be problematic. Click here for more details.

Files changed (67) hide show
  1. package/cjs/PropertySymbol.cjs +2 -1
  2. package/cjs/PropertySymbol.cjs.map +1 -1
  3. package/cjs/PropertySymbol.d.ts +1 -0
  4. package/cjs/PropertySymbol.d.ts.map +1 -1
  5. package/cjs/css/declaration/css-parser/CSSStyleDeclarationCSSParser.cjs +20 -9
  6. package/cjs/css/declaration/css-parser/CSSStyleDeclarationCSSParser.cjs.map +1 -1
  7. package/cjs/css/declaration/css-parser/CSSStyleDeclarationCSSParser.d.ts +10 -1
  8. package/cjs/css/declaration/css-parser/CSSStyleDeclarationCSSParser.d.ts.map +1 -1
  9. package/cjs/css/declaration/element-style/CSSStyleDeclarationElementStyle.cjs +30 -17
  10. package/cjs/css/declaration/element-style/CSSStyleDeclarationElementStyle.cjs.map +1 -1
  11. package/cjs/css/declaration/element-style/CSSStyleDeclarationElementStyle.d.ts +1 -0
  12. package/cjs/css/declaration/element-style/CSSStyleDeclarationElementStyle.d.ts.map +1 -1
  13. package/cjs/css/declaration/property-manager/CSSStyleDeclarationPropertyManager.cjs +5 -4
  14. package/cjs/css/declaration/property-manager/CSSStyleDeclarationPropertyManager.cjs.map +1 -1
  15. package/cjs/css/declaration/property-manager/CSSStyleDeclarationPropertyManager.d.ts.map +1 -1
  16. package/cjs/nodes/html-iframe-element/HTMLIFrameElement.cjs +9 -6
  17. package/cjs/nodes/html-iframe-element/HTMLIFrameElement.cjs.map +1 -1
  18. package/cjs/nodes/html-iframe-element/HTMLIFrameElement.d.ts +4 -4
  19. package/cjs/nodes/html-iframe-element/HTMLIFrameElement.d.ts.map +1 -1
  20. package/cjs/nodes/html-iframe-element/HTMLIFrameElementNamedNodeMap.cjs +43 -2
  21. package/cjs/nodes/html-iframe-element/HTMLIFrameElementNamedNodeMap.cjs.map +1 -1
  22. package/cjs/nodes/html-iframe-element/HTMLIFrameElementNamedNodeMap.d.ts.map +1 -1
  23. package/cjs/nodes/html-link-element/HTMLLinkElementStyleSheetLoader.cjs +4 -3
  24. package/cjs/nodes/html-link-element/HTMLLinkElementStyleSheetLoader.cjs.map +1 -1
  25. package/cjs/nodes/html-link-element/HTMLLinkElementStyleSheetLoader.d.ts.map +1 -1
  26. package/cjs/nodes/html-style-element/HTMLStyleElement.cjs +44 -9
  27. package/cjs/nodes/html-style-element/HTMLStyleElement.cjs.map +1 -1
  28. package/cjs/nodes/html-style-element/HTMLStyleElement.d.ts +17 -0
  29. package/cjs/nodes/html-style-element/HTMLStyleElement.d.ts.map +1 -1
  30. package/lib/PropertySymbol.d.ts +1 -0
  31. package/lib/PropertySymbol.d.ts.map +1 -1
  32. package/lib/PropertySymbol.js +1 -0
  33. package/lib/PropertySymbol.js.map +1 -1
  34. package/lib/css/declaration/css-parser/CSSStyleDeclarationCSSParser.d.ts +10 -1
  35. package/lib/css/declaration/css-parser/CSSStyleDeclarationCSSParser.d.ts.map +1 -1
  36. package/lib/css/declaration/css-parser/CSSStyleDeclarationCSSParser.js +20 -9
  37. package/lib/css/declaration/css-parser/CSSStyleDeclarationCSSParser.js.map +1 -1
  38. package/lib/css/declaration/element-style/CSSStyleDeclarationElementStyle.d.ts +1 -0
  39. package/lib/css/declaration/element-style/CSSStyleDeclarationElementStyle.d.ts.map +1 -1
  40. package/lib/css/declaration/element-style/CSSStyleDeclarationElementStyle.js +30 -17
  41. package/lib/css/declaration/element-style/CSSStyleDeclarationElementStyle.js.map +1 -1
  42. package/lib/css/declaration/property-manager/CSSStyleDeclarationPropertyManager.d.ts.map +1 -1
  43. package/lib/css/declaration/property-manager/CSSStyleDeclarationPropertyManager.js +5 -4
  44. package/lib/css/declaration/property-manager/CSSStyleDeclarationPropertyManager.js.map +1 -1
  45. package/lib/nodes/html-iframe-element/HTMLIFrameElement.d.ts +4 -4
  46. package/lib/nodes/html-iframe-element/HTMLIFrameElement.d.ts.map +1 -1
  47. package/lib/nodes/html-iframe-element/HTMLIFrameElement.js +9 -6
  48. package/lib/nodes/html-iframe-element/HTMLIFrameElement.js.map +1 -1
  49. package/lib/nodes/html-iframe-element/HTMLIFrameElementNamedNodeMap.d.ts.map +1 -1
  50. package/lib/nodes/html-iframe-element/HTMLIFrameElementNamedNodeMap.js +43 -2
  51. package/lib/nodes/html-iframe-element/HTMLIFrameElementNamedNodeMap.js.map +1 -1
  52. package/lib/nodes/html-link-element/HTMLLinkElementStyleSheetLoader.d.ts.map +1 -1
  53. package/lib/nodes/html-link-element/HTMLLinkElementStyleSheetLoader.js +4 -3
  54. package/lib/nodes/html-link-element/HTMLLinkElementStyleSheetLoader.js.map +1 -1
  55. package/lib/nodes/html-style-element/HTMLStyleElement.d.ts +17 -0
  56. package/lib/nodes/html-style-element/HTMLStyleElement.d.ts.map +1 -1
  57. package/lib/nodes/html-style-element/HTMLStyleElement.js +45 -11
  58. package/lib/nodes/html-style-element/HTMLStyleElement.js.map +1 -1
  59. package/package.json +1 -1
  60. package/src/PropertySymbol.ts +1 -0
  61. package/src/css/declaration/css-parser/CSSStyleDeclarationCSSParser.ts +27 -12
  62. package/src/css/declaration/element-style/CSSStyleDeclarationElementStyle.ts +36 -16
  63. package/src/css/declaration/property-manager/CSSStyleDeclarationPropertyManager.ts +5 -4
  64. package/src/nodes/html-iframe-element/HTMLIFrameElement.ts +8 -6
  65. package/src/nodes/html-iframe-element/HTMLIFrameElementNamedNodeMap.ts +60 -0
  66. package/src/nodes/html-link-element/HTMLLinkElementStyleSheetLoader.ts +4 -6
  67. package/src/nodes/html-style-element/HTMLStyleElement.ts +49 -8
@@ -132,15 +132,23 @@ export default class CSSStyleDeclarationElementStyle {
132
132
  if (sheet) {
133
133
  this.parseCSSRules({
134
134
  elements: documentElements,
135
+ rootElement:
136
+ documentElements[0].element[PropertySymbol.tagName] === 'HTML'
137
+ ? documentElements[0]
138
+ : null,
135
139
  cssRules: sheet.cssRules
136
140
  });
137
141
  }
138
142
  }
139
143
 
140
- for (const styleSheet of this.element[PropertySymbol.ownerDocument].adoptedStyleSheets) {
144
+ for (const sheet of this.element[PropertySymbol.ownerDocument].adoptedStyleSheets) {
141
145
  this.parseCSSRules({
142
146
  elements: documentElements,
143
- cssRules: styleSheet.cssRules
147
+ rootElement:
148
+ documentElements[0].element[PropertySymbol.tagName] === 'HTML'
149
+ ? documentElements[0]
150
+ : null,
151
+ cssRules: sheet.cssRules
144
152
  });
145
153
  }
146
154
 
@@ -170,10 +178,10 @@ export default class CSSStyleDeclarationElementStyle {
170
178
  }
171
179
  }
172
180
 
173
- for (const styleSheet of shadowRoot.adoptedStyleSheets) {
181
+ for (const sheet of shadowRoot.adoptedStyleSheets) {
174
182
  this.parseCSSRules({
175
183
  elements: shadowRootElements,
176
- cssRules: styleSheet.cssRules,
184
+ cssRules: sheet.cssRules,
177
185
  hostElement: styleAndElement
178
186
  });
179
187
  }
@@ -190,7 +198,7 @@ export default class CSSStyleDeclarationElementStyle {
190
198
  // Concatenates all parent element CSS to one string.
191
199
  const targetElement = parentElements[parentElements.length - 1];
192
200
  const propertyManager = new CSSStyleDeclarationPropertyManager();
193
- const cssVariables: { [k: string]: string } = {};
201
+ const cssProperties: { [k: string]: string } = {};
194
202
  let rootFontSize: string | number = 16;
195
203
  let parentFontSize: string | number = 16;
196
204
 
@@ -239,24 +247,27 @@ export default class CSSStyleDeclarationElementStyle {
239
247
  const elementStyleAttribute = (<Element>parentElement.element)[PropertySymbol.attributes][
240
248
  'style'
241
249
  ];
250
+
242
251
  if (elementStyleAttribute) {
243
252
  elementCSSText += elementStyleAttribute[PropertySymbol.value];
244
253
  }
245
254
 
246
- CSSStyleDeclarationCSSParser.parse(elementCSSText, (name, value, important) => {
247
- const isCSSVariable = name.startsWith('--');
255
+ const rulesAndProperties = CSSStyleDeclarationCSSParser.parse(elementCSSText);
256
+ const rules = rulesAndProperties.rules;
257
+
258
+ Object.assign(cssProperties, rulesAndProperties.properties);
259
+
260
+ for (const { name, value, important } of rules) {
248
261
  if (
249
- isCSSVariable ||
250
262
  CSSStyleDeclarationElementInheritedProperties[name] ||
251
263
  parentElement === targetElement
252
264
  ) {
253
- const cssValue = this.parseCSSVariablesInValue(value, cssVariables);
254
- if (cssValue && (!propertyManager.get(name)?.important || important)) {
255
- propertyManager.set(name, cssValue, important);
265
+ const parsedValue = this.parseCSSVariablesInValue(value.trim(), cssProperties);
256
266
 
257
- if (isCSSVariable) {
258
- cssVariables[name] = cssValue;
259
- } else if (name === 'font' || name === 'font-size') {
267
+ if (parsedValue && (!propertyManager.get(name)?.important || important)) {
268
+ propertyManager.set(name, parsedValue, important);
269
+
270
+ if (name === 'font' || name === 'font-size') {
260
271
  const fontSize = propertyManager.properties['font-size'];
261
272
  if (fontSize !== null) {
262
273
  const parsedValue = this.parseMeasurementsInValue({
@@ -274,7 +285,7 @@ export default class CSSStyleDeclarationElementStyle {
274
285
  }
275
286
  }
276
287
  }
277
- });
288
+ }
278
289
  }
279
290
 
280
291
  for (const name of CSSStyleDeclarationElementMeasurementProperties) {
@@ -302,11 +313,13 @@ export default class CSSStyleDeclarationElementStyle {
302
313
  * @param options Options.
303
314
  * @param options.elements Elements.
304
315
  * @param options.cssRules CSS rules.
316
+ * @param options.rootElement Root element.
305
317
  * @param [options.hostElement] Host element.
306
318
  */
307
319
  private parseCSSRules(options: {
308
320
  cssRules: CSSRule[];
309
- elements: Array<IStyleAndElement>;
321
+ elements: IStyleAndElement[];
322
+ rootElement?: IStyleAndElement;
310
323
  hostElement?: IStyleAndElement;
311
324
  }): void {
312
325
  if (!options.elements.length) {
@@ -326,6 +339,13 @@ export default class CSSStyleDeclarationElementStyle {
326
339
  priorityWeight: 0
327
340
  });
328
341
  }
342
+ } else if (selectorText.startsWith(':root')) {
343
+ if (options.rootElement) {
344
+ options.rootElement.cssTexts.push({
345
+ cssText: (<CSSStyleRule>rule)[PropertySymbol.cssText],
346
+ priorityWeight: 0
347
+ });
348
+ }
329
349
  } else {
330
350
  for (const element of options.elements) {
331
351
  const match = QuerySelector.matches(<Element>element.element, selectorText, {
@@ -30,11 +30,12 @@ export default class CSSStyleDeclarationPropertyManager {
30
30
  */
31
31
  constructor(options?: { cssText?: string }) {
32
32
  if (options?.cssText) {
33
- CSSStyleDeclarationCSSParser.parse(options.cssText, (name, value, important) => {
34
- if (important || !this.get(name)?.important) {
35
- this.set(name, value, important);
33
+ const { rules } = CSSStyleDeclarationCSSParser.parse(options.cssText);
34
+ for (const rule of rules) {
35
+ if (rule.important || !this.get(rule.name)?.important) {
36
+ this.set(rule.name, rule.value, rule.important);
36
37
  }
37
- });
38
+ }
38
39
  }
39
40
  }
40
41
 
@@ -9,6 +9,7 @@ import HTMLIFrameElementNamedNodeMap from './HTMLIFrameElementNamedNodeMap.js';
9
9
  import CrossOriginBrowserWindow from '../../window/CrossOriginBrowserWindow.js';
10
10
  import IBrowserFrame from '../../browser/types/IBrowserFrame.js';
11
11
  import HTMLIFrameElementPageLoader from './HTMLIFrameElementPageLoader.js';
12
+ import DOMTokenList from '../../dom-token-list/DOMTokenList.js';
12
13
 
13
14
  /**
14
15
  * HTML Iframe Element.
@@ -23,7 +24,7 @@ export default class HTMLIFrameElement extends HTMLElement {
23
24
 
24
25
  // Internal properties
25
26
  public override [PropertySymbol.attributes]: NamedNodeMap;
26
-
27
+ public [PropertySymbol.sandbox]: DOMTokenList = null;
27
28
  // Private properties
28
29
  #contentWindowContainer: { window: BrowserWindow | CrossOriginBrowserWindow | null } = {
29
30
  window: null
@@ -140,14 +141,15 @@ export default class HTMLIFrameElement extends HTMLElement {
140
141
  *
141
142
  * @returns Sandbox.
142
143
  */
143
- public get sandbox(): string {
144
- return this.getAttribute('sandbox') || '';
144
+ public get sandbox(): DOMTokenList {
145
+ if (!this[PropertySymbol.sandbox]) {
146
+ this[PropertySymbol.sandbox] = new DOMTokenList(this, 'sandbox');
147
+ }
148
+ return <DOMTokenList>this[PropertySymbol.sandbox];
145
149
  }
146
150
 
147
151
  /**
148
152
  * Sets sandbox.
149
- *
150
- * @param sandbox Sandbox.
151
153
  */
152
154
  public set sandbox(sandbox: string) {
153
155
  this.setAttribute('sandbox', sandbox);
@@ -163,7 +165,7 @@ export default class HTMLIFrameElement extends HTMLElement {
163
165
  }
164
166
 
165
167
  /**
166
- * Sets sandbox.
168
+ * Sets srcdoc.
167
169
  *
168
170
  * @param srcdoc Srcdoc.
169
171
  */
@@ -3,6 +3,23 @@ import Element from '../element/Element.js';
3
3
  import HTMLElementNamedNodeMap from '../html-element/HTMLElementNamedNodeMap.js';
4
4
  import HTMLIFrameElementPageLoader from './HTMLIFrameElementPageLoader.js';
5
5
  import * as PropertySymbol from '../../PropertySymbol.js';
6
+ import DOMTokenList from '../../dom-token-list/DOMTokenList.js';
7
+
8
+ const SANDBOX_FLAGS = [
9
+ 'allow-downloads',
10
+ 'allow-forms',
11
+ 'allow-modals',
12
+ 'allow-orientation-lock',
13
+ 'allow-pointer-lock',
14
+ 'allow-popups',
15
+ 'allow-popups-to-escape-sandbox',
16
+ 'allow-presentation',
17
+ 'allow-same-origin',
18
+ 'allow-scripts',
19
+ 'allow-top-navigation',
20
+ 'allow-top-navigation-by-user-activation',
21
+ 'allow-top-navigation-to-custom-protocols'
22
+ ];
6
23
 
7
24
  /**
8
25
  * Named Node Map.
@@ -37,6 +54,49 @@ export default class HTMLIFrameElementNamedNodeMap extends HTMLElementNamedNodeM
37
54
  this.#pageLoader.loadPage();
38
55
  }
39
56
 
57
+ if (item[PropertySymbol.name] === 'sandbox') {
58
+ if (!this[PropertySymbol.ownerElement][PropertySymbol.sandbox]) {
59
+ this[PropertySymbol.ownerElement][PropertySymbol.sandbox] = new DOMTokenList(
60
+ this[PropertySymbol.ownerElement],
61
+ 'sandbox'
62
+ );
63
+ } else {
64
+ this[PropertySymbol.ownerElement][PropertySymbol.sandbox][PropertySymbol.updateIndices]();
65
+ }
66
+
67
+ this.#validateSandboxFlags();
68
+ }
69
+
40
70
  return replacedAttribute || null;
41
71
  }
72
+
73
+ /**
74
+ *
75
+ * @param tokens
76
+ * @param vconsole
77
+ */
78
+ #validateSandboxFlags(): void {
79
+ const window =
80
+ this[PropertySymbol.ownerElement][PropertySymbol.ownerDocument][PropertySymbol.ownerWindow];
81
+ const values = this[PropertySymbol.ownerElement][PropertySymbol.sandbox].values();
82
+ const invalidFlags: string[] = [];
83
+
84
+ for (const token of values) {
85
+ if (!SANDBOX_FLAGS.includes(token)) {
86
+ invalidFlags.push(token);
87
+ }
88
+ }
89
+
90
+ if (invalidFlags.length === 1) {
91
+ window.console.error(
92
+ `Error while parsing the 'sandbox' attribute: '${invalidFlags[0]}' is an invalid sandbox flag.`
93
+ );
94
+ } else if (invalidFlags.length > 1) {
95
+ window.console.error(
96
+ `Error while parsing the 'sandbox' attribute: '${invalidFlags.join(
97
+ `', '`
98
+ )}' are invalid sandbox flags.`
99
+ );
100
+ }
101
+ }
42
102
  }
@@ -38,6 +38,7 @@ export default class HTMLLinkElementStyleSheetLoader {
38
38
  public async loadStyleSheet(url: string | null, rel: string | null): Promise<void> {
39
39
  const element = this.#element;
40
40
  const browserSettings = this.#browserFrame.page.context.browser.settings;
41
+ const window = element[PropertySymbol.ownerDocument][PropertySymbol.ownerWindow];
41
42
 
42
43
  if (
43
44
  !url ||
@@ -50,10 +51,7 @@ export default class HTMLLinkElementStyleSheetLoader {
50
51
 
51
52
  let absoluteURL: string;
52
53
  try {
53
- absoluteURL = new URL(
54
- url,
55
- element[PropertySymbol.ownerDocument][PropertySymbol.ownerWindow].location.href
56
- ).href;
54
+ absoluteURL = new URL(url, window.location.href).href;
57
55
  } catch (error) {
58
56
  return;
59
57
  }
@@ -79,10 +77,10 @@ export default class HTMLLinkElementStyleSheetLoader {
79
77
 
80
78
  const resourceFetch = new ResourceFetch({
81
79
  browserFrame: this.#browserFrame,
82
- window: element[PropertySymbol.ownerDocument][PropertySymbol.ownerWindow]
80
+ window: window
83
81
  });
84
82
  const readyStateManager = (<{ [PropertySymbol.readyStateManager]: DocumentReadyStateManager }>(
85
- (<unknown>element[PropertySymbol.ownerDocument][PropertySymbol.ownerWindow])
83
+ (<unknown>window)
86
84
  ))[PropertySymbol.readyStateManager];
87
85
 
88
86
  this.#loadedStyleSheetURL = absoluteURL;
@@ -1,6 +1,7 @@
1
1
  import CSSStyleSheet from '../../css/CSSStyleSheet.js';
2
2
  import * as PropertySymbol from '../../PropertySymbol.js';
3
3
  import HTMLElement from '../html-element/HTMLElement.js';
4
+ import Node from '../node/Node.js';
4
5
 
5
6
  /**
6
7
  * HTML Style Element.
@@ -17,14 +18,7 @@ export default class HTMLStyleElement extends HTMLElement {
17
18
  * @returns CSS style sheet.
18
19
  */
19
20
  public get sheet(): CSSStyleSheet {
20
- if (!this[PropertySymbol.isConnected]) {
21
- return null;
22
- }
23
- if (!this[PropertySymbol.sheet]) {
24
- this[PropertySymbol.sheet] = new CSSStyleSheet();
25
- }
26
- this[PropertySymbol.sheet].replaceSync(this.textContent);
27
- return this[PropertySymbol.sheet];
21
+ return this[PropertySymbol.sheet] ? this[PropertySymbol.sheet] : null;
28
22
  }
29
23
 
30
24
  /**
@@ -84,4 +78,51 @@ export default class HTMLStyleElement extends HTMLElement {
84
78
  this.setAttribute('disabled', '');
85
79
  }
86
80
  }
81
+
82
+ /**
83
+ * @override
84
+ */
85
+ public override appendChild(node: Node): Node {
86
+ const returnValue = super.appendChild(node);
87
+ if (this[PropertySymbol.sheet]) {
88
+ this[PropertySymbol.sheet].replaceSync(this.textContent);
89
+ }
90
+ return returnValue;
91
+ }
92
+
93
+ /**
94
+ * @override
95
+ */
96
+ public override removeChild(node: Node): Node {
97
+ const returnValue = super.removeChild(node);
98
+ if (this[PropertySymbol.sheet]) {
99
+ this[PropertySymbol.sheet].replaceSync(this.textContent);
100
+ }
101
+ return returnValue;
102
+ }
103
+
104
+ /**
105
+ * @override
106
+ */
107
+ public override insertBefore(newNode: Node, referenceNode: Node | null): Node {
108
+ const returnValue = super.insertBefore(newNode, referenceNode);
109
+ if (this[PropertySymbol.sheet]) {
110
+ this[PropertySymbol.sheet].replaceSync(this.textContent);
111
+ }
112
+ return returnValue;
113
+ }
114
+
115
+ /**
116
+ * @override
117
+ */
118
+ public override [PropertySymbol.connectToNode](parentNode: Node = null): void {
119
+ super[PropertySymbol.connectToNode](parentNode);
120
+
121
+ if (parentNode) {
122
+ this[PropertySymbol.sheet] = new CSSStyleSheet();
123
+ this[PropertySymbol.sheet].replaceSync(this.textContent);
124
+ } else {
125
+ this[PropertySymbol.sheet] = null;
126
+ }
127
+ }
87
128
  }