En AcroForm-handling er en dictionary knyttet til en widget, der fortæller viseren, hvad den skal gøre, når der sker noget med den widget. Klik på en knap, og viseren læser dens action-dictionary: en URI-handling åbner en webadresse, en JavaScript-handling kører et script, en SubmitForm-handling sender de indsamlede feltværdier til et endpoint, en ResetForm-handling nulstiller dem til standardværdierne. Handlingen er data, ikke adfærd bagt ind i filen. ISO 32000-1 §12.6 definerer dictionary-formen; viseren leverer motoren, der fortolker den. Den adskillelse betyder noget, fordi en handling, der er skrevet perfekt ind i PDF'en, stadig ikke gør noget, hvis læseren i den anden ende ikke har nogen motor til den, og en stor del af AcroForm-frustrationerne kan spores tilbage til det hul frem for til et defekt felt
HotPDF skriver disse dictionaries direkte fra Delphi og C++Builder, sammen med de feltwidgets, de hænger på. To strukturer er i spil for enhver interaktiv formular: den widget, brugeren ser på siden, og feltet plus action-maskineriet nedenunder, der bærer data og forbindelserne. De redigeres uafhængigt af hinanden, og den ene kan være forkert, mens den anden ser fin ud. Afsnittene nedenfor gennemgår feltnavngivning, selve knap-handlingerne, felt-niveau JavaScript og den klasse af fejl, der overlever et visuelt tjek, fordi den udelukkende bor i den anden struktur
Feltnavne er routingnøgler, ikke billedtekster
Hvert AcroForm-felt bærer et fuldt kvalificeret navn. ISO 32000-1 §12.7.3 gør netop det navn, ikke den synlige billedtekst, til nøglen, som feltets værdi rejser under, når formularen eksporteres eller sendes ind. Udviklere, der kommer fra VCL-design, har en tendens til at behandle en kontrols navn som en privat kodeidentifikator, og det er det ikke her. Det er transportformatet
Det første, der følger af det, er, at to felter med samme fuldt kvalificerede navn ikke er to felter. PDF behandler dem som to widget-annotationer af ét felt, der deler én værdi, så det at skrive i det ene opdaterer det andet med det samme. Det er præcis, hvad man ønsker, når et kundenavn skal gentages på hver side af en kontrakt. Det er en fejl, når en generationsløkke ved et uheld genbruger 'Field1' på tværs af tre sider. Ingen visuel inspektion fanger det andet tilfælde. Hver side tegner stadig sin egen boks, og forbindelsen viser sig først, når nogen begynder at skrive
Navne med punktum, såsom applicant.email, opbygger et hierarki. Forælderknuden applicant grupperer sine børn, hvilket er det, der gør det muligt for en nulstilling eller indsendelse kun at målrette en del af en formular. At navngive felter på denne måde fra starten koster intet, og det betaler sig selv, den første gang det modtagende system kun beder om applicant-blokken
Radioknapper har deres egen regel. Knapper, der skal skifte sammen, skal dele et gruppenavn. I HotPDF knytter kald til AddRadioButton, der sender det samme gruppenavn, deres widgets til ét overordnet felt, og hver knaps eksportværdi ('basic' eller 'full') identificerer den valgte mulighed. Giv hver knap et unikt navn, og man får en række uafhængige tænd/sluk-kontakter i stedet for én gensidigt udelukkende gruppe, hvilket gengives identisk, men opfører sig forkert
Oprettelse af feltsættet side for side
HotPDF placerer felter via THPDFPage-metoder, så hvert felt tilhører det side-objekt, der oprettede det. Den rækkefølgefælde, man skal holde øje med, er AddPage. Den omdirigerer CurrentPage til den nye side i samme øjeblik, den returnerer, så ethvert feltkald derefter havner på den nye side, selv når feltet logisk hørte til den side, man lige har forladt. Afslut hver side, tegnet indhold og felter sammen, før du kalder AddPage
procedure BuildClaimForm(Pdf: THotPDF);
begin
// Side 1: applicant-blok
Pdf.CurrentPage.AddTextField('applicant.name', '', Rect(50, 700, 300, 722));
Pdf.CurrentPage.AddTextField('applicant.email', '', Rect(50, 660, 300, 682));
Pdf.CurrentPage.AddCheckBox('consent', 'Y', Rect(50, 620, 70, 640), False);
Pdf.CurrentPage.AddRadioButton('coverage', 'basic', Rect(50, 580, 70, 600), True);
Pdf.CurrentPage.AddRadioButton('coverage', 'full', Rect(90, 580, 110, 600), False);
Pdf.CurrentPage.AddComboBox('plan', 'Standard',
['Basic', 'Standard', 'Premium'], Rect(50, 540, 200, 565));
Pdf.AddPage; // CurrentPage peger nu på side 2
Pdf.CurrentPage.AddListBox('riders', 'None',
['None', 'Flood', 'Earthquake'], Rect(50, 500, 200, 600));
end;
Koordinater følger PDF-konventionen, med origo i sidens nederste venstre hjørne. Det er det samme origo, som TextOut bruger til tegnet tekst, så Rect(50, 100, 200, 120) ligger nær bunden af en Letter-side, ikke toppen. VCL placerer Y øverst og lader det vokse nedad, så en layouttabel, der overføres direkte, kommer ud spejlvendt lodret, hvor hvert felt havner i den forkerte ende af siden. Lav konverteringen én gang i en fælles hjælpefunktion i stedet for ved hvert kaldested, så retter en enkelt rettelse hele formularen
Kobling af knapper til URI-, JavaScript- og submit-handlinger
En trykknap er inaktiv, indtil en handling knyttes til den. HotPDF eksponerer handlingstyperne fra ISO 32000-1 §12.6.4 gennem opremsningen THPDFButtonAction (baURI, baJavaScript, baSubmitURL, baResetForm, baHide, baShow, baNamed) og tilbyder to metoder, der opretter knappen og binder dens handling i ét kald
// Åbn en hjælpeside i systembrowseren
Pdf.CurrentPage.AddPushButtonWithAction('btnHelp', 'Help',
'https://www.example.com/claims-help', Rect(320, 700, 420, 730), baURI);
// Kør JavaScript i viseren
Pdf.CurrentPage.AddPushButtonWithAction('btnRecalc', 'Recalculate',
'app.alert("Totals updated.");', Rect(320, 660, 420, 690), baJavaScript);
// Send som XFDF, og bevar tomme felter i payloaden
Pdf.CurrentPage.AddPushButtonWithSubmitAction('btnSubmit', 'Submit claim',
'https://api.example.com/claims', Rect(320, 620, 420, 650),
[sffXFDF, sffIncludeNoValueFields]);
Submit-flagene fortjener mere eftertanke, end de normalt får. AddPushButtonWithSubmitAction tager et THPDFSubmitFormFlags-sæt, og et tomt sæt giver et almindeligt url-kodet post, hvilket er det format, mange eksempel-endpoints accepterer, men mange produktions-endpoints afviser. At tilføje sffXFDF skifter payloaden til XFDF. sffGetMethod ændrer HTTP-verbet. sffIncludeNoValueFields beholder tomme felter i payloaden i stedet for at droppe dem stiltiende, hvilket betyder noget, i det øjeblik forbrugeren skelner mellem "fraværende" og "tom". Flagsættet er en del af din grænsefladekontrakt med det modtagende endpoint, så aftal det med det team, der parser indsendelsen, ikke efter det første afviste batch
Felt-niveau JavaScript: keystroke, format, validate
Knapklik er ikke det eneste sted, handlinger bor. HotPDF knytter også JavaScript til de felt-specifikke hændelser, som script-kompatible visere udløser, mens en bruger indtaster data. Der er tre triggere, og de udløses på forskellige punkter i input-livscyklussen. En keystroke-handling kører, hver gang et tegn ankommer, og igen ved commit. En format-handling omskriver den viste værdi, efter en ændring er committet, udelukkende af hensyn til visningen. En validate-handling har det sidste ord og accepterer eller afviser den committede værdi, før den bliver feltets værdi
// Afvis committede værdier, der ikke er plausible e-mailadresser
Pdf.AttachFieldKeyStrokeAction('applicant.email',
'if (event.willCommit && !/^[\w.-]+@[\w.-]+\.\w+$/.test(event.value)) event.rc = false;');
// Vis amerikanske telefonnumre som (NNN) NNN-NNNN
Pdf.AttachFieldFormatAction('applicant.phone',
'event.value = event.value.replace(/(\d{3})(\d{3})(\d{4})/, "($1) $2-$3");');
// Afvis ansøgere under 18 år ved commit
Pdf.AttachFieldValidateAction('applicant.age',
'if (parseInt(event.value) < 18) event.rc = false;');
At sætte event.rc = false inde i et keystroke- eller validate-script fortæller viseren, at input skal afvises. Hagen er, at intet af dette kører, medmindre viseren leverer en JavaScript-motor. Acrobat og nogle få desktop-produkter har en. De fleste mobile læsere, browser-indlejrede renderere og udskriftspipelines har det ikke, og de dropper scriptene uden varsel. Så feltscripts forbedrer datakvaliteten for den delmængde af brugere, hvis læser kører dem, og det er alt, de gør. De er ikke en sikkerhedsgrænse. Hver indsendt værdi skal stadig valideres på serveren, når den ankommer, fordi man ikke kan antage, at klienten har tjekket noget som helst
Fejl, der består visuel gennemgang
De sværeste AcroForm-fejl at fange er dem, der bor i datastrukturen frem for i gengivelsen, fordi det at åbne filen og kigge på den ikke fortæller én noget. Fire går igen tilstrækkeligt ofte til at være værd at nævne, og hver af dem har en mekanisk test, der finder den, før udgivelse
- Eksportværdi-drift. Et afkrydsningsfelt oprettet som
AddCheckBox('consent', 'Yes', ...)senderYes. En modtager, der matcher påY, afviser hver eneste indsendelse, mens siden ser perfekt ud. Udfyld formularen, eksportér den som XFDF fra Acrobat, og diff værdierne mod det skema, modtageren rent faktisk forventer - Utilsigtet værdispejling. To felter, der deler et fuldt kvalificeret navn, smelter sammen til ét. Symptomet viser sig, når data indtastes, og aldrig ved generering, så testen er at skrive i formularen, ikke at gengive den og vurdere resultatet med øjet
- Combo-værdier uden for mulighedslisten. Når den aktuelle værdi, der sendes til
AddComboBox, ikke er en af de angivne muligheder, er visere uenige om, hvorvidt den skal vises, tømmes eller markeres. Hold standardværdien inden for listen, og uenigheden forsvinder - Felter, der stadig kan redigeres, efter workflowet er lukket. HotPDF har intet flatten-kald for udseendet af AcroForm-felter. Den understøttede måde at fastfryse en udfyldt formular på er at oprette felterne med flaget
ffReadOnly, som holder værdien synlig gennem feltets eget appearance-stream, samtidig med at redigering afvises. Feltet forbliver et levende formularobjekt, hvilket er, hvad downstream-samling og signeringsværktøjer forventer at finde
Én adfærd i viseren er værd en regressionsnote, selvom ingen kodeændring adresserer den. Virksomhedsinstallationer af Acrobat kan deaktivere JavaScript eller begrænse submit-mål via politik, så en handling, der virkede gennem hvert eneste udviklingsbuild, kan ligge død på en låst kundedesktop. Planlæg et synligt fallback for det tilfælde, hvor knappen intet gør, selv hvis det fallback blot er en trykt instruktion, der fortæller brugeren, hvad han eller hun skal gøre i stedet
Hvor formulararbejdet forbinder sig til resten af dokumentet
Et signaturfelt er i sig selv en AcroForm-felttype. En formular, der senere skal certificeres eller modunderskrives, er bedre tjent med at reservere det felt under genereringen end at få det lappet ind bagefter, og grundene til det på byte-niveau findes i følgeartiklen om digitale signaturer og PAdES-signering med HotPDF. Input, der ankommer som XFA-pakker frem for native AcroForm, er en anden situation: at flade XFA ud til AcroForm-felter er sin egen workflow med sin egen tabsmodel, fordi de to formularteknologier ikke kan sameksistere i én fil
Felt-, handlings- og trigger-metoderne, der er vist her, er en del af den almindelige HotPDF Delphi Component-API til Delphi og C++Builder; produktsiden linker til den fulde reference, herunder feltflag-overloads og den komplette opremsning af submit-flag