* Allow to delete actions for which no element ID exists

This commit is contained in:
Michaël Van Canneyt 2023-08-12 15:59:14 +02:00
parent 0cbb6646f7
commit d62ee4e3ba
8 changed files with 247 additions and 32 deletions

View File

@ -16,7 +16,7 @@ object HTMLActionListEditorForm: THTMLActionListEditorForm
OnKeyPress = ActionListEditorKeyPress
OnShow = FormShow
Position = poScreenCenter
LCLVersion = '2.3.0.0'
LCLVersion = '3.99.0.0'
object PanelDescr: TPanel
Left = 0
Height = 26
@ -146,6 +146,11 @@ object HTMLActionListEditorForm: THTMLActionListEditorForm
Caption = 'Add missing tags (Use Data-aware actions)'
OnExecute = actAddMissingDBExecute
end
object actRemoveMissing: TAction
Caption = 'Remove actions without corresponding tag'
Hint = 'Remove actions without corresponding tag with ID equal to ElementID'
OnExecute = actRemoveMissingExecute
end
end
object PopMenuActions: TPopupMenu
Left = 128

View File

@ -33,6 +33,7 @@ type
ActDelete: TAction;
actAddMissing: TAction;
actAddMissingUsingDB: TAction;
actRemoveMissing: TAction;
ActPanelToolBar: TAction;
ActPanelDescr: TAction;
ActMoveUp: TAction;
@ -78,6 +79,7 @@ type
var CloseAction: TCloseAction);
procedure ActionListEditorKeyDown(Sender: TObject; var Key: Word; {%H-}Shift: TShiftState);
procedure ActionListEditorKeyPress(Sender: TObject; var Key: char);
procedure actRemoveMissingExecute(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormHide(Sender: TObject);
procedure FormShow(Sender: TObject);
@ -113,7 +115,9 @@ type
{ TActionListComponentEditor }
Function CreateMissingActions(aEditor : TComponentEditor; aList : THTMLCustomElementActionList; PreferDB : Boolean = False) : Integer;
Function RemoveActionsWithoutID(aEditor : TComponentEditor; aList : THTMLCustomElementActionList) : Integer;
Function FindActionEditor(AList: THTMLCustomElementActionList): THTMLActionListEditorForm;
Function GetActionsWithoutID(aList : THTMLCustomElementActionList; aMissing : TFPList) : Integer;
implementation
@ -151,6 +155,69 @@ begin
end;
Function GetActionsWithoutID(aList : THTMLCustomElementActionList; aMissing : TFPList) : Integer;
Var
FN : String;
I : Integer;
Tags : TElementInfoList;
aAction : THTMLCustomElementAction;
begin
Result:=0;
FN:=HTMLTools.GetHTMLFileForComponent(aList);
Tags:=TElementInfoList.Create;
try
HTMLTools.GetTagIDs(FN,Tags,[eoExtraInfo]);
For I:=aList.ActionCount-1 downto 0 do
begin
aAction:=aList.Actions[i];
if (aAction.ElementID<>'') and (Tags.FindByID(aAction.ElementID)=Nil) then
aMissing.Add(aAction);
end;
finally
Tags.Free;
end;
end;
Procedure DeleteActionsWithoutID(aEditor : TComponentEditor; aMissing : TFPList);
var
I : Integer;
aAction : THTMLCustomElementAction;
begin
For I:=0 to aMissing.Count-1 do
begin
aAction:=THTMLCustomElementAction(aMissing[i]);
aEditor.Designer.PropertyEditorHook.DeletePersistent(TPersistent(aAction));
end;
end;
Function RemoveActionsWithoutID(aEditor : TComponentEditor; aList : THTMLCustomElementActionList) : Integer;
Var
FN : String;
aMissing : TFPList;
begin
Result:=0;
FN:=HTMLTools.GetHTMLFileForComponent(aList);
if (FN='') then
begin
ShowMessage(Format(rsErrNoHTMLFileNameForComponent,[aList.Name]));
exit;
end;
aMissing:=TFPList.Create;
try
GetActionsWithoutID(aList,aMissing);
Result:=aMissing.Count;
DeleteActionsWithoutID(aEditor,aMissing);
finally
aMissing.Free;
end;
end;
function CreateMissingActions(aEditor: TComponentEditor;
aList: THTMLCustomElementActionList; PreferDB : Boolean = False): Integer;
@ -160,6 +227,8 @@ Var
Tags : TElementInfoList;
aEl : TElementInfo;
aAction : THTMLCustomElementAction;
aMissing : TFPList;
aHook : TPropertyEditorHook;
begin
Result:=-1;
@ -169,40 +238,50 @@ begin
ShowMessage(Format(rsErrNoHTMLFileNameForComponent,[aList.Name]));
exit;
end;
aMissing:=Nil;
Tags:=TElementInfoList.Create;
try
aMissing:=TFPList.Create;
HTMLTools.GetTagIDs(FN,Tags,[eoExtraInfo]);
GetActionsWithoutID(aList,aMissing);
// Remove existing
for I:=Tags.Count-1 downto 0 do
if aList.FindActionByElementID(Tags[i].ElementID)<>Nil then
Tags.Delete(I);
if Tags.Count=0 then
if (Tags.Count=0) and (aMissing.Count=0) then
begin
ShowMessage(rsAllTagsHaveAction);
exit;
end;
// Now select
if SelectHTMLActionClasses(Tags,PreferDB) then
if SelectHTMLActionClasses(Tags,PreferDB,aMissing) then
begin
DeleteActionsWithoutID(aEditor,aMissing);
Result:=0;
aEditor.Designer.ClearSelection;
For I:=0 to Tags.Count-1 do
begin
aEl:=Tags[i];
if aEl.ActionClass=Nil then
continue;
aAction:=aList.NewAction(aList.Owner,aEl.ActionClass);
aName:='act'+HTMLTools.TagToIdentifier(aEl.ElementID);
if aList.Owner.FindComponent(aName)<>Nil then
aName:=aEditor.Designer.CreateUniqueComponentName(aName);
aAction.Name:=aName;
aAction.ElementID:=aEl.ElementID;
aEditor.Designer.ClearSelection;
aEditor.Designer.PropertyEditorHook.PersistentAdded(aAction,True);
aHook:=aEditor.Designer.PropertyEditorHook;
if assigned(aHook) then
aHook.PersistentAdded(aAction,True);
Inc(Result);
end;
end;
finally
Tags.Free;
aMissing.Free;
end;
aEditor.Designer.Modified;
if assigned(aEditor.Designer) then
aEditor.Designer.Modified;
end;
function FindActionEditor(AList: THTMLCustomElementActionList): THTMLActionListEditorForm;
@ -517,6 +596,12 @@ begin
Close;
end;
procedure THTMLActionListEditorForm.actRemoveMissingExecute(Sender: TObject);
begin
if QuestionDlg(rsCaution,rsMayDeleteActionsInCode,mtWarning,[mrOK,rsRiskOK,mrCancel,rsCancel,'iscancel','isdefault'],0)=mrOK then
RemoveActionsWithoutID(FCompEditor,HTMLActionList);
end;
procedure THTMLActionListEditorForm.OnComponentDelete(APersistent: TPersistent);
var

View File

@ -8,7 +8,7 @@ object frmSelectHTMLActionClasses: TfrmSelectHTMLActionClasses
ClientWidth = 514
OnClose = FormClose
OnCreate = FormCreate
LCLVersion = '2.3.0.0'
LCLVersion = '3.99.0.0'
object pnlTop: TPanel
Left = 0
Height = 34
@ -44,25 +44,66 @@ object frmSelectHTMLActionClasses: TfrmSelectHTMLActionClasses
TabOrder = 1
ShowButtons = [pbOK, pbCancel]
end
object VLEClasses: TValueListEditor
object PageControl1: TPageControl
Left = 0
Height = 328
Top = 34
Width = 514
ActivePage = TSAdd
Align = alClient
DefaultColWidth = 200
FixedCols = 0
RowCount = 2
TabIndex = 0
TabOrder = 2
KeyOptions = [keyUnique]
TitleCaptions.Strings = (
'Tag'
'Action Class'
)
OnGetPickList = VLEClassesGetPickList
ColWidths = (
200
312
)
object TSAdd: TTabSheet
Caption = 'Add actions'
ClientHeight = 298
ClientWidth = 504
object VLEClasses: TValueListEditor
Left = 0
Height = 298
Top = 0
Width = 504
Align = alClient
DefaultColWidth = 200
FixedCols = 0
RowCount = 2
TabOrder = 0
KeyOptions = [keyUnique]
TitleCaptions.Strings = (
'Tag'
'Action Class'
)
OnGetPickList = VLEClassesGetPickList
ColWidths = (
200
302
)
end
end
object TSRemove: TTabSheet
Caption = 'Remove actions'
ClientHeight = 298
ClientWidth = 504
object clbRemove: TCheckListBox
Left = 0
Height = 242
Top = 56
Width = 504
Align = alClient
ItemHeight = 0
TabOrder = 0
TopIndex = -1
end
object Label1: TLabel
Left = 0
Height = 56
Top = 0
Width = 504
Align = alTop
Alignment = taCenter
AutoSize = False
Caption = 'The following actions have no corresponding tag. '#10'Any actions that are checked will be removed.'
Layout = tlCenter
end
end
end
end

View File

@ -6,7 +6,7 @@ interface
uses
Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls,
ButtonPanel, stub.htmlactions, idehtml2class, ValEdit;
ButtonPanel, stub.htmlactions, idehtml2class, ValEdit, ComCtrls, CheckLst;
type
@ -24,10 +24,10 @@ type
TElementInfoList = Class(TTagInfoList)
private
function GetInfo(aIndex : Integer): TElementINfo;
function GetInfo(aIndex : Integer): TElementInfo;
Public
Constructor Create; overload;
Property Infos[aIndex : Integer] : TElementINfo Read GetInfo; default;
Property Infos[aIndex : Integer] : TElementInfo Read GetInfo; default;
end;
{ TfrmSelectHTMLActionClasses }
@ -35,7 +35,12 @@ type
TfrmSelectHTMLActionClasses = class(TForm)
bpHTMLActions: TButtonPanel;
cbUseDBAware: TCheckBox;
clbRemove: TCheckListBox;
Label1: TLabel;
PageControl1: TPageControl;
pnlTop: TPanel;
TSAdd: TTabSheet;
TSRemove: TTabSheet;
VLEClasses: TValueListEditor;
procedure cbUseDBAwareChange(Sender: TObject);
procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
@ -44,34 +49,40 @@ type
Values: TStrings);
private
FPreferDB: Boolean;
FRemoveList: TFPList;
FTags: TElementInfoList;
procedure AllocateDefaultClasses;
procedure DisplayRemoveList;
function GetTagClass(const aEl: TElementInfo): THTMLCustomElementActionClass;
procedure SaveSelectedClasses;
procedure SetPreferDB(AValue: Boolean);
procedure SetRemoveList(AValue: TFPList);
procedure SetTags(AValue: TElementInfoList);
public
Property PreferDB : Boolean Read FPreferDB Write SetPreferDB;
// Extra info Expected to be in TTagInfo object attached to string
Property Tags : TElementInfoList Read FTags Write SetTags;
// On entry, list of actions that can be removed. On close, actions that should actually be removed.
Property RemoveList : TFPList Read FRemoveList Write SetRemoveList;
end;
Function SelectHTMLActionClasses(aTags : TElementInfoList; aPreferDB : Boolean) : Boolean;
Function SelectHTMLActionClasses(aTags : TElementInfoList; aPreferDB : Boolean; aRemoveList : TFPList) : Boolean;
implementation
uses strutils, p2jselementactions, stub.data.HTMLActions, strpas2jscomponents;
{$R *.lfm}
Function SelectHTMLActionClasses(aTags : TElementInfoList; aPreferDB : Boolean) : Boolean;
Function SelectHTMLActionClasses(aTags : TElementInfoList; aPreferDB : Boolean; aRemoveList : TFPList) : Boolean;
begin
With TfrmSelectHTMLActionClasses.Create(Application) do
try
PreferDB:=aPreferDB;
Tags:=aTags;
RemoveList:=aRemoveList;
Result:=ShowModal=mrOK
finally
Free;
@ -106,6 +117,8 @@ Var
I : Integer;
begin
Values.Clear;
Values.Add(rsNoControl);
For I:=0 to TPas2JSActionRegistry.Instance.ActionCount-1 do
Values.Add(TPas2JSActionRegistry.Instance[I].ActionClass.ClassName);
end;
@ -139,10 +152,19 @@ begin
begin
aEl:=VLEClasses.Strings.Objects[I] as TElementInfo;
VLEClasses.Strings.GetNameValue(I,N,V);
aAct:=TPas2JSActionRegistry.Instance.FindActionByClassName(V);
if (V='') or (V=rsNoControl) then
aAct:=Nil
else
aAct:=TPas2JSActionRegistry.Instance.FindActionByClassName(V);
if aAct<>Nil then
aEl.ActionClass:=aAct.ActionClass;
aEl.ActionClass:=aAct.ActionClass
else
aEl.ActionClass:=Nil;
end;
if Assigned(FRemoveList) then
For I:=CLBRemove.Count-1 downto 0 do
if CLBRemove.Checked[i] then
FRemoveList.Remove(CLBRemove.Items.Objects[i]);
end;
procedure TfrmSelectHTMLActionClasses.FormCreate(Sender: TObject);
@ -152,7 +174,7 @@ begin
end;
Function TfrmSelectHTMLActionClasses.GetTagClass(Const aEl : TElementInfo) : THTMLCustomElementActionClass;
function TfrmSelectHTMLActionClasses.GetTagClass(const aEl: TElementInfo): THTMLCustomElementActionClass;
begin
Result:=THTMLElementAction;
@ -190,6 +212,32 @@ begin
AllocateDefaultClasses;
end;
procedure TfrmSelectHTMLActionClasses.SetRemoveList(AValue: TFPList);
begin
if FRemoveList=AValue then Exit;
FRemoveList:=AValue;
DisplayRemoveList;
end;
procedure TfrmSelectHTMLActionClasses.DisplayRemoveList;
Var
I : Integer;
A : THTMLCustomElementAction;
begin
if (FRemoveList=Nil) or (FRemoveList.Count=0) then
TSRemove.TabVisible:=False
else
begin
For I:=0 to FRemoveList.Count-1 do
begin
A:=THTMLCustomElementAction(FRemoveList[i]);
clbRemove.Items.AddObject(Format('%s (ID: %s)',[A.Name,A.ElementID]),A);
end;
end;
end;
procedure TfrmSelectHTMLActionClasses.SetTags(AValue: TElementInfoList);
begin
if FTags=AValue then Exit;

