4
4
********************************************************************/
5
5
'use strict' ;
6
6
7
+ // FIXME: should move shorthandGetter(), shorthandSetter(), implicitSetter() and
8
+ // subImplicitSetter() to CSSStyleDeclaration()
9
+
7
10
const { resolve : resolveColor , utils } = require ( '@asamuzakjp/css-color' ) ;
8
11
const { cssCalc, isColor, isGradient, splitValue } = utils ;
9
12
@@ -22,6 +25,9 @@ exports.TYPES = {
22
25
UNIDENT : 0x8000 ,
23
26
} ;
24
27
28
+ // CSS global values
29
+ exports . GLOBAL_VALUES = Object . freeze ( [ 'initial' , 'inherit' , 'unset' , 'revert' , 'revert-layer' ] ) ;
30
+
25
31
// regular expressions
26
32
var DIGIT = '(?:0|[1-9]\\d*)' ;
27
33
var NUMBER = `[+-]?(?:${ DIGIT } (?:\\.\\d*)?|\\.\\d+)(?:e-?${ DIGIT } )?` ;
@@ -37,6 +43,7 @@ var calcRegEx =
37
43
38
44
// This will return one of the above types based on the passed in string
39
45
exports . valueType = function valueType ( val ) {
46
+ // see https://webidl.spec.whatwg.org/#LegacyNullToEmptyString
40
47
if ( val === '' || val === null ) {
41
48
return exports . TYPES . NULL_OR_EMPTY_STR ;
42
49
}
@@ -53,7 +60,7 @@ exports.valueType = function valueType(val) {
53
60
return exports . TYPES . CALC ;
54
61
}
55
62
if ( unitRegEx . test ( val ) ) {
56
- const [ , , unit ] = unitRegEx . exec ( val ) ;
63
+ var [ , , unit ] = unitRegEx . exec ( val ) ;
57
64
if ( ! unit ) {
58
65
return exports . TYPES . NUMBER ;
59
66
}
@@ -162,7 +169,7 @@ exports.parseLength = function parseLength(val) {
162
169
format : 'specifiedValue' ,
163
170
} ) ;
164
171
case exports . TYPES . LENGTH : {
165
- const [ , numVal , unit ] = unitRegEx . exec ( val ) ;
172
+ var [ , numVal , unit ] = unitRegEx . exec ( val ) ;
166
173
return `${ parseFloat ( numVal ) } ${ unit } ` ;
167
174
}
168
175
default :
@@ -186,9 +193,10 @@ exports.parsePercent = function parsePercent(val) {
186
193
return cssCalc ( val , {
187
194
format : 'specifiedValue' ,
188
195
} ) ;
189
- case exports . TYPES . PERCENT :
190
- const [ , numVal , unit ] = unitRegEx . exec ( val ) ;
196
+ case exports . TYPES . PERCENT : {
197
+ var [ , numVal , unit ] = unitRegEx . exec ( val ) ;
191
198
return `${ parseFloat ( numVal ) } ${ unit } ` ;
199
+ }
192
200
default :
193
201
if ( varContainedRegEx . test ( val ) ) {
194
202
return val ;
@@ -212,9 +220,10 @@ exports.parseMeasurement = function parseMeasurement(val) {
212
220
format : 'specifiedValue' ,
213
221
} ) ;
214
222
case exports . TYPES . LENGTH :
215
- case exports . TYPES . PERCENT :
216
- const [ , numVal , unit ] = unitRegEx . exec ( val ) ;
223
+ case exports . TYPES . PERCENT : {
224
+ var [ , numVal , unit ] = unitRegEx . exec ( val ) ;
217
225
return `${ parseFloat ( numVal ) } ${ unit } ` ;
226
+ }
218
227
default :
219
228
if ( varContainedRegEx . test ( val ) ) {
220
229
return val ;
@@ -236,7 +245,7 @@ exports.parseInheritingMeasurement = function parseInheritingMeasurement(val) {
236
245
exports . parseUrl = function parseUrl ( val ) {
237
246
var type = exports . valueType ( val ) ;
238
247
if ( type === exports . TYPES . NULL_OR_EMPTY_STR ) {
239
- return val ;
248
+ return '' ;
240
249
}
241
250
var res = urlRegEx . exec ( val ) ;
242
251
// does it match the regex?
@@ -293,10 +302,11 @@ exports.parseUrl = function parseUrl(val) {
293
302
return 'url("' + urlstr + '")' ;
294
303
} ;
295
304
305
+ // NOTE: seems not in use?
296
306
exports . parseString = function parseString ( val ) {
297
307
var type = exports . valueType ( val ) ;
298
308
if ( type === exports . TYPES . NULL_OR_EMPTY_STR ) {
299
- return val ;
309
+ return '' ;
300
310
}
301
311
if ( type !== exports . TYPES . STRING ) {
302
312
return undefined ;
@@ -320,14 +330,38 @@ exports.parseString = function parseString(val) {
320
330
return val ;
321
331
} ;
322
332
323
- exports . parseColor = function parseColor ( val ) {
333
+ exports . parseKeyword = function parseKeyword ( val , validKeywords = [ ] ) {
324
334
var type = exports . valueType ( val ) ;
325
- if ( type === exports . TYPES . NULL_OR_EMPTY_STR || type === exports . TYPES . VAR ) {
335
+ if ( type === exports . TYPES . NULL_OR_EMPTY_STR ) {
336
+ return '' ;
337
+ }
338
+ if ( type === exports . TYPES . VAR ) {
326
339
return val ;
327
340
}
341
+ if ( type !== exports . TYPES . KEYWORD ) {
342
+ return undefined ;
343
+ }
344
+ val = val . toString ( ) . toLowerCase ( ) ;
345
+ if ( validKeywords . includes ( val ) || exports . GLOBAL_VALUES . includes ( val ) ) {
346
+ return val ;
347
+ }
348
+ return undefined ;
349
+ } ;
350
+
351
+ exports . parseColor = function parseColor ( val ) {
352
+ var type = exports . valueType ( val ) ;
353
+ if ( type === exports . TYPES . NULL_OR_EMPTY_STR ) {
354
+ return '' ;
355
+ }
328
356
if ( type === exports . TYPES . UNDEFINED ) {
329
357
return undefined ;
330
358
}
359
+ if ( type === exports . TYPES . VAR ) {
360
+ return val ;
361
+ }
362
+ if ( type === exports . TYPES . KEYWORD ) {
363
+ return exports . parseKeyword ( val ) ;
364
+ }
331
365
if ( / ^ [ a - z ] + $ / i. test ( val ) && type === exports . TYPES . COLOR ) {
332
366
return val ;
333
367
}
@@ -346,7 +380,7 @@ exports.parseColor = function parseColor(val) {
346
380
exports . parseAngle = function parseAngle ( val ) {
347
381
var type = exports . valueType ( val ) ;
348
382
if ( type === exports . TYPES . NULL_OR_EMPTY_STR ) {
349
- return val ;
383
+ return '' ;
350
384
}
351
385
if ( type !== exports . TYPES . ANGLE ) {
352
386
return undefined ;
@@ -368,34 +402,19 @@ exports.parseAngle = function parseAngle(val) {
368
402
return flt + 'deg' ;
369
403
} ;
370
404
371
- exports . parseKeyword = function parseKeyword ( val , validKeywords ) {
405
+ exports . parseImage = function parseImage ( val ) {
372
406
var type = exports . valueType ( val ) ;
373
407
if ( type === exports . TYPES . NULL_OR_EMPTY_STR ) {
374
- return val ;
408
+ return '' ;
375
409
}
376
- if ( type !== exports . TYPES . KEYWORD ) {
410
+ if ( type === exports . TYPES . UNDEFINED ) {
377
411
return undefined ;
378
412
}
379
- val = val . toString ( ) . toLowerCase ( ) ;
380
- var i ;
381
- for ( i = 0 ; i < validKeywords . length ; i ++ ) {
382
- if ( validKeywords [ i ] . toLowerCase ( ) === val ) {
383
- return validKeywords [ i ] ;
384
- }
385
- }
386
- return undefined ;
387
- } ;
388
-
389
- exports . parseImage = function parseImage ( val ) {
390
- if ( / ^ (?: n o n e | i n h e r i t ) $ / i. test ( val ) ) {
391
- return val . toLowerCase ( ) ;
392
- }
393
- var type = exports . valueType ( val ) ;
394
- if ( type === exports . TYPES . NULL_OR_EMPTY_STR || type === exports . TYPES . VAR ) {
413
+ if ( type === exports . TYPES . VAR ) {
395
414
return val ;
396
415
}
397
- if ( type === exports . TYPES . UNDEFINED ) {
398
- return undefined ;
416
+ if ( type === exports . TYPES . KEYWORD ) {
417
+ return exports . parseKeyword ( val , [ 'none' ] ) ;
399
418
}
400
419
var values = splitValue ( val , {
401
420
delimiter : ',' ,
@@ -445,56 +464,22 @@ exports.dashedToCamelCase = function (dashed) {
445
464
return camel ;
446
465
} ;
447
466
448
- var isSpace = / \s / ;
449
- var openingDeliminators = [ '"' , "'" , '(' ] ;
450
- var closingDeliminators = [ '"' , "'" , ')' ] ;
451
- // this splits on whitespace, but keeps quoted and parened parts together
452
- var getParts = function ( str ) {
453
- var deliminatorStack = [ ] ;
454
- var length = str . length ;
455
- var i ;
456
- var parts = [ ] ;
457
- var currentPart = '' ;
458
- var openingIndex ;
459
- var closingIndex ;
460
- for ( i = 0 ; i < length ; i ++ ) {
461
- openingIndex = openingDeliminators . indexOf ( str [ i ] ) ;
462
- closingIndex = closingDeliminators . indexOf ( str [ i ] ) ;
463
- if ( isSpace . test ( str [ i ] ) ) {
464
- if ( deliminatorStack . length === 0 ) {
465
- if ( currentPart !== '' ) {
466
- parts . push ( currentPart ) ;
467
- }
468
- currentPart = '' ;
469
- } else {
470
- currentPart += str [ i ] ;
471
- }
472
- } else {
473
- if ( str [ i ] === '\\' ) {
474
- i ++ ;
475
- currentPart += str [ i ] ;
476
- } else {
477
- currentPart += str [ i ] ;
478
- if ( closingIndex !== - 1 && closingIndex === deliminatorStack [ deliminatorStack . length - 1 ] ) {
479
- deliminatorStack . pop ( ) ;
480
- } else if ( openingIndex !== - 1 ) {
481
- deliminatorStack . push ( openingIndex ) ;
482
- }
483
- }
484
- }
485
- }
486
- if ( currentPart !== '' ) {
487
- parts . push ( currentPart ) ;
467
+ exports . camelToDashed = function ( camelCase ) {
468
+ var dashed = camelCase . replace ( / (?< = [ a - z ] ) [ A - Z ] / g, '-$&' ) . toLowerCase ( ) ;
469
+ var vendorPrefixes = [ 'o' , 'moz' , 'ms' , 'webkit' ] ;
470
+ var match = dashed . match ( / ^ ( [ a - z ] + ) \- / ) ;
471
+ if ( match && vendorPrefixes . includes ( match [ 1 ] ) ) {
472
+ dashed = '-' + dashed ;
488
473
}
489
- return parts ;
474
+ return dashed ;
490
475
} ;
491
476
492
- /*
493
- * this either returns undefined meaning that it isn't valid
494
- * or returns an object where the keys are dashed short
495
- * hand properties and the values are the values to set
496
- * on them
497
- */
477
+ // this either returns undefined meaning that it isn't valid
478
+ // or returns an object where the keys are dashed short
479
+ // hand properties and the values are the values to set
480
+ // on them
481
+ // FIXME: need additional argument which indicates syntax
482
+ // and/or use Map() for shorthandFor to ensure order of the longhand properties
498
483
exports . shorthandParser = function parse ( v , shorthandFor ) {
499
484
var obj = { } ;
500
485
var type = exports . valueType ( v ) ;
@@ -504,19 +489,19 @@ exports.shorthandParser = function parse(v, shorthandFor) {
504
489
} ) ;
505
490
return obj ;
506
491
}
507
-
492
+ if ( type === exports . TYPES . UNDEFINED ) {
493
+ return undefined ;
494
+ }
508
495
if ( typeof v === 'number' ) {
509
496
v = v . toString ( ) ;
510
497
}
511
-
512
498
if ( typeof v !== 'string' ) {
513
499
return undefined ;
514
500
}
515
-
516
501
if ( v . toLowerCase ( ) === 'inherit' ) {
517
502
return { } ;
518
503
}
519
- var parts = getParts ( v ) ;
504
+ var parts = splitValue ( v ) ;
520
505
var valid = true ;
521
506
parts . forEach ( function ( part , i ) {
522
507
var partValid = false ;
@@ -526,21 +511,29 @@ exports.shorthandParser = function parse(v, shorthandFor) {
526
511
obj [ property ] = part ;
527
512
}
528
513
} ) ;
529
- valid = valid && partValid ;
514
+ if ( valid ) {
515
+ valid = partValid ;
516
+ }
530
517
} ) ;
531
518
if ( ! valid ) {
532
519
return undefined ;
533
520
}
534
521
return obj ;
535
522
} ;
536
523
524
+ // FIXME: check against shorthandParser and reduce Object.keys().forEach() loops
537
525
exports . shorthandSetter = function ( property , shorthandFor ) {
538
526
return function ( v ) {
527
+ if ( v === undefined ) {
528
+ return ;
529
+ }
530
+ if ( v === null ) {
531
+ v = '' ;
532
+ }
539
533
var obj = exports . shorthandParser ( v , shorthandFor ) ;
540
534
if ( obj === undefined ) {
541
535
return ;
542
536
}
543
- //console.log('shorthandSetter for:', property, 'obj:', obj);
544
537
Object . keys ( obj ) . forEach ( function ( subprop ) {
545
538
// in case subprop is an implicit property, this will clear
546
539
// *its* subpropertiesX
@@ -611,7 +604,7 @@ exports.implicitSetter = function (propertyBefore, propertyAfter, isValid, parse
611
604
if ( v . toLowerCase ( ) === 'inherit' || v === '' ) {
612
605
parts = [ v ] ;
613
606
} else {
614
- parts = getParts ( v ) ;
607
+ parts = splitValue ( v ) ;
615
608
}
616
609
if ( parts . length < 1 || parts . length > 4 ) {
617
610
return undefined ;
@@ -646,12 +639,10 @@ exports.implicitSetter = function (propertyBefore, propertyAfter, isValid, parse
646
639
} ;
647
640
} ;
648
641
649
- //
650
642
// Companion to implicitSetter, but for the individual parts.
651
643
// This sets the individual value, and checks to see if all four
652
644
// sub-parts are set. If so, it sets the shorthand version and removes
653
645
// the individual parts from the cssText.
654
- //
655
646
exports . subImplicitSetter = function ( prefix , part , isValid , parser ) {
656
647
var property = prefix + '-' + part ;
657
648
var subparts = [ prefix + '-top' , prefix + '-right' , prefix + '-bottom' , prefix + '-left' ] ;
@@ -697,16 +688,3 @@ exports.subImplicitSetter = function (prefix, part, isValid, parser) {
697
688
return v ;
698
689
} ;
699
690
} ;
700
-
701
- var camelToDashed = / [ A - Z ] / g;
702
- var firstSegment = / ^ \( [ ^ - ] \) - / ;
703
- var vendorPrefixes = [ 'o' , 'moz' , 'ms' , 'webkit' ] ;
704
- exports . camelToDashed = function ( camelCase ) {
705
- var match ;
706
- var dashed = camelCase . replace ( camelToDashed , '-$&' ) . toLowerCase ( ) ;
707
- match = dashed . match ( firstSegment ) ;
708
- if ( match && vendorPrefixes . indexOf ( match [ 1 ] ) !== - 1 ) {
709
- dashed = '-' + dashed ;
710
- }
711
- return dashed ;
712
- } ;
0 commit comments