|
@@ -18,11 +18,13 @@ type
|
|
|
FLock: integer;
|
|
|
FInspectNeeded: boolean;
|
|
|
FTarget: TFresnelElement;
|
|
|
- procedure OnTargetDomChanged(Event: TAbstractEvent);
|
|
|
+ procedure OnTargetCSSApplied(Event: TAbstractEvent);
|
|
|
procedure SetTarget(const AValue: TFresnelElement);
|
|
|
protected
|
|
|
procedure Inspect;
|
|
|
- procedure AddRule(Row: integer; Selectors, Origin: TCSSString; RuleEl: TCSSRuleElement);
|
|
|
+ procedure UpdateRule(Row: integer; Selectors, Origin: TCSSString; RuleEl: TCSSRuleElement);
|
|
|
+ procedure UpdateDeclaration(RuleDiv: TDiv; Row: integer; DeclEl: TCSSDeclarationElement);
|
|
|
+ procedure UpdateLabel(DeclDiv: TDiv; Index: integer; aClass, aCaption: string);
|
|
|
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
|
|
|
public
|
|
|
const
|
|
@@ -33,6 +35,11 @@ type
|
|
|
RuleBracketLabelClass = 'CSSStyleInspRuleBracket';
|
|
|
RuleOriginLabelClass = 'CSSStyleInspOrigin';
|
|
|
RuleFooterDivClass = 'CSSStyleInspFooter';
|
|
|
+ DeclDivClass = 'CSSStyleInspDecl';
|
|
|
+ DeclKeyLabelClass = 'CSSStyleInspKey';
|
|
|
+ DeclColonLabelClass = 'CSSStyleInspColon';
|
|
|
+ DeclValueLabelClass = 'CSSStyleInspValue';
|
|
|
+ SkippedClass = 'CSSStyleInspSkipped';
|
|
|
public
|
|
|
constructor Create(AOwner: TComponent); override;
|
|
|
destructor Destroy; override;
|
|
@@ -62,16 +69,16 @@ begin
|
|
|
VP:=Target.Viewport;
|
|
|
if VP<>nil then
|
|
|
begin
|
|
|
- VP.AddEventListener(evtViewportCSSApplied,@OnTargetDomChanged);
|
|
|
+ VP.AddEventListener(evtViewportCSSApplied,@OnTargetCSSApplied);
|
|
|
if VP.Rendered then
|
|
|
Inspect;
|
|
|
end;
|
|
|
end;
|
|
|
end;
|
|
|
|
|
|
-procedure TCSSStyleInspector.OnTargetDomChanged(Event: TAbstractEvent);
|
|
|
+procedure TCSSStyleInspector.OnTargetCSSApplied(Event: TAbstractEvent);
|
|
|
begin
|
|
|
- writeln('TCSSStyleInspector.OnTargetDomChanged ',Event.Sender<>nil);
|
|
|
+ writeln('TCSSStyleInspector.OnTargetCSSApplied ',Event.Sender<>nil);
|
|
|
Inspect;
|
|
|
end;
|
|
|
|
|
@@ -113,7 +120,7 @@ begin
|
|
|
Row:=0;
|
|
|
|
|
|
// Element.Style aka inline style
|
|
|
- AddRule(Row,'Element.Style','',Target.StyleElement);
|
|
|
+ UpdateRule(Row,'Element.Style','',Target.StyleElement);
|
|
|
inc(Row);
|
|
|
|
|
|
// CSS rules
|
|
@@ -148,7 +155,7 @@ begin
|
|
|
end;
|
|
|
writeln('TCSSStyleInspector.Inspect ',i,' Spec=',aRule.Specificity,' Selector="',Selectors,'" Src=',RuleOrigin);
|
|
|
|
|
|
- AddRule(Row,Selectors,RuleOrigin,RuleEl);
|
|
|
+ UpdateRule(Row,Selectors,RuleOrigin,RuleEl);
|
|
|
inc(Row);
|
|
|
end;
|
|
|
|
|
@@ -160,14 +167,11 @@ begin
|
|
|
end;
|
|
|
end;
|
|
|
|
|
|
-procedure TCSSStyleInspector.AddRule(Row: integer; Selectors, Origin: TCSSString;
|
|
|
+procedure TCSSStyleInspector.UpdateRule(Row: integer; Selectors, Origin: TCSSString;
|
|
|
RuleEl: TCSSRuleElement);
|
|
|
var
|
|
|
- i, j: Integer;
|
|
|
- ChildEl, KeyEl: TCSSElement;
|
|
|
- DeclEl: TCSSDeclarationElement;
|
|
|
- ResolvedKeyEl: TCSSResolvedIdentifierElement;
|
|
|
- Src: String;
|
|
|
+ i, SubRow: Integer;
|
|
|
+ ChildEl: TCSSElement;
|
|
|
CurDiv, HeaderDiv, FooterDiv: TDiv;
|
|
|
BracketCloseLabel, BracketOpenLabel, SelectorLabel, OriginLabel: TLabel;
|
|
|
begin
|
|
@@ -191,8 +195,9 @@ begin
|
|
|
HeaderDiv.CSSClasses.Text:=RuleHeaderDivClass;
|
|
|
HeaderDiv.Parent:=CurDiv;
|
|
|
|
|
|
+ // todo: highlight not matching rules
|
|
|
SelectorLabel:=TLabel.Create(Self);
|
|
|
- SelectorLabel.CSSClasses.Text:=RuleBracketLabelClass;
|
|
|
+ SelectorLabel.CSSClasses.Text:=RuleSelectorLabelClass;
|
|
|
SelectorLabel.Caption:=Selectors;
|
|
|
SelectorLabel.Parent:=HeaderDiv;
|
|
|
|
|
@@ -208,7 +213,7 @@ begin
|
|
|
|
|
|
// footer: "}"
|
|
|
FooterDiv:=TDiv.Create(Self);
|
|
|
- FooterDiv.CSSClasses.Text:=RuleHeaderDivClass;
|
|
|
+ FooterDiv.CSSClasses.Text:=RuleFooterDivClass;
|
|
|
FooterDiv.Parent:=CurDiv;
|
|
|
|
|
|
BracketCloseLabel:=TLabel.Create(Self);
|
|
@@ -221,54 +226,131 @@ begin
|
|
|
|
|
|
if RuleEl<>nil then
|
|
|
begin
|
|
|
+ SubRow:=1;
|
|
|
for i:=0 to RuleEl.ChildCount-1 do
|
|
|
begin
|
|
|
ChildEl:=RuleEl.Children[i];
|
|
|
//writeln(' Child ',i,' ',ChildEl.ClassName);
|
|
|
if ChildEl is TCSSDeclarationElement then
|
|
|
begin
|
|
|
- DeclEl:=TCSSDeclarationElement(ChildEl);
|
|
|
- Src:='';
|
|
|
- if DeclEl.KeyCount<>1 then
|
|
|
- begin
|
|
|
- // todo: multi key declaration
|
|
|
- continue;
|
|
|
- end;
|
|
|
- KeyEl:=DeclEl.Keys[0];
|
|
|
- if KeyEl is TCSSResolvedIdentifierElement then
|
|
|
- begin
|
|
|
- ResolvedKeyEl:=TCSSResolvedIdentifierElement(KeyEl);
|
|
|
- Src+=ResolvedKeyEl.Name;
|
|
|
-
|
|
|
- Src+=' : ';
|
|
|
- For j:=0 to DeclEl.ChildCount-1 do
|
|
|
- begin
|
|
|
- if j>0 then
|
|
|
- Src+=', ';
|
|
|
- Src+=DeclEl.Children[j].AsFormattedString;
|
|
|
- end;
|
|
|
- if DeclEl.IsImportant then
|
|
|
- Src+=' !important';
|
|
|
- if ResolvedKeyEl.NumericalID<=CSSIDNone then
|
|
|
- begin
|
|
|
- // unknown attribute
|
|
|
- writeln('TCSSStyleInspector.AddRule Unknown attribute: ',i,' "',Src,'"');
|
|
|
- end else begin
|
|
|
- // todo: check for validity
|
|
|
- // todo: check if already set
|
|
|
- // todo: split shorthands
|
|
|
- writeln('TCSSStyleInspector.AddRule Known: ',i,' "',Src,'"');
|
|
|
- end;
|
|
|
- end else begin
|
|
|
- // todo: unknown declaration
|
|
|
- writeln('TCSSStyleInspector.AddRule Invalid: ',i,' "',DeclEl.AsFormattedString,'"');
|
|
|
- end;
|
|
|
- // todo: !important
|
|
|
+ UpdateDeclaration(CurDiv,SubRow,TCSSDeclarationElement(ChildEl));
|
|
|
+ inc(SubRow);
|
|
|
end;
|
|
|
end;
|
|
|
end;
|
|
|
end;
|
|
|
|
|
|
+procedure TCSSStyleInspector.UpdateDeclaration(RuleDiv: TDiv; Row: integer;
|
|
|
+ DeclEl: TCSSDeclarationElement);
|
|
|
+var
|
|
|
+ KeyEl: TCSSElement;
|
|
|
+ ResolvedKeyEl: TCSSResolvedIdentifierElement;
|
|
|
+ ValueTxt, KeyTxt: String;
|
|
|
+ i, Index: Integer;
|
|
|
+ DeclDiv: TDiv;
|
|
|
+begin
|
|
|
+ // add or update div
|
|
|
+ if Row<RuleDiv.NodeCount-1 then // -1 for the footer
|
|
|
+ begin
|
|
|
+ DeclDiv:=RuleDiv.Nodes[Row] as TDiv;
|
|
|
+ end else begin
|
|
|
+ DeclDiv:=TDiv.Create(Self);
|
|
|
+ DeclDiv.CSSClasses.text:=DeclDivClass;
|
|
|
+ RuleDiv.InsertBefore(DeclDiv,RuleDiv.Nodes[Row]);
|
|
|
+ end;
|
|
|
+
|
|
|
+ KeyTxt:='';
|
|
|
+ for i:=0 to DeclEl.KeyCount-1 do
|
|
|
+ begin
|
|
|
+ if i>0 then
|
|
|
+ KeyTxt+=', ';
|
|
|
+ KeyTxt+=DeclEl.Keys[i].AsFormattedString;
|
|
|
+ end;
|
|
|
+
|
|
|
+ ValueTxt:='';
|
|
|
+ for i:=0 to DeclEl.ChildCount-1 do
|
|
|
+ begin
|
|
|
+ if i>0 then
|
|
|
+ ValueTxt+=', ';
|
|
|
+ ValueTxt+=DeclEl.Children[i].AsFormattedString;
|
|
|
+ end;
|
|
|
+ if DeclEl.IsImportant then
|
|
|
+ ValueTxt+=' !important';
|
|
|
+
|
|
|
+ Index:=0;
|
|
|
+ if (DeclEl.KeyCount<>1) then
|
|
|
+ begin
|
|
|
+ // unsupported declaration
|
|
|
+ end else begin
|
|
|
+ KeyEl:=DeclEl.Keys[0];
|
|
|
+ if KeyEl is TCSSResolvedIdentifierElement then
|
|
|
+ begin
|
|
|
+ ResolvedKeyEl:=TCSSResolvedIdentifierElement(KeyEl);
|
|
|
+ if ResolvedKeyEl.NumericalID<=CSSIDNone then
|
|
|
+ begin
|
|
|
+ // unknown attribute
|
|
|
+ writeln('TCSSStyleInspector.AddDeclaration Unknown attribute: ',i,' "',ValueTxt,'"');
|
|
|
+ end else begin
|
|
|
+ // todo: check for validity
|
|
|
+ // todo: check if overriden
|
|
|
+ // todo: split shorthands
|
|
|
+ writeln('TCSSStyleInspector.AddDeclaration Known: ',i,' "',ValueTxt,'"');
|
|
|
+ UpdateLabel(DeclDiv,Index,DeclKeyLabelClass,KeyTxt);
|
|
|
+ inc(Index);
|
|
|
+ UpdateLabel(DeclDiv,Index,DeclColonLabelClass,':');
|
|
|
+ inc(Index);
|
|
|
+ UpdateLabel(DeclDiv,Index,DeclValueLabelClass,ValueTxt);
|
|
|
+ inc(Index);
|
|
|
+ end;
|
|
|
+ end else begin
|
|
|
+ // todo: unknown declaration
|
|
|
+ writeln('TCSSStyleInspector.AddDeclaration Invalid: ',i,' "',DeclEl.AsFormattedString,'"');
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+
|
|
|
+ if Index=0 then
|
|
|
+ begin
|
|
|
+ // invalid declaration
|
|
|
+ UpdateLabel(DeclDiv,Index,SkippedClass,KeyTxt+': '+ValueTxt);
|
|
|
+ inc(Index);
|
|
|
+ end;
|
|
|
+
|
|
|
+ // delete old elements
|
|
|
+ while DeclDiv.NodeCount>Index do
|
|
|
+ DeclDiv.Nodes[DeclDiv.NodeCount-1].Free;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TCSSStyleInspector.UpdateLabel(DeclDiv: TDiv; Index: integer; aClass, aCaption: string);
|
|
|
+var
|
|
|
+ aLabel: TLabel;
|
|
|
+ El: TFresnelElement;
|
|
|
+begin
|
|
|
+ writeln('TCSSStyleInspector.UpdateLabel ',Index,' "',aClass,'" "',aCaption,'"');
|
|
|
+ if Index=DeclDiv.NodeCount then
|
|
|
+ begin
|
|
|
+ // add
|
|
|
+ aLabel:=TLabel.Create(Self);
|
|
|
+ aLabel.CSSClasses.Text:=aClass;
|
|
|
+ aLabel.Caption:=aCaption;
|
|
|
+ aLabel.Parent:=DeclDiv;
|
|
|
+ end else begin
|
|
|
+ // update
|
|
|
+ El:=DeclDiv.Nodes[Index];
|
|
|
+ if El is TLabel then
|
|
|
+ begin
|
|
|
+ // update label
|
|
|
+ aLabel.CSSClasses.Text:=aClass;
|
|
|
+ aLabel.Caption:=aCaption;
|
|
|
+ end else begin
|
|
|
+ // insert label
|
|
|
+ aLabel:=TLabel.Create(Self);
|
|
|
+ aLabel.CSSClasses.Text:=aClass;
|
|
|
+ aLabel.Caption:=aCaption;
|
|
|
+ DeclDiv.InsertBefore(aLabel,El);
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
procedure TCSSStyleInspector.Notification(AComponent: TComponent; Operation: TOperation);
|
|
|
begin
|
|
|
inherited Notification(AComponent, Operation);
|
|
@@ -297,7 +379,16 @@ end;
|
|
|
|
|
|
class function TCSSStyleInspector.GetCSSTypeStyle: TCSSString;
|
|
|
begin
|
|
|
- Result:='.'+RulesDivClass+' { }';
|
|
|
+ Result:=
|
|
|
+ '.'+RulesDivClass+' { font-color: white; background-color: #333 }'+LineEnding
|
|
|
+ //+'.'+RuleSelectorLabelClass+' { }'+LineEnding
|
|
|
+ +'.'+RuleBracketLabelClass+' { font-weight: bold; }'+LineEnding
|
|
|
+ //+'.'+RuleOriginLabelClass+' { }'+LineEnding
|
|
|
+ +'.'+RuleFooterDivClass+' { border-bottom: 1px solid #888; }'+LineEnding
|
|
|
+ +'.'+DeclDivClass+' { margin-left: 30px; }'+LineEnding
|
|
|
+ +'.'+DeclKeyLabelClass+' { font-color: cyan; }'+LineEnding
|
|
|
+ +'.'+DeclColonLabelClass+' { margin-right: 1em; }'+LineEnding
|
|
|
+ ;
|
|
|
end;
|
|
|
|
|
|
procedure TCSSStyleInspector.BeginUpdate;
|