View File

@ -26,6 +26,7 @@ Type
destructor Destroy; override;
procedure Edit; override;
procedure CreateMissing;
procedure RemoveNonID;
property ActionList: THTMLElementActionList read FActionList write FActionList;
function GetVerbCount: Integer; override;
function GetVerb({%H-}Index: Integer): string; override;
@ -652,9 +653,14 @@ begin
ShowMessage(Format(rsHTMLActionsCreated,[aCount]));
end;
procedure THTMLElementActionListComponentEditor.RemoveNonID;
begin
end;
function THTMLElementActionListComponentEditor.GetVerbCount: Integer;
begin
Result := 2;
Result := 3;
end;
function THTMLElementActionListComponentEditor.GetVerb(Index: Integer): string;
@ -662,6 +668,7 @@ begin
case Index of
0 : Result := rsActionListComponentEditor;
1 : Result := rsActionListCreateMissing;
2 : Result := rsActionListRemoveNoID;
end;
end;
@ -670,6 +677,7 @@ begin
case Index of
0 : Edit;
1 : CreateMissing;
2 : RemoveNonID;
end;
end;

View File

@ -191,7 +191,7 @@ begin
RegisterPropertyEditor(TypeInfo(String),TBootstrapModal,'ParentID',TElementIDPropertyEditor);
RegisterPropertyEditor(TypeInfo(String),TBootstrapModal,'ElementID',TElementIDPropertyEditor);
RegisterPropertyEditor(TypeInfo(String),TDBBootstrapTableWidget,'ElementID',TElementIDPropertyEditor);
RegisterPropertyEditor(TypeInfo(String),TDBBootstrapTableWidget,'ParentIDID',TElementIDPropertyEditor);
RegisterPropertyEditor(TypeInfo(String),TDBBootstrapTableWidget,'ParentID',TElementIDPropertyEditor);
RegisterPropertyEditor(TypeInfo(String),TReferenceItem,'Selector',TElementIDSelectorPropertyEditor);
// RegisterPropertyEditor(TypeInfo(String),TDBHTMLButtonElementAction,'ElementID',TElementIDPropertyEditor);
RegisterPropertyEditor(TypeInfo(String),TBootstrapModal,'Template',TTemplatePropertyEditor);

