Skip to content

Commit ae88254

Browse files
committed
Fix borders part2
1 parent 29d3a59 commit ae88254

27 files changed

+1520
-463
lines changed

lib/CSSStyleDeclaration.js

Lines changed: 109 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,25 @@
44
*/
55
"use strict";
66
const allExtraProperties = require("./allExtraProperties");
7-
const { shorthandProperties } = require("./shorthandProperties");
87
const allProperties = require("./generated/allProperties");
98
const implementedProperties = require("./generated/implementedProperties");
109
const generatedProperties = require("./generated/properties");
1110
const {
1211
hasVarFunc,
12+
isValidPropertyValue,
1313
parseCSS,
1414
parsePropertyValue,
1515
parseShorthand,
1616
prepareValue,
1717
splitValue
1818
} = require("./parsers");
19+
const { shorthandProperties } = require("./shorthandProperties");
1920
const { dashedToCamelCase } = require("./utils/camelize");
21+
const {
22+
borderProperties,
23+
normalizeBorderProperties,
24+
prepareBorderProperties
25+
} = require("./utils/normalizeBorders");
2026
const { getPropertyDescriptor } = require("./utils/propertyDescriptors");
2127
const { asciiLowercase } = require("./utils/strings");
2228

@@ -124,7 +130,6 @@ class CSSStyleDeclaration {
124130
}
125131
}
126132

