Skip to content

Commit

Permalink
#344@trivial: Adds cache to HTMLStyleElement.sheet.
Browse files Browse the repository at this point in the history
  • Loading branch information
capricorn86 committed Oct 5, 2022
1 parent c881207 commit 53046fa
Show file tree
Hide file tree
Showing 8 changed files with 106 additions and 42 deletions.
34 changes: 12 additions & 22 deletions packages/happy-dom/src/css/CSSStyleSheet.ts
Expand Up @@ -5,7 +5,7 @@ import CSSRule from './CSSRule';
import MediaList from './MediaList';

/**
* Attr node interface.
* CSS StyleSheet.
*
* Reference:
* https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet.
Expand All @@ -16,20 +16,16 @@ export default class CSSStyleSheet {
public namespaceURI: string = null;
public readonly cssRules: CSSRule[] = [];

// Constructable Stylesheets is a new feature that only Blink supports:
// https://wicg.github.io/construct-stylesheets/
// TODO: Not fully implemented.
// TODO: MediaList is not fully implemented.
public media: MediaList | string;
public title: string;
public alternate: boolean;
public disabled: boolean;
private _currentText: string = null;

/**
* Constructor.
*
* Constructable Stylesheets is a new feature that only Blink supports:
* https://wicg.github.io/construct-stylesheets/.
*
* @param [options] Options.
* @param [options.media] Media.
* @param [options.title] Title.
Expand All @@ -51,9 +47,7 @@ export default class CSSStyleSheet {
/**
* Inserts a rule.
*
* Constructable Stylesheets is a new feature that only Blink supports:
* https://wicg.github.io/construct-stylesheets/.
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/insertRule
* @param rule Rule.
* @param [index] Index.
* @returns The newly inserterted rule's index.
Expand All @@ -79,8 +73,7 @@ export default class CSSStyleSheet {
DOMExceptionNameEnum.indexSizeError
);
}
this.cssRules.splice(index, 0);
this.cssRules.push(rules[0]);
this.cssRules.splice(index, 0, rules[0]);
return index;
}

Expand All @@ -94,9 +87,7 @@ export default class CSSStyleSheet {
/**
* Removes a rule.
*
* Constructable Stylesheets is a new feature that only Blink supports:
* https://wicg.github.io/construct-stylesheets/.
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/deleteRule
* @param index Index.
*/
public deleteRule(index: number): void {
Expand All @@ -106,9 +97,7 @@ export default class CSSStyleSheet {
/**
* Replaces all CSS rules.
*
* Constructable Stylesheets is a new feature that only Blink supports:
* https://wicg.github.io/construct-stylesheets/.
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/replace
* @param text CSS text.
* @returns Promise.
*/
Expand All @@ -119,12 +108,13 @@ export default class CSSStyleSheet {
/**
* Replaces all CSS rules.
*
* Constructable Stylesheets is a new feature that only Blink supports:
* https://wicg.github.io/construct-stylesheets/.
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/replaceSync
* @param text CSS text.
*/
public replaceSync(text: string): void {
(<CSSRule[]>this.cssRules) = CSSParser.parseFromString(this, text);
if (this._currentText !== text) {
this._currentText = text;
(<CSSRule[]>this.cssRules) = CSSParser.parseFromString(this, text);
}
}
}
Expand Up @@ -255,7 +255,10 @@ export default class CSSStyleDeclarationPropertyGetParser {
}

/**
* Returns border image.
*
* @param properties Properties.
* @returns Property value
*/
public static getBorderImage(properties: {
[k: string]: ICSSStyleDeclarationPropertyValue;
Expand Down
Expand Up @@ -4,6 +4,15 @@ import CSSStyleDeclarationValueParser from './CSSStyleDeclarationValueParser';
import CSSStyleDeclarationPropertyGetParser from './CSSStyleDeclarationPropertyGetParser';
import CSSStyleDeclarationCSSParser from './CSSStyleDeclarationCSSParser';

const TO_STRING_SHORTHAND_PROPERTIES = [
['margin'],
['padding'],
['border', ['border-width', 'border-style', 'border-color', 'border-image']],
['border-radius'],
['background', 'background-position'],
['font']
];

/**
* Computed this.properties property parser.
*/
Expand Down Expand Up @@ -465,6 +474,9 @@ export default class CSSStyleDeclarationPropertyManager {
case 'text-transform':
properties = CSSStyleDeclarationPropertySetParser.getTextTransform(value, important);
break;
case 'visibility':
properties = CSSStyleDeclarationPropertySetParser.getVisibility(value, important);
break;
default:
const trimmedValue = value.trim();
if (trimmedValue) {
Expand Down Expand Up @@ -526,33 +538,26 @@ export default class CSSStyleDeclarationPropertyManager {
const clone = this.clone();
const properties = {};

for (const fallbackNames of [
['margin'],
['padding'],
['border', ['border-width', 'border-style', 'border-color', 'border-image']],
['border-radius'],
['background', 'background-position'],
['font']
]) {
for (const fallbackName of fallbackNames) {
if (Array.isArray(fallbackName)) {
for (const shorthandPropertyGroup of TO_STRING_SHORTHAND_PROPERTIES) {
for (const shorthandProperty of shorthandPropertyGroup) {
if (Array.isArray(shorthandProperty)) {
let isMatch = false;
for (const childFallbackName of fallbackName) {
const property = clone.get(childFallbackName);
for (const childShorthandProperty of shorthandProperty) {
const property = clone.get(childShorthandProperty);
if (property) {
properties[childFallbackName] = property;
clone.remove(childFallbackName);
properties[childShorthandProperty] = property;
clone.remove(childShorthandProperty);
isMatch = true;
}
}
if (isMatch) {
break;
}
} else {
const property = clone.get(fallbackName);
const property = clone.get(shorthandProperty);
if (property) {
properties[fallbackName] = property;
clone.remove(fallbackName);
properties[shorthandProperty] = property;
clone.remove(shorthandProperty);
break;
}
}
Expand Down
Expand Up @@ -89,6 +89,7 @@ const TEXT_TRANSFORM = [
'full-width',
'full-size-kana'
];
const VISIBILITY = ['visible', 'hidden', 'collapse'];

/**
* Computed style property parser.
Expand Down Expand Up @@ -2992,4 +2993,34 @@ export default class CSSStyleDeclarationPropertySetParser {
}
return null;
}

/**
* Returns visibility.
*
* @param value Value.
* @param important Important.
* @returns Property
*/
public static getVisibility(
value: string,
important: boolean
): {
[key: string]: ICSSStyleDeclarationPropertyValue;
} {
const variable = CSSStyleDeclarationValueParser.getVariable(value);
if (variable) {
return { visibility: { value: variable, important } };
}

const lowerValue = value.toLowerCase();
const parsedValue =
CSSStyleDeclarationValueParser.getGlobal(lowerValue) ||
(VISIBILITY.includes(lowerValue) && lowerValue);
if (parsedValue) {
return {
visibility: { value: parsedValue, important }
};
}
return null;
}
}
6 changes: 4 additions & 2 deletions packages/happy-dom/src/file/Blob.ts
Expand Up @@ -110,7 +110,6 @@ export default class Blob implements IBlob {
return blob;
}


/**
* Returns a Promise that resolves to a ArrayBuffer.
*
Expand All @@ -120,8 +119,11 @@ export default class Blob implements IBlob {
// Reference:
// https://github.com/web-std/io/blob/c88170bf24f064adfbb3586a21fb76650ca5a9ab/packages/blob/src/blob.js#L139-L148
// https://stackoverflow.com/questions/8609289/convert-a-binary-nodejs-buffer-to-javascript-arraybuffer
/**
*
*/
public async arrayBuffer(): Promise<ArrayBuffer> {
return new Uint8Array(this._buffer).buffer
return new Uint8Array(this._buffer).buffer;
}

/**
Expand Down
3 changes: 3 additions & 0 deletions packages/happy-dom/test/css/CSSStyleSheet.test.ts
Expand Up @@ -14,6 +14,9 @@ describe('CSSStyleSheet', () => {
cssStyleSheet.insertRule('div { background-color: green }');
cssStyleSheet.insertRule('span { background-color: green }');
expect(cssStyleSheet.insertRule('button { background-color: green }', 1)).toBe(1);
expect(cssStyleSheet.cssRules[0].cssText).toBe('div { background-color: green; }');
expect(cssStyleSheet.cssRules[1].cssText).toBe('button { background-color: green; }');
expect(cssStyleSheet.cssRules[2].cssText).toBe('span { background-color: green; }');
});

it('Inserts a rule.', () => {
Expand Down
Expand Up @@ -1693,7 +1693,7 @@ describe('CSSStyleDeclaration', () => {
expect(declaration.font).toBe('small-caps bold 24px / 1 sans-serif');

element.setAttribute('style', 'font: caption');
debugger;

expect(declaration.font).toBe('caption');
});
});
Expand Down Expand Up @@ -1880,6 +1880,27 @@ describe('CSSStyleDeclaration', () => {
});
});

describe('get visibility()', () => {
it('Returns style property.', () => {
const declaration = new CSSStyleDeclaration(element);

for (const value of [
'var(--test-variable)',
'inherit',
'initial',
'revert',
'unset',
'visible',
'hidden',
'collapse'
]) {
element.setAttribute('style', `visibility: ${value}`);

expect(declaration.visibility).toBe(value);
}
});
});

describe('get length()', () => {
it('Returns length when of styles on element.', () => {
const declaration = new CSSStyleDeclaration(element);
Expand Down
Expand Up @@ -57,11 +57,20 @@ describe('HTMLStyleElement', () => {
const textNode = document.createTextNode(
'body { background-color: red }\ndiv { background-color: green }'
);

element.appendChild(textNode);
document.head.appendChild(element);

expect(element.sheet.cssRules.length).toBe(2);
expect(element.sheet.cssRules[0].cssText).toBe('body { background-color: red; }');
expect(element.sheet.cssRules[1].cssText).toBe('div { background-color: green; }');

element.sheet.insertRule('html { background-color: blue }', 0);

expect(element.sheet.cssRules.length).toBe(3);
expect(element.sheet.cssRules[0].cssText).toBe('html { background-color: blue; }');
expect(element.sheet.cssRules[1].cssText).toBe('body { background-color: red; }');
expect(element.sheet.cssRules[2].cssText).toBe('div { background-color: green; }');
});
});
});

0 comments on commit 53046fa

Please sign in to comment.