feat: add an onClick option for a form field's mouse-up action - #1790
Conversation
105406c to
dde6b58
Compare
|
Updated: on reflection this shouldn't widen the discouraged raw |
dde6b58 to
cea74ed
Compare
|
Updated again: onClick now calls the function with app/getField/display/event as parameters (this bound to the Document) instead of relying on ambient TypeScript globals — a plain global |
8732f59 to
6e700f0
Compare
|
Note: the aa-before.pdf/aa-after.pdf attached above were built against an earlier version of this PR (the raw |
blikblum
left a comment
There was a problem hiding this comment.
Besides onClick, is there other event that can be set?
| doc.formPushButton('btn1', 10, 200, 100, 30, opts); | ||
| ``` | ||
|
|
||
| `onClick` also accepts a plain function, called with Acrobat's own `app`, |
There was a problem hiding this comment.
Simplify the description. Be objective hiding internal details, just with enough information to user create correct functions
There was a problem hiding this comment.
Rewritten. The push-button option is now a single line pointing at a short "Field Actions" section under Common Annotation Options, which lists the six options one line each and shows a string example and a function example. No stringification details, no this-binding rationale, no array.map analogy.
| onClick: function (app, getField) { | ||
| app.alert('clicked'); | ||
| this.getField('otherField').value = 'updated from btn1'; | ||
| } |
There was a problem hiding this comment.
param getField is not used. Is really necessary?
There was a problem hiding this comment.
No — removed. The action is now written as (fn).call(this); with no arguments at all: the viewer's globals are already in scope inside the action, so there was never a need to pass them in. The only reason they were parameters was to avoid ambient global declarations for the types file, which is gone too.
| TypeScript projects can import `AcrobatOnClick` and the other types this | ||
| signature uses from `pdfkit/types/acrobat-js` — a small, best-effort set of | ||
| types for the handful of Acrobat globals most `onClick` handlers need, kept | ||
| separate from pdfkit's own types so nothing is declared globally: |
There was a problem hiding this comment.
Nop. Types will be handled separately. Do not expose it for now. It can be documented internally
There was a problem hiding this comment.
Removed. types/acrobat-js.d.ts is deleted, the package.json export is gone, and this documentation section with it. Nothing about types is exposed by the PR any more.
| ### Advanced Form Field Use | ||
|
|
||
| Older implementations used to pass all unknown options to the internal PDF object structure. A small set of direct PDF dictionary escape hatches is still recognized: `Ff`, `MK.CA`, and `AA` when a `format` option is used but its use is discouraged and likely will be removed in future versions. | ||
| Older implementations used to pass all unknown options to the internal PDF object structure. A small set of direct PDF dictionary escape hatches is still recognized: `Ff` and `MK.CA`, but their use is discouraged and they may be removed in future versions. A previously-recognized `AA` escape hatch (only reachable together with a `format` option) has been replaced by the `onClick` option above, which needs no PDF dictionary knowledge and works on its own. |
There was a problem hiding this comment.
Nop. This is not a changelog and no need to justify
There was a problem hiding this comment.
Removed, and the paragraph is back to master's wording, untouched. It only needed rewording because the original diff had dropped the AA escape hatch; I kept the escape hatch working instead, so the sentence is still accurate as written. mapFormat() runs first and still seeds pdfObject.AA from options.AA, and the action options merge into that dictionary afterwards.
| // generated, so it can't close over outside variables, and only plain | ||
| // function syntax (not arrow functions or other syntax Acrobat's engine | ||
| // may not support) should be relied on. | ||
| const js = |
There was a problem hiding this comment.
Keep it simple, pass the base minimum arguments to get it working
There was a problem hiding this comment.
Done — it passes no arguments now, just (fn).call(this);. Only the this binding remains, which is the binding a viewer already gives any field action, and it is one token rather than a parameter list.
| "require": "./js/output.cjs", | ||
| "default": "./js/output.mjs" | ||
| }, | ||
| "./types/acrobat-js": { |
There was a problem hiding this comment.
Reverted. package.json is unchanged from master in this PR now.
…rk-only) Not for upstream: this lets Yarn install this branch directly from GitHub without a build step, since pdfkit has no committed build output and Yarn Classic v1 does not reliably run "prepare"/"postinstall" for a nested git dependency's own devDependencies. Consumed by the Plan monorepo while foliojs#1789 and foliojs#1790 are under review; rebuild and recommit js/ if this branch is rebased onto a newer upstream master.
Add `onClick`, `onMouseDown`, `onMouseEnter`, `onMouseExit`, `onFocus` and `onBlur` to the options every form annotation method accepts, mapping to the widget annotation's /AA entries. Each takes the JavaScript to run, as a string or as a plain function whose source text is written into the action. The `AA` escape hatch keeps working exactly as documented: mapFormat() still seeds the dictionary from it, and the action options are merged in afterwards.
6e700f0 to
5ccc29d
Compare
…rk-only) Not for upstream: this lets Yarn install this branch directly from GitHub without a build step, since pdfkit has no committed build output and Yarn Classic v1 does not reliably run "prepare"/"postinstall" for a nested git dependency's own devDependencies. Consumed by the Plan monorepo while foliojs#1789 and foliojs#1790 are under review; rebuild and recommit js/ if this branch is rebased onto a newer upstream master.
|
Thanks — pushed an update addressing all of it. "Besides onClick, is there other event that can be set?" Yes. The widget annotation's Since the mapping is just a table, I exposed the six interaction events rather than special-casing one: const ANNOTATION_ACTIONS = {
onClick: 'U', onMouseDown: 'D', onMouseEnter: 'E',
onMouseExit: 'X', onFocus: 'Fo', onBlur: 'Bl',
};I left the four page-level ones out — they describe the page rather than the field, and I have no use case for them. Happy to cut this back to The inline comments
The diff is additions only now — no edits to existing docs text and no |
|
Many thanks |
What kind of change does this PR introduce?
Feature. Fixes #1792.
A small, purpose-built option, along the lines invited in
docs/forms.md's Advanced Form Field Use section ("If an option is not supported, open an issue on Github and it will be considered for addition to the API").Context
There's no supported way to attach a mouse-up JavaScript action to a form field — most usefully, a push button that runs custom logic when clicked. The only path that ever reaches
AAismapFormat(), and only together with aformatoption, which is meant for keystroke/format validation, not arbitrary actions.That's deliberate, not an oversight: pdfkit's docs explicitly say the handful of raw dictionary escape hatches still recognized (
Ff,MK.CA,AA-with-format) are discouraged and may be removed. So rather than widening that raw access further, this adds a dedicated option instead.The change
Adds an
onClickoption, accepted by all form annotation methods, mapped by a newmapActions(options, pdfObject)step (mirroring the other unconditional mappers) that sets the field'sAA.Umouse-up action.mapFormat()still runs afterward and extends the sameAAdictionary with format-validation actions when aformatoption is also given, so that combination keeps working.onClickaccepts either a plain string or a function. A function is stringified and invoked withthisbound to the Document (exactly as Acrobat itself binds it in any field action) and Acrobat's ownapp,getField,displayandeventpassed in as arguments — the same pattern tools like Puppeteer use forpage.evaluate(fn). It still runs inside the PDF viewer's own JavaScript engine, not wherever the PDF was generated, so it can't close over outside variables.Passing the globals as parameters, rather than the more obvious route of declaring them as ambient TypeScript globals, is deliberate: a global
eventcollides with the DOM lib's own deprecatedwindow.eventin any project with"dom"in itslibarray, which I only found by actually trying it. Parameters sidestep that entirely — nothing is declared globally, so there's nothing to collide with.A new
types/acrobat-js.d.ts(exported viapackage.json'sexportsmap) gives TypeScript projects real types for this signature, kept separate from pdfkit's own types so nothing is pulled in just by installing pdfkit:This is deliberately a minimal, best-effort common subset (
app,getField,display,event, the Documentthis), not a full Acrobat SDK type surface — documented as such, with contributions welcome to extend it.Demo
Attached: a minimal PDF pair (a push button with an
onClickaction, before/after this change) plus screenshots from Adobe Acrobat/Reader. Before: clicking the button does nothing. After: it shows an alert.Testing
yarn test:unit— all existing tests pass unchanged, plus new ones: a push button with a stringonClick, one with a functiononClick, and the combinedonClick+formatcase.yarn lint/yarn format— clean.node) andnode16TypeScript module resolution, and against a project with"dom"inlib, using a throwaway project outside this repo (not part of the diff).Checklist:
cc @blikblum for review.