127-
// FIXME:
128133
get cssText() {
129134
if (this._computed) {
130135
return "";
@@ -133,24 +138,31 @@ class CSSStyleDeclaration {
133138
for (let i = 0; i < this._length; i++) {
134139
const property = this[i];
135140
const value = this.getPropertyValue(property);
136-
const priority = this.getPropertyPriority(property);
141+
const priority = this._priorities.get(property);
137142
if (priority === "important") {
138-
properties.set(property, `${property}: ${value} !${priority};`);
143+
properties.set(property, { property, value, priority });
139144
} else {
140-
properties.set(property, `${property}: ${value};`);
141-
}
142-
}
143-
for (const [property] of properties) {
144-
if (shorthandProperties.has(property)) {
145-
const longhandProperties = shorthandProperties.get(property);
146-
for (const [longhand] of longhandProperties) {
147-
if (properties.has(longhand) && !this.getPropertyPriority(longhand)) {
148-
properties.delete(longhand);
145+
if (shorthandProperties.has(property)) {
146+
const longhandProperties = shorthandProperties.get(property);
147+
for (const [longhand] of longhandProperties) {
148+
if (properties.has(longhand) && !this._priorities.get(longhand)) {
149+
properties.delete(longhand);
150+
}
149151
}
150152
}
153+
properties.set(property, { property, value, priority: null });
151154
}
152155
}
153-
return [...properties.values()].join(" ");
156+
const normalizedProperties = normalizeBorderProperties(properties);
157+
const parts = [];
158+
for (const { property, value, priority } of normalizedProperties.values()) {
159+
if (priority) {
160+
parts.push(`${property}: ${value} !${priority};`);
161+
} else {
162+
parts.push(`${property}: ${value};`);
163+
}
164+
}
165+
return parts.join(" ");
154166
}
155167

156168
set cssText(val) {
@@ -333,20 +345,37 @@ Object.defineProperties(CSSStyleDeclaration.prototype, {
333345
/**
334346
* @param {string} property
335347
* @param {object} shorthandFor
348+
* @param {Map} initialValues
336349
*/
337-
value(property, shorthandFor) {
338-
const values = [];
350+
value(property, shorthandFor, initialValues = new Map()) {
351+
const obj = {};
352+
const filter = initialValues.size > 0;
353+
const firstKey = filter && initialValues.keys().next().value;
339354
for (const key of shorthandFor.keys()) {
340355
const val = this.getPropertyValue(key);
341-
if (hasVarFunc(val)) {
356+
if (val === "" || hasVarFunc(val)) {
342357
return "";
343358
}
344-
if (val !== "") {
345-
values.push(val);
359+
if (filter) {
360+
const initialValue = initialValues.get(key);
361+
if (key === firstKey) {
362+
obj[key] = val;
363+
} else if (val !== initialValue) {
364+
obj[key] = val;
365+
if (obj[firstKey] && obj[firstKey] === initialValues.get(firstKey)) {
366+
delete obj[firstKey];
367+
}
368+
}
369+
} else {
370+
obj[key] = val;
346371
}
347372
}
348-
if (values.length) {
349-
return values.join(" ");
373+
if (Object.values(obj).length) {
374+
const value = Object.values(obj).join(" ");
375+
if (isValidPropertyValue(property, value)) {
376+
return value;
377+
}
378+
return "";
350379
}
351380
if (this._values.has(property)) {
352381
return this.getPropertyValue(property);
@@ -358,13 +387,15 @@ Object.defineProperties(CSSStyleDeclaration.prototype, {
358387

359388
_implicitGetter: {
360389
/**
361-
* @param {string} property
390+
* @param {string} prefix
391+
* @param {string} part
362392
* @param {Array.<string>} positions
363393
*/
364-
value(property, positions = []) {
394+
value(prefix, part, positions = []) {
395+
const suffix = part ? `-${part}` : "";
365396
const values = [];
366397
for (const position of positions) {
367-
const val = this.getPropertyValue(`${property}-${position}`);
398+
const val = this.getPropertyValue(`${prefix}-${position}${suffix}`);
368399
if (val === "" || hasVarFunc(val)) {
369400
return "";
370401
}
@@ -498,16 +529,17 @@ Object.defineProperties(CSSStyleDeclaration.prototype, {
498529
/**
499530
* @param {string} prefix
500531
* @param {string} part
501-
* @param {string} val
532+
* @param {string|Array.<string>} val
502533
* @param {Function} parser
503534
* @param {Array.<string>} positions
504535
*/
505536
value(prefix, part, val, parser, positions = []) {
506537
const suffix = part ? `-${part}` : "";
507-
const shorthandProp = `${prefix}${suffix}`;
508538
const values = [];
509539
if (val === "") {
510540
values.push(val);
541+
} else if (Array.isArray(val) && val.length) {
542+
values.push(...val);
511543
} else {
512544
const parsedValue = parser(val, {
513545
globalObject: this._global
@@ -520,29 +552,43 @@ Object.defineProperties(CSSStyleDeclaration.prototype, {
520552
if (!values.length || values.length > positions.length) {
521553
return;
522554
}
523-
this._setProperty(shorthandProp, values.join(" "));
555+
const shorthandProp = `${prefix}${suffix}`;
556+
const shorthandVal = values.join(" ");
557+
const positionValues = [...values];
524558
switch (positions.length) {
525-
case 4:
559+
case 4: {
526560
if (values.length === 1) {
527-
values.push(values[0], values[0], values[0]);
561+
positionValues.push(values[0], values[0], values[0]);
528562
} else if (values.length === 2) {
529-
values.push(values[0], values[1]);
563+
positionValues.push(values[0], values[1]);
530564
} else if (values.length === 3) {
531-
values.push(values[1]);
565+
positionValues.push(values[1]);
532566
}
533567
break;
534-
case 2:
568+
}
569+
case 2: {
535570
if (values.length === 1) {
536-
values.push(values[0]);
571+
positionValues.push(values[0]);
537572
}
538573
break;
574+
}
539575
default:
540576
}
577+
const longhandValues = [];
578+
for (const position of positions) {
579+
const property = `${prefix}-${position}${suffix}`;
580+
const longhandValue = this.getPropertyValue(property);
581+
const longhandPriority = this._priorities.get(property);
582+
longhandValues.push([longhandValue, longhandPriority]);
583+
}
541584
for (let i = 0; i < positions.length; i++) {
542585
const property = `${prefix}-${positions[i]}${suffix}`;
586+
const [longhandValue, longhandPriority] = longhandValues[i];
587+
const longhandVal = longhandPriority ? longhandValue : positionValues[i];
543588
this.removeProperty(property);
544-
this._values.set(property, values[i]);
589+
this._values.set(property, longhandVal);
545590
}
591+
this._setProperty(shorthandProp, shorthandVal);
546592
},
547593
enumerable: false
548594
},
@@ -568,13 +614,13 @@ Object.defineProperties(CSSStyleDeclaration.prototype, {
568614
}
569615
const property = `${prefix}-${part}`;
570616
this._setProperty(property, parsedValue);
571-
const combinedPriority = this.getPropertyPriority(prefix);
617+
const combinedPriority = this._priorities.get(prefix);
572618
const subparts = [];
573619
for (const position of positions) {
574620
subparts.push(`${prefix}-${position}`);
575621
}
576622
const parts = subparts.map((subpart) => this._values.get(subpart));
577-
const priorities = subparts.map((subpart) => this.getPropertyPriority(subpart));
623+
const priorities = subparts.map((subpart) => this._priorities.get(subpart));
578624
const [priority] = priorities;
579625
// Combine into a single property if all values are set and have the same
580626
// priority.
@@ -599,6 +645,33 @@ Object.defineProperties(CSSStyleDeclaration.prototype, {
599645
}
600646
},
601647
enumerable: false
648+
},
649+
650+
_implicitBorderSetter: {
651+
/**
652+
* @param {string} prop
653+
* @param {string} val
654+
*/
655+
value(prop, val) {
656+
const properties = new Map();
657+
if (prop !== "border") {
658+
for (let i = 0; i < this._length; i++) {
659+
const property = this[i];
660+
if (borderProperties.has(property)) {
661+
const value = this.getPropertyValue(property);
662+
properties.set(property, { property, value, priority: null });
663+
}
664+
}
665+
}
666+
const parsedProperties = prepareBorderProperties(prop, val, properties, {
667+
globalObject: this._global
668+
});
669+
for (const [property, item] of parsedProperties) {
670+
const { value } = item;
671+
this._setProperty(property, value);
672+
}
673+
},
674+
enumerable: false
602675
}
603676
});
604677

lib/parsers.js

Lines changed: 33 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,39 @@ exports.isValidPropertyValue = function isValidPropertyValue(prop, val) {
158158
return error === null && matched !== null;
159159
};
160160

161+
// Parse CSS function to AST.
162+
exports.parseFunction = function parseFunction(val) {
163+
if (typeof val !== "string") {
164+
val = exports.prepareValue(val);
165+
}
166+
if (val === "") {
167+
return {
168+
name: null,
169+
value: "",
170+
hasVar: false,
171+
raw: ""
172+
};
173+
}
174+
const obj = exports.parseCSS(val, { context: "value" }, true);
175+
if (!obj || !Array.isArray(obj.children) || obj.children.length > 1) {
176+
return;
177+
}
178+
const [{ name, type }] = obj.children;
179+
if (type !== "Function") {
180+
return;
181+
}
182+
const value = val
183+
.replace(new RegExp(`^${name}\\(`), "")
184+
.replace(/\)$/, "")
185+
.trim();
186+
return {
187+
name,
188+
value,
189+
hasVar: exports.hasVarFunc(val),
190+
raw: val
191+
};
192+
};
193+
161194
exports.parseCalc = function parseCalc(val, opt = { format: "specifiedValue" }) {
162195
if (typeof val !== "string") {
163196
val = exports.prepareValue(val);
@@ -193,38 +226,6 @@ exports.parseCalc = function parseCalc(val, opt = { format: "specifiedValue" })
193226
return values.join(" ");
194227
};
195228

196-
exports.parseFunction = function parseFunction(val) {
197-
if (typeof val !== "string") {
198-
val = exports.prepareValue(val);
199-
}
200-
if (val === "") {
201-
return {
202-
name: null,
203-
value: "",
204-
hasVar: false,
205-
raw: ""
206-
};
207-
}
208-
const obj = exports.parseCSS(val, { context: "value" }, true);
209-
if (!obj || !Array.isArray(obj.children) || obj.children.length > 1) {
210-
return;
211-
}
212-
const [{ name, type }] = obj.children;
213-
if (type !== "Function") {
214-
return;
215-
}
216-
const value = val
217-
.replace(new RegExp(`^${name}\\(`), "")
218-
.replace(/\)$/, "")
219-
.trim();
220-
return {
221-
name,
222-
value,
223-
hasVar: exports.hasVarFunc(val),
224-
raw: val
225-
};
226-
};
227-
228229
exports.parseNumber = function parseNumber(val, opt = {}) {
229230
const { clamp } = opt;
230231
const max = opt.max ?? Number.INFINITY;

0 commit comments

Comments
 (0)