Comparing version 3.0.0 to 4.0.0
@@ -21,7 +21,4 @@ /********************************************************************* | ||
this._length = 0; | ||
this._onChange = | ||
onChangeCallback || | ||
function () { | ||
return; | ||
}; | ||
this._onChange = onChangeCallback; | ||
this._setInProgress = false; | ||
}; | ||
@@ -81,2 +78,3 @@ CSSStyleDeclaration.prototype = { | ||
} | ||
var originalText = this.cssText; | ||
if (this._values[name]) { | ||
@@ -96,3 +94,5 @@ // Property already exist. Overwrite it. | ||
this._importants[name] = priority; | ||
this._onChange(this.cssText); | ||
if (this._onChange && this.cssText !== originalText && !this._setInProgress) { | ||
this._onChange(this.cssText); | ||
} | ||
}, | ||
@@ -127,3 +127,5 @@ | ||
this._onChange(this.cssText); | ||
if (this._onChange) { | ||
this._onChange(this.cssText); | ||
} | ||
return prevValue; | ||
@@ -203,2 +205,3 @@ }, | ||
} | ||
this._setInProgress = true; | ||
var rule_length = dummyRule.length; | ||
@@ -214,3 +217,6 @@ var name; | ||
} | ||
this._onChange(this.cssText); | ||
this._setInProgress = false; | ||
if (this._onChange) { | ||
this._onChange(this.cssText); | ||
} | ||
}, | ||
@@ -217,0 +223,0 @@ enumerable: true, |
@@ -349,2 +349,110 @@ 'use strict'; | ||
test('setting individual padding and margin properties to an empty string should clear them', () => { | ||
var style = new CSSStyleDeclaration(); | ||
var properties = ['padding', 'margin']; | ||
var parts = ['Top', 'Right', 'Bottom', 'Left']; | ||
for (var i = 0; i < properties.length; i++) { | ||
for (var j = 0; j < parts.length; j++) { | ||
var property = properties[i] + parts[j]; | ||
style[property] = '12px'; | ||
expect(style[property]).toEqual('12px'); | ||
style[property] = ''; | ||
expect(style[property]).toEqual(''); | ||
} | ||
} | ||
}); | ||
test('removing and setting individual margin properties updates the combined property accordingly', () => { | ||
var style = new CSSStyleDeclaration(); | ||
style.margin = '1px 2px 3px 4px'; | ||
style.marginTop = ''; | ||
expect(style.margin).toEqual(''); | ||
expect(style.marginRight).toEqual('2px'); | ||
expect(style.marginBottom).toEqual('3px'); | ||
expect(style.marginLeft).toEqual('4px'); | ||
style.marginBottom = ''; | ||
expect(style.margin).toEqual(''); | ||
expect(style.marginRight).toEqual('2px'); | ||
expect(style.marginLeft).toEqual('4px'); | ||
style.marginBottom = '5px'; | ||
expect(style.margin).toEqual(''); | ||
expect(style.marginRight).toEqual('2px'); | ||
expect(style.marginBottom).toEqual('5px'); | ||
expect(style.marginLeft).toEqual('4px'); | ||
style.marginTop = '6px'; | ||
expect(style.cssText).toEqual('margin: 6px 2px 5px 4px;'); | ||
}); | ||
test.each(['padding', 'margin'])( | ||
'removing an individual %s property should remove the combined property and replace it with the remaining individual ones', | ||
(property) => { | ||
var style = new CSSStyleDeclaration(); | ||
var parts = ['Top', 'Right', 'Bottom', 'Left']; | ||
var partValues = ['1px', '2px', '3px', '4px']; | ||
for (var j = 0; j < parts.length; j++) { | ||
var partToRemove = parts[j]; | ||
style[property] = partValues.join(' '); | ||
style[property + partToRemove] = ''; | ||
// Main property should have been removed | ||
expect(style[property]).toEqual(''); | ||
// Expect other parts to still be there | ||
for (var k = 0; k < parts.length; k++) { | ||
var propertyCss = property + '-' + parts[k].toLowerCase() + ': ' + partValues[k] + ';'; | ||
if (k === j) { | ||
expect(style[property + parts[k]]).toEqual(''); | ||
expect(style.cssText).not.toContain(propertyCss); | ||
} else { | ||
expect(style[property + parts[k]]).toEqual(partValues[k]); | ||
expect(style.cssText).toContain(propertyCss); | ||
} | ||
} | ||
} | ||
} | ||
); | ||
test.each(['margin', 'padding'])( | ||
'setting additional %s properties keeps important status of others', | ||
(property) => { | ||
var style = new CSSStyleDeclaration(); | ||
var importantProperty = property + '-top: 3px !important;'; | ||
style.cssText = importantProperty; | ||
expect(style.cssText).toContain(importantProperty); | ||
style[property + 'Right'] = '4px'; | ||
style[property + 'Bottom'] = '5px'; | ||
style[property + 'Left'] = '6px'; | ||
expect(style.cssText).toContain(importantProperty); | ||
expect(style.cssText).toContain(property + '-right: 4px;'); | ||
expect(style.cssText).toContain(property + '-bottom: 5px;'); | ||
expect(style.cssText).toContain(property + '-left: 6px;'); | ||
expect(style.cssText).not.toContain('margin:'); | ||
} | ||
); | ||
test.each(['margin', 'padding'])( | ||
'setting individual %s keeps important status of others', | ||
(property) => { | ||
var style = new CSSStyleDeclaration(); | ||
style.cssText = property + ': 3px !important;'; | ||
style[property + 'Top'] = '4px'; | ||
expect(style.cssText).toContain(property + '-top: 4px;'); | ||
expect(style.cssText).toContain(property + '-right: 3px !important;'); | ||
expect(style.cssText).toContain(property + '-bottom: 3px !important;'); | ||
expect(style.cssText).toContain(property + '-left: 3px !important;'); | ||
expect(style.cssText).not.toContain('margin:'); | ||
} | ||
); | ||
test('setting a value to 0 should return the string value', () => { | ||
@@ -357,8 +465,44 @@ var style = new CSSStyleDeclaration(); | ||
test('onchange callback should be called when the csstext changes', () => { | ||
var called = 0; | ||
var style = new CSSStyleDeclaration(function (cssText) { | ||
called++; | ||
expect(cssText).toEqual('opacity: 0;'); | ||
}); | ||
style.cssText = 'opacity: 0;'; | ||
expect(called).toEqual(1); | ||
style.cssText = 'opacity: 0;'; | ||
expect(called).toEqual(2); | ||
}); | ||
test('onchange callback should be called only once when multiple properties were added', () => { | ||
var called = 0; | ||
var style = new CSSStyleDeclaration(function (cssText) { | ||
called++; | ||
expect(cssText).toEqual('width: 100px; height: 100px;'); | ||
}); | ||
style.cssText = 'width: 100px;height:100px;'; | ||
expect(called).toEqual(1); | ||
}); | ||
test('onchange callback should not be called when property is set to the same value', () => { | ||
var called = 0; | ||
var style = new CSSStyleDeclaration(function () { | ||
called++; | ||
}); | ||
style.setProperty('opacity', 0); | ||
expect(called).toEqual(1); | ||
style.setProperty('opacity', 0); | ||
expect(called).toEqual(1); | ||
}); | ||
test('onchange callback should not be called when removeProperty was called on non-existing property', () => { | ||
var called = 0; | ||
var style = new CSSStyleDeclaration(function () { | ||
called++; | ||
}); | ||
style.removeProperty('opacity'); | ||
expect(called).toEqual(0); | ||
}); | ||
test('setting float should work the same as cssfloat', () => { | ||
@@ -407,2 +551,39 @@ var style = new CSSStyleDeclaration(); | ||
test('setting empty string and null to a padding or margin works', () => { | ||
var style = new CSSStyleDeclaration(); | ||
var parts = ['Top', 'Right', 'Bottom', 'Left']; | ||
function testParts(base, nullValue) { | ||
var props = [base].concat(parts.map((part) => base + part)); | ||
for (let prop of props) { | ||
expect(style[prop]).toEqual(''); | ||
style[prop] = '10px'; | ||
expect(style[prop]).toEqual('10px'); | ||
style[prop] = nullValue; | ||
expect(style[prop]).toEqual(''); | ||
} | ||
} | ||
testParts('margin', ''); | ||
testParts('margin', null); | ||
testParts('padding', ''); | ||
testParts('padding', null); | ||
}); | ||
test('setting undefined to a padding or margin does nothing', () => { | ||
var style = new CSSStyleDeclaration(); | ||
var parts = ['Top', 'Right', 'Bottom', 'Left']; | ||
function testParts(base) { | ||
var props = [base].concat(parts.map((part) => base + part)); | ||
for (let prop of props) { | ||
style[prop] = '10px'; | ||
expect(style[prop]).toEqual('10px'); | ||
style[prop] = undefined; | ||
expect(style[prop]).toEqual('10px'); | ||
} | ||
} | ||
testParts('margin'); | ||
testParts('padding'); | ||
}); | ||
test('setting null to background works', () => { | ||
@@ -409,0 +590,0 @@ var style = new CSSStyleDeclaration(); |
'use strict'; | ||
// autogenerated - 2/12/2023 | ||
// autogenerated - 12/28/2023 | ||
@@ -5,0 +5,0 @@ /* |
@@ -686,2 +686,5 @@ /********************************************************************* | ||
} | ||
if (v === null) { | ||
v = ''; | ||
} | ||
if (typeof v !== 'string') { | ||
@@ -695,15 +698,24 @@ return undefined; | ||
this._setProperty(property, v); | ||
var parts = []; | ||
for (var i = 0; i < 4; i++) { | ||
if (this._values[subparts[i]] == null || this._values[subparts[i]] === '') { | ||
break; | ||
} | ||
parts.push(this._values[subparts[i]]); | ||
} | ||
if (parts.length === 4) { | ||
for (i = 0; i < 4; i++) { | ||
var combinedPriority = this.getPropertyPriority(prefix); | ||
var parts = subparts.map((subpart) => this._values[subpart]); | ||
var priorities = subparts.map((subpart) => this.getPropertyPriority(subpart)); | ||
// Combine into a single property if all values are set and have the same priority | ||
if ( | ||
parts.every((p) => p !== '' && p != null) && | ||
priorities.every((p) => p === priorities[0]) && | ||
priorities[0] === combinedPriority | ||
) { | ||
for (var i = 0; i < subparts.length; i++) { | ||
this.removeProperty(subparts[i]); | ||
this._values[subparts[i]] = parts[i]; | ||
} | ||
this._setProperty(prefix, parts.join(' ')); | ||
this._setProperty(prefix, parts.join(' '), priorities[0]); | ||
} else { | ||
this.removeProperty(prefix); | ||
for (var j = 0; j < subparts.length; j++) { | ||
// The property we're setting won't be important, the rest will either keep their priority or inherit it from the combined property | ||
var priority = subparts[j] === property ? '' : priorities[j] || combinedPriority; | ||
this._setProperty(subparts[j], parts[j], priority); | ||
} | ||
} | ||
@@ -710,0 +722,0 @@ return v; |
@@ -110,3 +110,10 @@ 'use strict'; | ||
}); | ||
it.each([ | ||
[120, 'rgb(0, 255, 0)'], | ||
[240, 'rgb(0, 0, 255)'], | ||
])('should convert not zero hsl with non zero hue %s to %s', (hue, rgbValue) => { | ||
let input = 'hsl(' + hue + ', 100%, 50%)'; | ||
let output = parsers.parseColor(input); | ||
expect(output).toEqual(rgbValue); | ||
}); | ||
it.todo('Add more tests'); | ||
@@ -113,0 +120,0 @@ }); |
'use strict'; | ||
// autogenerated - 2/12/2023 | ||
// autogenerated - 12/28/2023 | ||
@@ -1228,3 +1228,3 @@ /* | ||
var type = external_dependency_parsers_0.valueType(v); | ||
return type === margin_local_var_TYPES.LENGTH || type === margin_local_var_TYPES.PERCENT || type === margin_local_var_TYPES.INTEGER && (v === '0' || v === 0); | ||
return type === margin_local_var_TYPES.NULL_OR_EMPTY_STR || type === margin_local_var_TYPES.LENGTH || type === margin_local_var_TYPES.PERCENT || type === margin_local_var_TYPES.INTEGER && (v === '0' || v === 0); | ||
}; | ||
@@ -1254,2 +1254,6 @@ | ||
if (v === null) { | ||
v = ''; | ||
} | ||
if (typeof v !== 'string') { | ||
@@ -1377,3 +1381,3 @@ return; | ||
var type = external_dependency_parsers_0.valueType(v); | ||
return type === padding_local_var_TYPES.LENGTH || type === padding_local_var_TYPES.PERCENT || type === padding_local_var_TYPES.INTEGER && (v === '0' || v === 0); | ||
return type === padding_local_var_TYPES.NULL_OR_EMPTY_STR || type === padding_local_var_TYPES.LENGTH || type === padding_local_var_TYPES.PERCENT || type === padding_local_var_TYPES.INTEGER && (v === '0' || v === 0); | ||
}; | ||
@@ -1397,2 +1401,6 @@ | ||
if (v === null) { | ||
v = ''; | ||
} | ||
if (typeof v !== 'string') { | ||
@@ -1399,0 +1407,0 @@ return; |
@@ -12,2 +12,3 @@ 'use strict'; | ||
return ( | ||
type === TYPES.NULL_OR_EMPTY_STR || | ||
type === TYPES.LENGTH || | ||
@@ -44,2 +45,5 @@ type === TYPES.PERCENT || | ||
} | ||
if (v === null) { | ||
v = ''; | ||
} | ||
if (typeof v !== 'string') { | ||
@@ -46,0 +50,0 @@ return; |
@@ -9,2 +9,3 @@ 'use strict'; | ||
return ( | ||
type === TYPES.NULL_OR_EMPTY_STR || | ||
type === TYPES.LENGTH || | ||
@@ -37,2 +38,5 @@ type === TYPES.PERCENT || | ||
} | ||
if (v === null) { | ||
v = ''; | ||
} | ||
if (typeof v !== 'string') { | ||
@@ -39,0 +43,0 @@ return; |
'use strict'; | ||
const hueToRgb = (t1, t2, hue) => { | ||
if (hue < 0) hue += 6; | ||
if (hue >= 6) hue -= 6; | ||
const MAX_HUE = 360; | ||
const COLOR_NB = 12; | ||
const MAX_RGB_VALUE = 255; | ||
if (hue < 1) return (t2 - t1) * hue + t1; | ||
else if (hue < 3) return t2; | ||
else if (hue < 4) return (t2 - t1) * (4 - hue) + t1; | ||
else return t1; | ||
}; | ||
// https://www.w3.org/TR/css-color-4/#hsl-to-rgb | ||
exports.hslToRgb = (hue, sat, light) => { | ||
const t2 = light <= 0.5 ? light * (sat + 1) : light + sat - light * sat; | ||
const t1 = light * 2 - t2; | ||
const r = hueToRgb(t1, t2, hue + 2); | ||
const g = hueToRgb(t1, t2, hue); | ||
const b = hueToRgb(t1, t2, hue - 2); | ||
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)]; | ||
hue = hue % MAX_HUE; | ||
if (hue < 0) { | ||
hue += MAX_HUE; | ||
} | ||
function f(n) { | ||
const k = (n + hue / (MAX_HUE / COLOR_NB)) % COLOR_NB; | ||
const a = sat * Math.min(light, 1 - light); | ||
return light - a * Math.max(-1, Math.min(k - 3, 9 - k, 1)); | ||
} | ||
return [f(0), f(8), f(4)].map((value) => Math.round(value * MAX_RGB_VALUE)); | ||
}; |
@@ -9,3 +9,3 @@ { | ||
], | ||
"version": "3.0.0", | ||
"version": "4.0.0", | ||
"homepage": "https://github.com/jsdom/cssstyle", | ||
@@ -48,9 +48,8 @@ "maintainers": [ | ||
"babylon": "^6.18.0", | ||
"eslint": "^8.32.0", | ||
"eslint-config-prettier": "^8.6.0", | ||
"eslint-plugin-prettier": "^4.2.1", | ||
"jest": "^29.3.1", | ||
"minipass-fetch": "^3.0.1", | ||
"eslint": "^8.56.0", | ||
"eslint-config-prettier": "^9.1.0", | ||
"eslint-plugin-prettier": "^5.1.2", | ||
"jest": "^29.7.0", | ||
"npm-run-all": "^4.1.5", | ||
"prettier": "^2.8.3", | ||
"prettier": "^3.1.1", | ||
"resolve": "^1.22.1" | ||
@@ -72,4 +71,4 @@ }, | ||
"engines": { | ||
"node": ">=14" | ||
"node": ">=18" | ||
} | ||
} |
@@ -5,3 +5,3 @@ # CSSStyleDeclaration | ||
[![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) | ||
[![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=main)](https://travis-ci.org/jsdom/cssstyle) [![codecov](https://codecov.io/gh/jsdom/cssstyle/branch/main/graph/badge.svg)](https://codecov.io/gh/jsdom/cssstyle) | ||
@@ -12,3 +12,3 @@ --- | ||
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. | ||
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. | ||
@@ -15,0 +15,0 @@ It was originally created by Chad Walker, it is now maintained by the jsdom community. |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
185525
11
5980
0