Skip to content

Commit 383e2e2

Browse files
ExE-BossTimothyGu
andcommitted
Address review comments
Co-authored-by: Co-authored-by: Timothy Gu <timothygu99@gmail.com>
1 parent c3d2de8 commit 383e2e2

File tree

5 files changed

+82
-51
lines changed

5 files changed

+82
-51
lines changed

README.md

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,44 @@ A Node JS implementation of the CSS Object Model [CSSStyleDeclaration interface]
44

55
[![NpmVersion](https://img.shields.io/npm/v/cssstyle.svg)](https://www.npmjs.com/package/cssstyle) [![Build Status](https://travis-ci.org/jsdom/cssstyle.svg?branch=master)](https://travis-ci.org/jsdom/cssstyle) [![codecov](https://codecov.io/gh/jsdom/cssstyle/branch/master/graph/badge.svg)](https://codecov.io/gh/jsdom/cssstyle)
66

7-
---
7+
## Background
88

9-
#### Background
9+
This package is an extension of the CSSStyleDeclaration class in Nikita Vasilyev's [CSSOM](https://github.com/NV/CSSOM) with added support for CSS 2 & 3 properties. The primary use case is for testing browser code in a Node environment.
1010

11-
This package is an extension of the CSSStyleDeclaration class in Nikita Vasilyev's [CSSOM](https://github.com/NV/CSSOM) with added support for CSS 2 & 3 properties. The primary use case is for testing browser code in a Node environment.
12-
13-
It was originally created by Chad Walker, it is now maintaind by Jon Sakas and other open source contributors.
11+
It was originally created by Chad Walker, it is now maintained by Jon Sakas and other open source contributors.
1412

1513
Bug reports and pull requests are welcome.
14+
15+
## APIs
16+
17+
This package exposes two flavors of the `CSSStyleDeclaration` interface depending on the imported module.
18+
19+
### `cssstyle` module
20+
21+
This module default-exports the `CSSStyleDeclaration` interface constructor, with the change that it can be constructed and takes an `onChangeCallback` optional parameter:
22+
23+
```ts
24+
export = class CSSStyleDeclaration {
25+
/**
26+
* @param onChangeCallback The callback that is invoked whenever a property changes.
27+
*/
28+
constructor(onChangeCallback?: ((cssText: string) => void) | null);
29+
}
30+
```
31+
32+
### `cssstyle/webidl2js-wrapper` module
33+
34+
This module exports the `CSSStyleDeclaration` [interface wrapper API](https://github.com/jsdom/webidl2js#for-interfaces) generated by [webidl2js](https://github.com/jsdom/webidl2js).
35+
36+
#### `privateData`
37+
38+
The `privateData` argument takes the following properties:
39+
40+
```ts
41+
interface CSSStyleDeclarationPrivateData {
42+
/**
43+
* The callback that is invoked whenever a property changes.
44+
*/
45+
onChangeCallback?: ((cssText: string) => void) | null
46+
}
47+
```

index.js

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,24 @@ const sharedGlobalObject = {};
66
webidlWrapper.install(sharedGlobalObject);
77

88
const origCSSStyleDeclaration = sharedGlobalObject.CSSStyleDeclaration;
9-
function CSSStyleDeclaration() {
9+
10+
/**
11+
* @constructor
12+
* @param {((cssText: string) => void) | null} [onChangeCallback]
13+
* The callback that is invoked whenever a property changes.
14+
*/
15+
function CSSStyleDeclaration(onChangeCallback = null) {
1016
if (new.target === undefined) {
1117
throw new TypeError('Illegal invocation');
1218
}
1319

14-
let onChangeCallback = arguments[0];
15-
if (onChangeCallback === null || onChangeCallback === undefined) {
16-
onChangeCallback = null;
17-
} else {
20+
if (onChangeCallback !== null) {
1821
onChangeCallback = webidlConversions.Function(onChangeCallback, {
1922
context: 'Failed to constructor CSSStyleDeclaration: parameter 1',
2023
});
2124
}
2225

23-
return webidlWrapper.create(sharedGlobalObject, undefined, {
24-
onChangeCallback: onChangeCallback,
25-
});
26+
return webidlWrapper.create(sharedGlobalObject, undefined, { onChangeCallback });
2627
}
2728

2829
sharedGlobalObject.CSSStyleDeclaration = CSSStyleDeclaration;

lib/CSSStyleDeclaration-impl.js

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,13 @@ class CSSStyleDeclarationImpl {
2121
* @param {object} privateData
2222
* @param {((cssText: string) => void) | null} [privateData.onChangeCallback]
2323
*/
24-
constructor(globalObject, args, { onChangeCallback = null }) {
24+
constructor(globalObject, args, { onChangeCallback }) {
2525
this._globalObject = globalObject;
26-
this._values = {};
27-
this._importants = {};
26+
this._values = Object.create(null);
27+
this._importants = Object.create(null);
2828
this._length = 0;
2929
this._onChange = onChangeCallback || (() => {});
30+
this.parentRule = null;
3031
}
3132

3233
/**
@@ -37,24 +38,18 @@ class CSSStyleDeclarationImpl {
3738
* Returns the empty string if the property has not been set.
3839
*/
3940
getPropertyValue(name) {
40-
if (!this._values.hasOwnProperty(name)) {
41-
return '';
42-
}
43-
return this._values[name].toString();
41+
return this._values[name] || '';
4442
}
4543

4644
/**
4745
*
4846
* @param {string} name
4947
* @param {string} value
50-
* @param {string} [priority=null] "important" or null
48+
* @param {string} [priority=""] "important" or ""
5149
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleDeclaration-setProperty
5250
*/
53-
setProperty(name, value, priority) {
54-
if (value === undefined) {
55-
return;
56-
}
57-
if (value === null || value === '') {
51+
setProperty(name, value, priority = '') {
52+
if (value === '') {
5853
this.removeProperty(name);
5954
return;
6055
}
@@ -72,7 +67,14 @@ class CSSStyleDeclarationImpl {
7267
this._importants[lowercaseName] = priority;
7368
}
7469

75-
_setProperty(name, value, priority) {
70+
/**
71+
* @param {string} name
72+
* @param {string | null} value
73+
* @param {string} [priority=""]
74+
*/
75+
_setProperty(name, value, priority = '') {
76+
// FIXME: A good chunk of the implemented properties call this method
77+
// with `value = undefined`, expecting it to do nothing:
7678
if (value === undefined) {
7779
return;
7880
}
@@ -105,7 +107,7 @@ class CSSStyleDeclarationImpl {
105107
* Returns the empty string if the property has not been set or the property name does not correspond to a known CSS property.
106108
*/
107109
removeProperty(name) {
108-
if (!this._values.hasOwnProperty(name)) {
110+
if (!idlUtils.hasOwn(this._values, name)) {
109111
return '';
110112
}
111113

@@ -164,9 +166,9 @@ Object.defineProperties(CSSStyleDeclarationImpl.prototype, {
164166
value = this.getPropertyValue(name);
165167
priority = this.getPropertyPriority(name);
166168
if (priority !== '') {
167-
priority = ' !' + priority;
169+
priority = ` !${priority}`;
168170
}
169-
properties.push([name, ': ', value, priority, ';'].join(''));
171+
properties.push(`${name}: ${value}${priority};`);
170172
}
171173
return properties.join(' ');
172174
},
@@ -197,13 +199,6 @@ Object.defineProperties(CSSStyleDeclarationImpl.prototype, {
197199
enumerable: true,
198200
configurable: true,
199201
},
200-
parentRule: {
201-
get: function() {
202-
return null;
203-
},
204-
enumerable: true,
205-
configurable: true,
206-
},
207202
length: {
208203
get: function() {
209204
return this._length;
@@ -227,6 +222,7 @@ Object.defineProperties(CSSStyleDeclarationImpl.prototype, {
227222

228223
require('./properties')(CSSStyleDeclarationImpl.prototype);
229224

225+
// TODO: Consider using `[Reflect]` for basic properties
230226
allProperties.forEach(function(property) {
231227
if (!implementedProperties.has(property)) {
232228
var declaration = getBasicPropertyDescriptor(property);

scripts/convert-idl.js

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,10 @@ const outputDir = implDir;
1515
const propertyNames = [
1616
...allProperties,
1717
...Array.from(allExtraProperties).filter(prop => {
18-
return prop !== 'css-float' && !allProperties.has(prop);
18+
return !allProperties.has(prop);
1919
}),
2020
].sort();
2121

22-
const camelCasedAttributes = propertyNames.map(n => cssPropertyToIDLAttribute(n));
23-
const webkitCasedAttributes = propertyNames
24-
.filter(n => n.startsWith('-webkit-'))
25-
.map(n => cssPropertyToIDLAttribute(n, true));
26-
const dashedAttributes = propertyNames.filter(n => n.includes('-'));
27-
2822
{
2923
// TODO: This should be natively supported by WebIDL2JS's Transformer
3024
// https://github.com/jsdom/webidl2js/issues/188
@@ -43,7 +37,8 @@ partial interface CSSStyleDeclaration {
4337
`
4438
);
4539

46-
for (const camelCasedAttribute of camelCasedAttributes) {
40+
for (const property of propertyNames) {
41+
const camelCasedAttribute = cssPropertyToIDLAttribute(property);
4742
genIDL.write(` [CEReactions] attribute [TreatNullAs=EmptyString] CSSOMString _${camelCasedAttribute};
4843
`);
4944
}
@@ -52,7 +47,9 @@ partial interface CSSStyleDeclaration {
5247
// https://drafts.csswg.org/cssom/#dom-cssstyledeclaration-webkit_cased_attribute
5348
`);
5449

55-
for (const webkitCasedAttribute of webkitCasedAttributes) {
50+
for (const property of propertyNames) {
51+
if (!property.startsWith('-webkit-')) continue;
52+
const webkitCasedAttribute = cssPropertyToIDLAttribute(property, /* lowercaseFirst = */ true);
5653
genIDL.write(` [CEReactions] attribute [TreatNullAs=EmptyString] CSSOMString _${webkitCasedAttribute};
5754
`);
5855
}
@@ -61,8 +58,9 @@ partial interface CSSStyleDeclaration {
6158
// https://drafts.csswg.org/cssom/#dom-cssstyledeclaration-dashed_attribute
6259
`);
6360

64-
for (const dashedAttribute of dashedAttributes) {
65-
genIDL.write(` [CEReactions] attribute [TreatNullAs=EmptyString] CSSOMString ${dashedAttribute};
61+
for (const property of propertyNames) {
62+
if (!property.includes('-')) continue;
63+
genIDL.write(` [CEReactions] attribute [TreatNullAs=EmptyString] CSSOMString ${property};
6664
`);
6765
}
6866

@@ -78,7 +76,7 @@ partial interface CSSStyleDeclaration {
7876

7977
const transformer = new Transformer({
8078
implSuffix: '-impl',
81-
// TODO: Add support for `CEReactions`
79+
// TODO: Add support for `[CEReactions]`
8280
});
8381

8482
transformer.addSource(srcDir, implDir);

scripts/generate_implemented_properties.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,15 @@ const t = require('babel-types');
66
const generate = require('babel-generator').default;
77
const { idlAttributeToCSSProperty } = require('../lib/parsers');
88

9+
const webkitPropertyName = /^webkit[A-Z]/;
910
const dashedProperties = fs
1011
.readdirSync(path.resolve(__dirname, '../lib/properties'))
11-
.filter(propertyFile => propertyFile.slice(-3) === '.js')
12+
.filter(propertyFile => path.extname(propertyFile) === '.js')
1213
.map(propertyFile => {
13-
return idlAttributeToCSSProperty(propertyFile.slice(0, -3), propertyFile.startsWith('webkit'));
14+
return idlAttributeToCSSProperty(
15+
path.basename(propertyFile, '.js'),
16+
webkitPropertyName.test(propertyFile)
17+
);
1418
});
1519

1620
const out_file = fs.createWriteStream(path.resolve(__dirname, '../lib/implementedProperties.js'), {

0 commit comments

Comments
 (0)