feat: quick-search fill modes + editable custom-field combobox + JS build gate
Quick search (Ctrl+Shift+Q fill mode) - Enter / left-click → full autofill (username + Tab + password), like Ctrl+Shift+L. - Shift+Enter / right-click → username only (new Delphi username-only SendInput path via field=user; ExecuteAutofill AUsernameOnly param). - Ctrl+Enter / Ctrl+click → password only. - Copy mode (tray / palette) unchanged: Enter/left = password, Shift+Enter/right = username. - Clipboard fix: copy-then-minimise no longer wipes the just-copied password — MinimizeToTray takes an AClearClipboard flag (False on the quick-search copy path, driven by app/minimize?keepclip=1). The 30s auto-clear still guards it. - Right-click on a result row suppresses the native/custom context menu (preventDefault + stopPropagation). Editable custom-field combobox - Option-backed custom fields (card brand, expiry year/month, etc.) now render a custom editable combobox instead of a locked <select>: an arrow drops a menu of ALL options (a native <datalist> filtered to the typed text, which confused users), while the input stays freely typeable for values not in the list. Storage shape unchanged. - Outside-click closes the menu via the existing slideover mousedown handler; item mousedown + preventDefault so blur doesn't race the pick. Build safety - BuildAssets.ps1 runs `node --check` on every embedded .js before generating assets.res. A syntax error now aborts the asset build (exit 1, file + line logged) instead of shipping a dead bundle that only surfaces after a full Delphi rebuild. Node is optional: absent → warn and continue. Docs - CODE_AUDIT.md: full static-analysis report (security, latent bugs, maintainability, future features, prioritized action plan). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -129,8 +129,11 @@ type
|
||||
public
|
||||
constructor Create(AMainForm: TForm);
|
||||
destructor Destroy; override;
|
||||
// Hide main window and show tray icon.
|
||||
procedure MinimizeToTray;
|
||||
// Hide main window and show tray icon. AClearClipboard defaults to
|
||||
// True (a manual minimise wipes any copied password immediately);
|
||||
// the quick-search "copy then hide so I can paste" flow passes False
|
||||
// so it doesn't nuke the password it just placed on the clipboard.
|
||||
procedure MinimizeToTray(AClearClipboard: Boolean = True);
|
||||
// Restore main window and remove tray icon.
|
||||
procedure RestoreFromTray;
|
||||
// Apply Windows dark-mode title bar to the main form. Win10 19044+
|
||||
@@ -160,8 +163,10 @@ type
|
||||
// If AUsername is empty, only the password is typed (no Tab) — matches
|
||||
// the password-only hotkey path AND avoids spurious Tab on entries
|
||||
// without a stored username.
|
||||
// AUsernameOnly = True → type ONLY the username (no Tab, no password);
|
||||
// used by the quick-search "autofill username" action.
|
||||
procedure ExecuteAutofill(ATargetHWND: HWND;
|
||||
const AUsername, APassword: string);
|
||||
const AUsername, APassword: string; AUsernameOnly: Boolean = False);
|
||||
property SecureClipboard: TSecureClipboard read FSecureClipboard;
|
||||
property TrayAdded: Boolean read FTrayAdded;
|
||||
property AutofillRegistered: Boolean read FAutofillRegistered;
|
||||
@@ -551,7 +556,7 @@ begin
|
||||
until LWnd = 0;
|
||||
end;
|
||||
|
||||
procedure TPMBridge.MinimizeToTray;
|
||||
procedure TPMBridge.MinimizeToTray(AClearClipboard: Boolean = True);
|
||||
var
|
||||
LFormHwnd, LAppHwnd: HWND;
|
||||
begin
|
||||
@@ -561,8 +566,12 @@ begin
|
||||
// Extra safety: clear the clipboard immediately when the user minimizes,
|
||||
// rather than waiting for the 30s auto-clear timer to fire. A password
|
||||
// the user just copied shouldn't sit in the clipboard while the app is
|
||||
// out of sight.
|
||||
FSecureClipboard.Clear;
|
||||
// out of sight. SKIPPED when AClearClipboard=False — the quick-search
|
||||
// copy-then-hide flow deliberately keeps the password on the clipboard
|
||||
// (the 30s auto-clear timer still guards it) so the user can paste it
|
||||
// into their target app after we minimise.
|
||||
if AClearClipboard then
|
||||
FSecureClipboard.Clear;
|
||||
|
||||
LFormHwnd := MainFormHWND(FMainForm);
|
||||
LAppHwnd := FindFMXAppWindow;
|
||||
@@ -1115,7 +1124,7 @@ begin
|
||||
end;
|
||||
|
||||
procedure TPMBridge.ExecuteAutofill(ATargetHWND: HWND;
|
||||
const AUsername, APassword: string);
|
||||
const AUsername, APassword: string; AUsernameOnly: Boolean = False);
|
||||
const
|
||||
MinimizeSettleMs = 80;
|
||||
FocusSettleDelayMs = 120;
|
||||
@@ -1135,6 +1144,16 @@ begin
|
||||
WaitForModifierRelease(1000);
|
||||
Sleep(FocusSettleDelayMs);
|
||||
|
||||
// Username-only: type just the username into the focused field, no Tab,
|
||||
// no password. Used by the quick-search right-click / Shift+Enter path.
|
||||
if AUsernameOnly then
|
||||
begin
|
||||
SendSelectAllAndDelete;
|
||||
Sleep(60);
|
||||
SendUnicodeString(AUsername);
|
||||
Exit;
|
||||
end;
|
||||
|
||||
if AUsername = '' then
|
||||
begin
|
||||
SendSelectAllAndDelete;
|
||||
|
||||
Reference in New Issue
Block a user