|
@@ -58,6 +58,7 @@ const
|
|
CSSPseudoID_FirstOfType = 6; // :first-of-type
|
|
CSSPseudoID_FirstOfType = 6; // :first-of-type
|
|
CSSPseudoID_LastOfType = 7; // :last-of-type
|
|
CSSPseudoID_LastOfType = 7; // :last-of-type
|
|
CSSPseudoID_OnlyOfType = 8; // :only-of-type
|
|
CSSPseudoID_OnlyOfType = 8; // :only-of-type
|
|
|
|
+ CSSCallID_NthChild = 9; // :nth-child
|
|
|
|
|
|
type
|
|
type
|
|
TCSSMsgID = int64;
|
|
TCSSMsgID = int64;
|
|
@@ -158,6 +159,11 @@ type
|
|
NormValue: string;
|
|
NormValue: string;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+ TCSSCallData = class(TCSSElResolverData)
|
|
|
|
+ public
|
|
|
|
+ NumericalID: TCSSNumericalID;
|
|
|
|
+ end;
|
|
|
|
+
|
|
TCSSResolverOption = (
|
|
TCSSResolverOption = (
|
|
croErrorOnUnknownName
|
|
croErrorOnUnknownName
|
|
);
|
|
);
|
|
@@ -172,6 +178,12 @@ const
|
|
DefaultCSSComputeOptions = [ccoCommit];
|
|
DefaultCSSComputeOptions = [ccoCommit];
|
|
|
|
|
|
type
|
|
type
|
|
|
|
+ TCSSResStringComparison = (
|
|
|
|
+ crscDefault,
|
|
|
|
+ crscCaseInsensitive,
|
|
|
|
+ crscCaseSensitive
|
|
|
|
+ );
|
|
|
|
+ TCSSResStringComparisons = set of TCSSResStringComparison;
|
|
|
|
|
|
{ TCSSResolver }
|
|
{ TCSSResolver }
|
|
|
|
|
|
@@ -179,6 +191,7 @@ type
|
|
private
|
|
private
|
|
FNumericalIDs: array[TCSSNumericalIDKind] of TCSSNumericalIDs;
|
|
FNumericalIDs: array[TCSSNumericalIDKind] of TCSSNumericalIDs;
|
|
FOptions: TCSSResolverOptions;
|
|
FOptions: TCSSResolverOptions;
|
|
|
|
+ FStringComparison: TCSSResStringComparison;
|
|
FStyle: TCSSElement;
|
|
FStyle: TCSSElement;
|
|
FOwnsStyle: boolean;
|
|
FOwnsStyle: boolean;
|
|
FFirstElData: TCSSElResolverData;
|
|
FFirstElData: TCSSElResolverData;
|
|
@@ -204,10 +217,16 @@ type
|
|
function SelectorBinaryMatches(aBinary: TCSSBinaryElement; const TestNode: TCSSNode): TCSSSpecifity; virtual;
|
|
function SelectorBinaryMatches(aBinary: TCSSBinaryElement; const TestNode: TCSSNode): TCSSSpecifity; virtual;
|
|
function SelectorArrayMatches(anArray: TCSSArrayElement; const TestNode: TCSSNode): TCSSSpecifity; virtual;
|
|
function SelectorArrayMatches(anArray: TCSSArrayElement; const TestNode: TCSSNode): TCSSSpecifity; virtual;
|
|
function SelectorArrayBinaryMatches(aBinary: TCSSBinaryElement; const TestNode: TCSSNode): TCSSSpecifity; virtual;
|
|
function SelectorArrayBinaryMatches(aBinary: TCSSBinaryElement; const TestNode: TCSSNode): TCSSSpecifity; virtual;
|
|
|
|
+ function SelectorCallMatches(aCall: TCSSCallElement; const TestNode: TCSSNode): TCSSSpecifity; virtual;
|
|
|
|
+ function Call_NthChild(aCall: TCSSCallElement; const TestNode: TCSSNode): TCSSSpecifity; virtual;
|
|
function ComputeValue(El: TCSSElement): TCSSString; virtual;
|
|
function ComputeValue(El: TCSSElement): TCSSString; virtual;
|
|
|
|
+ function SameValueText(const A, B: TCSSString): boolean; virtual;
|
|
|
|
+ function SameValueText(A: PChar; ALen: integer; B: PChar; BLen: integer): boolean; virtual;
|
|
|
|
+ function PosSubString(const SearchStr, Str: TCSSString): integer; virtual;
|
|
function PosWord(const SearchWord, Words: TCSSString): integer; virtual;
|
|
function PosWord(const SearchWord, Words: TCSSString): integer; virtual;
|
|
procedure MergeProperty(El: TCSSElement; Specifity: TCSSSpecifity); virtual;
|
|
procedure MergeProperty(El: TCSSElement; Specifity: TCSSSpecifity); virtual;
|
|
function ResolveIdentifier(El: TCSSIdentifierElement; Kind: TCSSNumericalIDKind): TCSSNumericalID; virtual;
|
|
function ResolveIdentifier(El: TCSSIdentifierElement; Kind: TCSSNumericalIDKind): TCSSNumericalID; virtual;
|
|
|
|
+ function ResolveCall(El: TCSSCallElement): TCSSNumericalID; virtual;
|
|
procedure AddElData(El: TCSSElement; ElData: TCSSElResolverData); virtual;
|
|
procedure AddElData(El: TCSSElement; ElData: TCSSElResolverData); virtual;
|
|
function AddElValueData(El: TCSSElement; const aValue: TCSSString): TCSSValueData; virtual;
|
|
function AddElValueData(El: TCSSElement; const aValue: TCSSString): TCSSValueData; virtual;
|
|
function FindComputedAttribute(AttrID: TCSSNumericalID): PCSSComputedAttribute;
|
|
function FindComputedAttribute(AttrID: TCSSNumericalID): PCSSComputedAttribute;
|
|
@@ -229,6 +248,7 @@ type
|
|
property Options: TCSSResolverOptions read FOptions write SetOptions;
|
|
property Options: TCSSResolverOptions read FOptions write SetOptions;
|
|
property Attributes[Index: integer]: PCSSComputedAttribute read GetAttributes;
|
|
property Attributes[Index: integer]: PCSSComputedAttribute read GetAttributes;
|
|
property AttributeCount: integer read FAttributeCount;
|
|
property AttributeCount: integer read FAttributeCount;
|
|
|
|
+ property StringComparison: TCSSResStringComparison read FStringComparison;
|
|
end;
|
|
end;
|
|
|
|
|
|
implementation
|
|
implementation
|
|
@@ -378,6 +398,8 @@ begin
|
|
Result:=SelectorArrayMatches(TCSSArrayElement(aSelector),TestNode)
|
|
Result:=SelectorArrayMatches(TCSSArrayElement(aSelector),TestNode)
|
|
else if C=TCSSListElement then
|
|
else if C=TCSSListElement then
|
|
Result:=SelectorListMatches(TCSSListElement(aSelector),TestNode)
|
|
Result:=SelectorListMatches(TCSSListElement(aSelector),TestNode)
|
|
|
|
+ else if C=TCSSCallElement then
|
|
|
|
+ Result:=SelectorCallMatches(TCSSCallElement(aSelector),TestNode)
|
|
else
|
|
else
|
|
DoError(20220908230152,'Unknown CSS selector element',aSelector);
|
|
DoError(20220908230152,'Unknown CSS selector element',aSelector);
|
|
end;
|
|
end;
|
|
@@ -592,44 +614,71 @@ var
|
|
AttrID: TCSSNumericalID;
|
|
AttrID: TCSSNumericalID;
|
|
{$IFDEF VerboseCSSResolver}
|
|
{$IFDEF VerboseCSSResolver}
|
|
i: integer;
|
|
i: integer;
|
|
|
|
+ aValue: TCSSString;
|
|
|
|
+ OldStringComparison: TCSSResStringComparison;
|
|
{$ENDIF}
|
|
{$ENDIF}
|
|
begin
|
|
begin
|
|
Result:=CSSSpecifityInvalid;
|
|
Result:=CSSSpecifityInvalid;
|
|
if anArray.Prefix<>nil then
|
|
if anArray.Prefix<>nil then
|
|
- DoError(20220910154004,'Invalid CSS array selector prefix',anArray.Prefix);
|
|
|
|
|
|
+ DoError(20220910154004,'Invalid CSS attribute selector prefix',anArray.Prefix);
|
|
{$IFDEF VerboseCSSResolver}
|
|
{$IFDEF VerboseCSSResolver}
|
|
writeln('TCSSResolver.SelectorArrayMatches Prefix=',GetCSSObj(anArray.Prefix),' ChildCount=',anArray.ChildCount);
|
|
writeln('TCSSResolver.SelectorArrayMatches Prefix=',GetCSSObj(anArray.Prefix),' ChildCount=',anArray.ChildCount);
|
|
for i:=0 to anArray.ChildCount-1 do
|
|
for i:=0 to anArray.ChildCount-1 do
|
|
writeln('TCSSResolver.SelectorArrayMatches ',i,' ',GetCSSObj(anArray.Children[i]));
|
|
writeln('TCSSResolver.SelectorArrayMatches ',i,' ',GetCSSObj(anArray.Children[i]));
|
|
{$ENDIF}
|
|
{$ENDIF}
|
|
- if anArray.ChildCount<>1 then
|
|
|
|
- DoError(20220910154033,'Invalid CSS array selector',anArray);
|
|
|
|
- El:=anArray.Children[0];
|
|
|
|
- C:=El.ClassType;
|
|
|
|
- if C=TCSSIdentifierElement then
|
|
|
|
- begin
|
|
|
|
- // [name] -> has attribute name
|
|
|
|
- AttrID:=ResolveIdentifier(TCSSIdentifierElement(El),nikAttribute);
|
|
|
|
- case AttrID of
|
|
|
|
- CSSIDNone:
|
|
|
|
- Result:=CSSSpecifityNoMatch;
|
|
|
|
- CSSAttributeID_ID,
|
|
|
|
- CSSAttributeID_Class:
|
|
|
|
- // basic CSS attributes are always defined
|
|
|
|
- Result:=CSSSpecifityClass;
|
|
|
|
- CSSAttributeID_All:
|
|
|
|
- // special CSS attributes without a value
|
|
|
|
- Result:=CSSSpecifityNoMatch;
|
|
|
|
- else
|
|
|
|
- if TestNode.HasCSSAttribute(AttrID) then
|
|
|
|
- Result:=CSSSpecifityClass
|
|
|
|
- else
|
|
|
|
|
|
+ if anArray.ChildCount<1 then
|
|
|
|
+ DoError(20220910154033,'Invalid CSS attribute selector',anArray);
|
|
|
|
+ OldStringComparison:=StringComparison;
|
|
|
|
+ try
|
|
|
|
+ if anArray.ChildCount>1 then
|
|
|
|
+ begin
|
|
|
|
+ El:=anArray.Children[1];
|
|
|
|
+ C:=El.ClassType;
|
|
|
|
+ if C=TCSSIdentifierElement then
|
|
|
|
+ begin
|
|
|
|
+ aValue:=TCSSIdentifierElement(El).Value;
|
|
|
|
+ case aValue of
|
|
|
|
+ 'i': FStringComparison:=crscCaseInsensitive;
|
|
|
|
+ 's': FStringComparison:=crscCaseSensitive;
|
|
|
|
+ else
|
|
|
|
+ if croErrorOnUnknownName in Options then
|
|
|
|
+ DoError(20220914174409,'Invalid attribute modifier "'+aValue+'"',El);
|
|
|
|
+ end;
|
|
|
|
+ end else
|
|
|
|
+ DoError(20220914173643,'Invalid CSS attribute modifier',El);
|
|
|
|
+ end;
|
|
|
|
+ if (anArray.ChildCount>2) and (croErrorOnUnknownName in Options) then
|
|
|
|
+ DoError(20220914174550,'Invalid CSS attribute modifier',anArray.Children[2]);
|
|
|
|
+
|
|
|
|
+ El:=anArray.Children[0];
|
|
|
|
+ C:=El.ClassType;
|
|
|
|
+ if C=TCSSIdentifierElement then
|
|
|
|
+ begin
|
|
|
|
+ // [name] -> has attribute name
|
|
|
|
+ AttrID:=ResolveIdentifier(TCSSIdentifierElement(El),nikAttribute);
|
|
|
|
+ case AttrID of
|
|
|
|
+ CSSIDNone:
|
|
Result:=CSSSpecifityNoMatch;
|
|
Result:=CSSSpecifityNoMatch;
|
|
- end;
|
|
|
|
- end else if C=TCSSBinaryElement then
|
|
|
|
- Result:=SelectorArrayBinaryMatches(TCSSBinaryElement(El),TestNode)
|
|
|
|
- else
|
|
|
|
- DoError(20220910153725,'Invalid CSS array selector',El);
|
|
|
|
|
|
+ CSSAttributeID_ID,
|
|
|
|
+ CSSAttributeID_Class:
|
|
|
|
+ // basic CSS attributes are always defined
|
|
|
|
+ Result:=CSSSpecifityClass;
|
|
|
|
+ CSSAttributeID_All:
|
|
|
|
+ // special CSS attributes without a value
|
|
|
|
+ Result:=CSSSpecifityNoMatch;
|
|
|
|
+ else
|
|
|
|
+ if TestNode.HasCSSAttribute(AttrID) then
|
|
|
|
+ Result:=CSSSpecifityClass
|
|
|
|
+ else
|
|
|
|
+ Result:=CSSSpecifityNoMatch;
|
|
|
|
+ end;
|
|
|
|
+ end else if C=TCSSBinaryElement then
|
|
|
|
+ Result:=SelectorArrayBinaryMatches(TCSSBinaryElement(El),TestNode)
|
|
|
|
+ else
|
|
|
|
+ DoError(20220910153725,'Invalid CSS array selector',El);
|
|
|
|
+ finally
|
|
|
|
+ FStringComparison:=OldStringComparison;
|
|
|
|
+ end;
|
|
end;
|
|
end;
|
|
|
|
|
|
function TCSSResolver.SelectorArrayBinaryMatches(aBinary: TCSSBinaryElement;
|
|
function TCSSResolver.SelectorArrayBinaryMatches(aBinary: TCSSBinaryElement;
|
|
@@ -673,21 +722,21 @@ begin
|
|
{$ENDIF}
|
|
{$ENDIF}
|
|
case aBinary.Operation of
|
|
case aBinary.Operation of
|
|
boEquals:
|
|
boEquals:
|
|
- if LeftValue=RightValue then
|
|
|
|
|
|
+ if SameValueText(LeftValue,RightValue) then
|
|
Result:=CSSSpecifityClass;
|
|
Result:=CSSSpecifityClass;
|
|
boSquaredEqual:
|
|
boSquaredEqual:
|
|
// begins with
|
|
// begins with
|
|
- if (RightValue<>'') and (LeftStr(LeftValue,length(RightValue))=RightValue) then
|
|
|
|
|
|
+ if (RightValue<>'') and SameValueText(LeftStr(LeftValue,length(RightValue)),RightValue) then
|
|
Result:=CSSSpecifityClass;
|
|
Result:=CSSSpecifityClass;
|
|
boDollarEqual:
|
|
boDollarEqual:
|
|
// ends with
|
|
// ends with
|
|
- if (RightValue<>'') and (RightStr(LeftValue,length(RightValue))=RightValue) then
|
|
|
|
|
|
+ if (RightValue<>'') and SameValueText(RightStr(LeftValue,length(RightValue)),RightValue) then
|
|
Result:=CSSSpecifityClass;
|
|
Result:=CSSSpecifityClass;
|
|
boPipeEqual:
|
|
boPipeEqual:
|
|
// equal to or starts with name-hyphen
|
|
// equal to or starts with name-hyphen
|
|
if (RightValue<>'')
|
|
if (RightValue<>'')
|
|
- and ((LeftValue=RightValue)
|
|
|
|
- or (LeftStr(LeftValue,length(RightValue)+1)=RightValue+'-')) then
|
|
|
|
|
|
+ and (SameValueText(LeftValue,RightValue)
|
|
|
|
+ or SameValueText(LeftStr(LeftValue,length(RightValue)+1),RightValue+'-')) then
|
|
Result:=CSSSpecifityClass;
|
|
Result:=CSSSpecifityClass;
|
|
boStarEqual:
|
|
boStarEqual:
|
|
// contains substring
|
|
// contains substring
|
|
@@ -707,6 +756,35 @@ begin
|
|
{$ENDIF}
|
|
{$ENDIF}
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+function TCSSResolver.SelectorCallMatches(aCall: TCSSCallElement;
|
|
|
|
+ const TestNode: TCSSNode): TCSSSpecifity;
|
|
|
|
+var
|
|
|
|
+ CallID: TCSSNumericalID;
|
|
|
|
+begin
|
|
|
|
+ Result:=CSSSpecifityNoMatch;
|
|
|
|
+ CallID:=ResolveCall(aCall);
|
|
|
|
+ case CallID of
|
|
|
|
+ CSSCallID_NthChild:
|
|
|
|
+ Result:=Call_NthChild(aCall,TestNode);
|
|
|
|
+ else
|
|
|
|
+ Result:=CSSSpecifityInvalid;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TCSSResolver.Call_NthChild(aCall: TCSSCallElement;
|
|
|
|
+ const TestNode: TCSSNode): TCSSSpecifity;
|
|
|
|
+var
|
|
|
|
+ i: Integer;
|
|
|
|
+begin
|
|
|
|
+ Result:=CSSSpecifityInvalid;
|
|
|
|
+ {$IFDEF VerboseCSSResolver}
|
|
|
|
+ writeln('TCSSResolver.Call_NthChild ',aCall.ArgCount);
|
|
|
|
+ for i:=0 to aCall.ArgCount-1 do
|
|
|
|
+ writeln('TCSSResolver.Call_NthChild ',i,' ',GetCSSObj(aCall.Args[i]),' AsString=',aCall.Args[i].AsString);
|
|
|
|
+ {$ENDIF}
|
|
|
|
+ DoError(20220914194913,'TCSSResolver.Call_NthChild',aCall);
|
|
|
|
+end;
|
|
|
|
+
|
|
function TCSSResolver.ComputeValue(El: TCSSElement): TCSSString;
|
|
function TCSSResolver.ComputeValue(El: TCSSElement): TCSSString;
|
|
var
|
|
var
|
|
ElData: TObject;
|
|
ElData: TObject;
|
|
@@ -729,23 +807,89 @@ begin
|
|
begin
|
|
begin
|
|
StrEl:=TCSSStringElement(El);
|
|
StrEl:=TCSSStringElement(El);
|
|
Result:=StrEl.Value;
|
|
Result:=StrEl.Value;
|
|
|
|
+ {$IFDEF VerboseCSSResolver}
|
|
writeln('TCSSResolver.ComputeValue String=[',Result,']');
|
|
writeln('TCSSResolver.ComputeValue String=[',Result,']');
|
|
|
|
+ {$ENDIF}
|
|
end
|
|
end
|
|
else if C=TCSSIntegerElement then
|
|
else if C=TCSSIntegerElement then
|
|
begin
|
|
begin
|
|
IntEl:=TCSSIntegerElement(El);
|
|
IntEl:=TCSSIntegerElement(El);
|
|
Result:=IntEl.AsString;
|
|
Result:=IntEl.AsString;
|
|
|
|
+ {$IFDEF VerboseCSSResolver}
|
|
|
|
+ writeln('TCSSResolver.ComputeValue Integer=[',Result,']');
|
|
|
|
+ {$ENDIF}
|
|
end else if C=TCSSFloatElement then
|
|
end else if C=TCSSFloatElement then
|
|
begin
|
|
begin
|
|
FloatEl:=TCSSFloatElement(El);
|
|
FloatEl:=TCSSFloatElement(El);
|
|
Result:=FloatEl.AsString;
|
|
Result:=FloatEl.AsString;
|
|
|
|
+ {$IFDEF VerboseCSSResolver}
|
|
|
|
+ writeln('TCSSResolver.ComputeValue Float=[',Result,']');
|
|
|
|
+ {$ENDIF}
|
|
end;
|
|
end;
|
|
- writeln('TCSSResolver.ComputeValue Value="',Result,'"');
|
|
|
|
AddElValueData(El,Result);
|
|
AddElValueData(El,Result);
|
|
end else
|
|
end else
|
|
DoError(20220910235106,'TCSSResolver.ComputeValue not supported',El);
|
|
DoError(20220910235106,'TCSSResolver.ComputeValue not supported',El);
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+function TCSSResolver.SameValueText(const A, B: TCSSString): boolean;
|
|
|
|
+begin
|
|
|
|
+ if StringComparison=crscCaseInsensitive then
|
|
|
|
+ Result:=SameText(A,B)
|
|
|
|
+ else
|
|
|
|
+ Result:=A=B;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TCSSResolver.SameValueText(A: PChar; ALen: integer; B: PChar;
|
|
|
|
+ BLen: integer): boolean;
|
|
|
|
+var
|
|
|
|
+ AC, BC: Char;
|
|
|
|
+ i: Integer;
|
|
|
|
+begin
|
|
|
|
+ if ALen<>BLen then exit(false);
|
|
|
|
+ if ALen=0 then exit(true);
|
|
|
|
+ if StringComparison=crscCaseInsensitive then
|
|
|
|
+ begin
|
|
|
|
+ for i:=0 to ALen-1 do
|
|
|
|
+ begin
|
|
|
|
+ AC:=A^;
|
|
|
|
+ BC:=B^;
|
|
|
|
+ if (AC<>BC) and (UpCase(AC)<>UpCase(BC)) then
|
|
|
|
+ exit(false);
|
|
|
|
+ inc(A);
|
|
|
|
+ inc(B);
|
|
|
|
+ end;
|
|
|
|
+ Result:=true;
|
|
|
|
+ end else
|
|
|
|
+ Result:=CompareMem(A,B,ALen);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TCSSResolver.PosSubString(const SearchStr, Str: TCSSString): integer;
|
|
|
|
+var
|
|
|
|
+ SearchLen: SizeInt;
|
|
|
|
+ i: Integer;
|
|
|
|
+ SearchP, StrP: PChar;
|
|
|
|
+ AC, BC: Char;
|
|
|
|
+begin
|
|
|
|
+ if SearchStr='' then exit(0);
|
|
|
|
+ if Str='' then exit(0);
|
|
|
|
+ if StringComparison=crscCaseInsensitive then
|
|
|
|
+ begin
|
|
|
|
+ SearchP:=PChar(SearchStr);
|
|
|
|
+ StrP:=PChar(Str);
|
|
|
|
+ SearchLen:=length(SearchStr);
|
|
|
|
+ AC:=SearchP^;
|
|
|
|
+ for i:=0 to length(Str)-SearchLen do
|
|
|
|
+ begin
|
|
|
|
+ BC:=StrP^;
|
|
|
|
+ if (upcase(AC)=upcase(BC)) and SameValueText(SearchP,SearchLen,StrP,SearchLen) then
|
|
|
|
+ exit(i+1);
|
|
|
|
+ inc(StrP);
|
|
|
|
+ end;
|
|
|
|
+ end else begin
|
|
|
|
+ Result:=Pos(SearchStr,Str);
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
function TCSSResolver.PosWord(const SearchWord, Words: TCSSString): integer;
|
|
function TCSSResolver.PosWord(const SearchWord, Words: TCSSString): integer;
|
|
// attribute selector ~=
|
|
// attribute selector ~=
|
|
const
|
|
const
|
|
@@ -763,13 +907,14 @@ begin
|
|
repeat
|
|
repeat
|
|
if p>WordsLen then
|
|
if p>WordsLen then
|
|
exit(0);
|
|
exit(0);
|
|
- if not (Words[p] in Whitespace) then break;
|
|
|
|
|
|
+ if not (Words[p] in Whitespace) then
|
|
|
|
+ break;
|
|
inc(p);
|
|
inc(p);
|
|
until false;
|
|
until false;
|
|
WordStart:=p;
|
|
WordStart:=p;
|
|
while (p<=WordsLen) and not (Words[p] in Whitespace) do
|
|
while (p<=WordsLen) and not (Words[p] in Whitespace) do
|
|
inc(p);
|
|
inc(p);
|
|
- if (p-WordStart=SearchLen) and CompareMem(@SearchWord[1],@Words[WordStart],SearchLen) then
|
|
|
|
|
|
+ if SameValueText(@SearchWord[1],SearchLen,@Words[WordStart],p-WordStart) then
|
|
exit(WordStart);
|
|
exit(WordStart);
|
|
until p>WordsLen;
|
|
until p>WordsLen;
|
|
end;
|
|
end;
|
|
@@ -838,7 +983,7 @@ begin
|
|
Result:=IdentData.NumericalID;
|
|
Result:=IdentData.NumericalID;
|
|
{$IFDEF VerboseCSSResolver}
|
|
{$IFDEF VerboseCSSResolver}
|
|
if IdentData.Kind<>Kind then
|
|
if IdentData.Kind<>Kind then
|
|
- DoError(20220908235300,'TCSSResolver.ResolveTypeIdentifier',El);
|
|
|
|
|
|
+ DoError(20220908235300,'TCSSResolver.ResolveIdentifier',El);
|
|
{$ENDIF}
|
|
{$ENDIF}
|
|
end else
|
|
end else
|
|
begin
|
|
begin
|
|
@@ -874,13 +1019,13 @@ begin
|
|
end;
|
|
end;
|
|
|
|
|
|
// resolve user defined names
|
|
// resolve user defined names
|
|
- if Result=0 then
|
|
|
|
|
|
+ if Result=CSSIDNone then
|
|
Result:=FNumericalIDs[Kind][aName];
|
|
Result:=FNumericalIDs[Kind][aName];
|
|
|
|
|
|
if Result=CSSIDNone then
|
|
if Result=CSSIDNone then
|
|
begin
|
|
begin
|
|
if croErrorOnUnknownName in FOptions then
|
|
if croErrorOnUnknownName in FOptions then
|
|
- DoError(20220908235919,'TCSSResolver.ResolveTypeIdentifier unknown '+CSSNumericalIDKindNames[Kind]+' "'+El.Name+'"',El);
|
|
|
|
|
|
+ DoError(20220908235919,'TCSSResolver.ResolveIdentifier unknown '+CSSNumericalIDKindNames[Kind]+' "'+El.Name+'"',El);
|
|
end;
|
|
end;
|
|
IdentData:=TCSSIdentifierData.Create;
|
|
IdentData:=TCSSIdentifierData.Create;
|
|
IdentData.Kind:=Kind;
|
|
IdentData.Kind:=Kind;
|
|
@@ -889,6 +1034,34 @@ begin
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+function TCSSResolver.ResolveCall(El: TCSSCallElement): TCSSNumericalID;
|
|
|
|
+var
|
|
|
|
+ Data: TObject;
|
|
|
|
+ CallData: TCSSCallData;
|
|
|
|
+ aName: TCSSString;
|
|
|
|
+begin
|
|
|
|
+ Data:=El.CustomData;
|
|
|
|
+ if Data<>nil then
|
|
|
|
+ begin
|
|
|
|
+ CallData:=TCSSCallData(Data);
|
|
|
|
+ Result:=CallData.NumericalID;
|
|
|
|
+ end else
|
|
|
|
+ begin
|
|
|
|
+ aName:=El.Name;
|
|
|
|
+ Result:=CSSIDNone;
|
|
|
|
+
|
|
|
|
+ case aName of
|
|
|
|
+ ':nth-child': Result:=CSSCallID_NthChild;
|
|
|
|
+ else
|
|
|
|
+ if croErrorOnUnknownName in FOptions then
|
|
|
|
+ DoError(20220914193946,'TCSSResolver.ResolveCall unknown "'+El.Name+'"',El);
|
|
|
|
+ end;
|
|
|
|
+ CallData:=TCSSCallData.Create;
|
|
|
|
+ CallData.NumericalID:=Result;
|
|
|
|
+ AddElData(El,CallData);
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
procedure TCSSResolver.AddElData(El: TCSSElement; ElData: TCSSElResolverData);
|
|
procedure TCSSResolver.AddElData(El: TCSSElement; ElData: TCSSElResolverData);
|
|
begin
|
|
begin
|
|
El.CustomData:=ElData;
|
|
El.CustomData:=ElData;
|