View File

@ -7,6 +7,7 @@ interface
Resourcestring
rsActionListComponentEditor = 'HTM&L Element Actionlist Editor...';
rsActionListCreateMissing = 'Create &actions for HTML tags...';
rsActionListRemoveNoID = '&Remove actions without corresponding tag';
rsErrNoHTMLFileNameForComponent = 'No HTML filename found for component %s';
rsAllTagsHaveAction = 'All HTML tags with IDs already have a corresponding Action component.';
rsHTMLActionsCreated = '%d HTML Element Action components were created';
@ -30,6 +31,10 @@ Resourcestring
rsCreateFieldDefsNoNew = 'Fielddefs are up-to-date, no new fielddefs were added';
rsCreateParamsCount = 'Added %d parameters';
rsCreateParamsNoNew = 'Parameters are up-to-date, no new parameters were added';
rsCaution = 'Please confirm';
rsMayDeleteActionsInCode = 'Removing actions with missing tag may remove actions that reference a tag created in code.';
rsRiskOK = 'I understand the risk, delete the actions.';
rsCancel = 'Cancel.';
rsEditingHTMLProp = 'Editing HTML property: %s';
rsEditTemplate = 'Edit Template';
@ -56,6 +61,8 @@ Resourcestring
rsCreateServiceClient = 'Create Service client component';
rsInvalidAPIReturned = 'The service URL "%s" returned an invalid API: %s';
rsNoControl = '<none>';
implementation
end.

View File

@ -259,6 +259,8 @@ Type
procedure SetTag(aIndex : Integer; AValue: TTagInfoItem);
Public
function AddTagItem(const aElementID, aTag, aType, aName: String): TTagInfoItem;
Function IndexOfID(const aElementID : String) : Integer;
Function FindByID(const aElementID : String) : TTagInfoItem;
Property Tags [aIndex : Integer] : TTagInfoItem Read GetTag Write SetTag; default;
end;
@ -412,6 +414,25 @@ begin
Result.InputName:=aName;
end;
function TTagInfoList.IndexOfID(const aElementID: String): Integer;
begin
Result:=Count-1;
While (Result>=0) and Not (aElementID=Tags[Result].ElementID) do
Dec(Result);
end;
function TTagInfoList.FindByID(const aElementID: String): TTagInfoItem;
var
I : integer;
begin
Result:=Nil;
I:=IndexOfID(aElementID);
if I<>-1 then
Result:=Tags[i];
end;
{ TTagInfoItem }
procedure TTagInfoItem.Assign(aSource: TPersistent);