Skip to content

Commit c8b2a2f

Browse files
committed
Add functions to get javascript actions and widget javascript actions
1 parent 58a39a7 commit c8b2a2f

8 files changed

Lines changed: 537 additions & 154 deletions

File tree

packages/engines/src/lib/orchestrator/pdf-engine.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@ import {
2525
PdfAnnotationsProgress,
2626
PdfAttachmentObject,
2727
PdfAddAttachmentParams,
28+
PdfDocumentJavaScriptActionObject,
2829
PdfWidgetAnnoObject,
2930
PdfWidgetAnnoField,
31+
PdfWidgetJavaScriptActionObject,
3032
FormFieldValue,
3133
PdfFlattenPageOptions,
3234
PdfPageFlattenResult,
@@ -776,6 +778,18 @@ export class PdfEngine<T = Blob> implements IPdfEngine<T> {
776778

777779
// ========== Forms ==========
778780

781+
getDocumentJavaScriptActions(
782+
doc: PdfDocumentObject,
783+
): PdfTask<PdfDocumentJavaScriptActionObject[]> {
784+
return this.workerQueue.enqueue(
785+
{
786+
execute: () => this.executor.getDocumentJavaScriptActions(doc),
787+
meta: { docId: doc.id, operation: 'getDocumentJavaScriptActions' },
788+
},
789+
{ priority: Priority.MEDIUM },
790+
);
791+
}
792+
779793
getPageAnnoWidgets(doc: PdfDocumentObject, page: PdfPageObject): PdfTask<PdfWidgetAnnoObject[]> {
780794
return this.workerQueue.enqueue(
781795
{
@@ -786,6 +800,19 @@ export class PdfEngine<T = Blob> implements IPdfEngine<T> {
786800
);
787801
}
788802

803+
getPageWidgetJavaScriptActions(
804+
doc: PdfDocumentObject,
805+
page: PdfPageObject,
806+
): PdfTask<PdfWidgetJavaScriptActionObject[]> {
807+
return this.workerQueue.enqueue(
808+
{
809+
execute: () => this.executor.getPageWidgetJavaScriptActions(doc, page),
810+
meta: { docId: doc.id, pageIndex: page.index, operation: 'getPageWidgetJavaScriptActions' },
811+
},
812+
{ priority: Priority.MEDIUM },
813+
);
814+
}
815+
789816
setFormFieldValue(
790817
doc: PdfDocumentObject,
791818
page: PdfPageObject,

packages/engines/src/lib/orchestrator/remote-executor.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ import {
2020
PdfAddAttachmentParams,
2121
PdfWidgetAnnoObject,
2222
PdfWidgetAnnoField,
23+
PdfDocumentJavaScriptActionObject,
24+
PdfWidgetJavaScriptActionObject,
2325
FormFieldValue,
2426
PdfFlattenPageOptions,
2527
PdfPageFlattenResult,
@@ -97,7 +99,9 @@ type MessageType =
9799
| 'addAttachment'
98100
| 'removeAttachment'
99101
| 'readAttachmentContent'
102+
| 'getDocumentJavaScriptActions'
100103
| 'getPageAnnoWidgets'
104+
| 'getPageWidgetJavaScriptActions'
101105
| 'setFormFieldValue'
102106
| 'setFormFieldState'
103107
| 'regenerateWidgetAppearances'
@@ -458,10 +462,26 @@ export class RemoteExecutor implements IPdfiumExecutor {
458462
return this.send<ArrayBuffer>('readAttachmentContent', [doc, attachment]);
459463
}
460464

465+
getDocumentJavaScriptActions(
466+
doc: PdfDocumentObject,
467+
): PdfTask<PdfDocumentJavaScriptActionObject[]> {
468+
return this.send<PdfDocumentJavaScriptActionObject[]>('getDocumentJavaScriptActions', [doc]);
469+
}
470+
461471
getPageAnnoWidgets(doc: PdfDocumentObject, page: PdfPageObject): PdfTask<PdfWidgetAnnoObject[]> {
462472
return this.send<PdfWidgetAnnoObject[]>('getPageAnnoWidgets', [doc, page]);
463473
}
464474

475+
getPageWidgetJavaScriptActions(
476+
doc: PdfDocumentObject,
477+
page: PdfPageObject,
478+
): PdfTask<PdfWidgetJavaScriptActionObject[]> {
479+
return this.send<PdfWidgetJavaScriptActionObject[]>('getPageWidgetJavaScriptActions', [
480+
doc,
481+
page,
482+
]);
483+
}
484+
465485
setFormFieldValue(
466486
doc: PdfDocumentObject,
467487
page: PdfPageObject,

packages/engines/src/lib/pdfium/engine.ts

Lines changed: 172 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,11 @@ import {
7272
PdfPageGeometry,
7373
PdfRun,
7474
toIntRect,
75+
PdfDocumentJavaScriptActionObject,
76+
PdfWidgetJavaScriptActionObject,
77+
PdfJavaScriptActionTrigger,
78+
PdfJavaScriptWidgetEventType,
79+
PDF_ANNOT_AACTION_EVENT,
7580
Quad,
7681
PdfAnnotationState,
7782
PdfAnnotationStateModel,
@@ -826,6 +831,64 @@ export class PdfiumNative implements IPdfiumExecutor {
826831
return task;
827832
}
828833

834+
getDocumentJavaScriptActions(
835+
doc: PdfDocumentObject,
836+
): PdfTask<PdfDocumentJavaScriptActionObject[], PdfErrorReason> {
837+
this.logger.debug(LOG_SOURCE, LOG_CATEGORY, 'getDocumentJavaScriptActions', doc);
838+
839+
const ctx = this.cache.getContext(doc.id);
840+
if (!ctx) {
841+
return PdfTaskHelper.reject({
842+
code: PdfErrorCode.DocNotOpen,
843+
message: 'document does not open',
844+
});
845+
}
846+
847+
const count = this.pdfiumModule.FPDFDoc_GetJavaScriptActionCount(ctx.docPtr);
848+
if (count < 0) {
849+
return PdfTaskHelper.reject({
850+
code: PdfErrorCode.Unknown,
851+
message: 'failed to read document javascript actions',
852+
});
853+
}
854+
855+
const actions: PdfDocumentJavaScriptActionObject[] = [];
856+
for (let index = 0; index < count; index++) {
857+
const actionPtr = this.pdfiumModule.FPDFDoc_GetJavaScriptAction(ctx.docPtr, index);
858+
if (!actionPtr) continue;
859+
860+
try {
861+
const name =
862+
readString(
863+
this.pdfiumModule.pdfium,
864+
(buffer: number, bufferLength) =>
865+
this.pdfiumModule.FPDFJavaScriptAction_GetName(actionPtr, buffer, bufferLength),
866+
this.pdfiumModule.pdfium.UTF16ToString,
867+
) ?? '';
868+
const script =
869+
readString(
870+
this.pdfiumModule.pdfium,
871+
(buffer: number, bufferLength) =>
872+
this.pdfiumModule.FPDFJavaScriptAction_GetScript(actionPtr, buffer, bufferLength),
873+
this.pdfiumModule.pdfium.UTF16ToString,
874+
) ?? '';
875+
876+
if (!script) continue;
877+
878+
actions.push({
879+
id: `document:${index}:${name}`,
880+
trigger: PdfJavaScriptActionTrigger.DocumentNamed,
881+
name,
882+
script,
883+
});
884+
} finally {
885+
this.pdfiumModule.FPDFDoc_CloseJavaScriptAction(actionPtr);
886+
}
887+
}
888+
889+
return PdfTaskHelper.resolve(actions);
890+
}
891+
829892
getPageAnnoWidgets(
830893
doc: PdfDocumentObject,
831894
page: PdfPageObject,
@@ -876,6 +939,108 @@ export class PdfiumNative implements IPdfiumExecutor {
876939
return PdfTaskHelper.resolve(annotationWidgets);
877940
}
878941

942+
getPageWidgetJavaScriptActions(
943+
doc: PdfDocumentObject,
944+
page: PdfPageObject,
945+
): PdfTask<PdfWidgetJavaScriptActionObject[], PdfErrorReason> {
946+
this.logger.debug(LOG_SOURCE, LOG_CATEGORY, 'getPageWidgetJavaScriptActions', doc, page);
947+
948+
const ctx = this.cache.getContext(doc.id);
949+
if (!ctx) {
950+
return PdfTaskHelper.reject({
951+
code: PdfErrorCode.DocNotOpen,
952+
message: 'document does not open',
953+
});
954+
}
955+
956+
const actions: PdfWidgetJavaScriptActionObject[] = [];
957+
ctx.borrowPage(page.index, (pageCtx) => {
958+
pageCtx.withFormHandle((formHandle) => {
959+
const annotCount = this.pdfiumModule.FPDFPage_GetAnnotCount(pageCtx.pagePtr);
960+
for (let i = 0; i < annotCount; i++) {
961+
pageCtx.withAnnotation(i, (annotPtr) => {
962+
const subtype = this.pdfiumModule.FPDFAnnot_GetSubtype(
963+
annotPtr,
964+
) as PdfAnnotationObject['type'];
965+
if (subtype !== PdfAnnotationSubtype.WIDGET) return;
966+
967+
let annotationId = this.getAnnotString(annotPtr, 'NM');
968+
if (!annotationId || !isUuidV4(annotationId)) {
969+
annotationId = uuidV4();
970+
this.setAnnotString(annotPtr, 'NM', annotationId);
971+
}
972+
973+
const fieldName =
974+
readString(
975+
this.pdfiumModule.pdfium,
976+
(buffer: number, bufferLength) =>
977+
this.pdfiumModule.FPDFAnnot_GetFormFieldName(
978+
formHandle,
979+
annotPtr,
980+
buffer,
981+
bufferLength,
982+
),
983+
this.pdfiumModule.pdfium.UTF16ToString,
984+
) ?? '';
985+
986+
const eventConfigs = [
987+
{
988+
event: PDF_ANNOT_AACTION_EVENT.KEY_STROKE,
989+
eventType: PdfJavaScriptWidgetEventType.Keystroke,
990+
trigger: PdfJavaScriptActionTrigger.WidgetKeystroke,
991+
},
992+
{
993+
event: PDF_ANNOT_AACTION_EVENT.FORMAT,
994+
eventType: PdfJavaScriptWidgetEventType.Format,
995+
trigger: PdfJavaScriptActionTrigger.WidgetFormat,
996+
},
997+
{
998+
event: PDF_ANNOT_AACTION_EVENT.VALIDATE,
999+
eventType: PdfJavaScriptWidgetEventType.Validate,
1000+
trigger: PdfJavaScriptActionTrigger.WidgetValidate,
1001+
},
1002+
{
1003+
event: PDF_ANNOT_AACTION_EVENT.CALCULATE,
1004+
eventType: PdfJavaScriptWidgetEventType.Calculate,
1005+
trigger: PdfJavaScriptActionTrigger.WidgetCalculate,
1006+
},
1007+
] as const;
1008+
1009+
for (const config of eventConfigs) {
1010+
const script =
1011+
readString(
1012+
this.pdfiumModule.pdfium,
1013+
(buffer: number, bufferLength) =>
1014+
this.pdfiumModule.FPDFAnnot_GetFormAdditionalActionJavaScript(
1015+
formHandle,
1016+
annotPtr,
1017+
config.event,
1018+
buffer,
1019+
bufferLength,
1020+
),
1021+
this.pdfiumModule.pdfium.UTF16ToString,
1022+
) ?? '';
1023+
1024+
if (!script) continue;
1025+
1026+
actions.push({
1027+
id: `widget:${page.index}:${annotationId}:${config.eventType}`,
1028+
trigger: config.trigger,
1029+
eventType: config.eventType,
1030+
pageIndex: page.index,
1031+
annotationId,
1032+
fieldName,
1033+
script,
1034+
});
1035+
}
1036+
});
1037+
}
1038+
});
1039+
});
1040+
1041+
return PdfTaskHelper.resolve(actions);
1042+
}
1043+
8791044
regenerateWidgetAppearances(
8801045
doc: PdfDocumentObject,
8811046
page: PdfPageObject,
@@ -2135,7 +2300,13 @@ export class PdfiumNative implements IPdfiumExecutor {
21352300
}
21362301

21372302
this.pdfiumModule.FORM_ForceToKillFocus(formHandle);
2138-
this.pdfiumModule.EPDFAnnot_GenerateFormFieldAP(annotationPtr);
2303+
2304+
if (
2305+
field.type !== PDF_FORM_FIELD_TYPE.CHECKBOX &&
2306+
field.type !== PDF_FORM_FIELD_TYPE.RADIOBUTTON
2307+
) {
2308+
this.pdfiumModule.EPDFAnnot_GenerateFormFieldAP(annotationPtr);
2309+
}
21392310

21402311
this.logger.perf(
21412312
LOG_SOURCE,

packages/engines/src/lib/webworker/engine.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {
22
FormFieldValue,
33
PdfWidgetAnnoField,
44
PdfAttachmentObject,
5+
PdfDocumentJavaScriptActionObject,
56
PdfFile,
67
PdfMetadataObject,
78
PdfSignatureObject,
@@ -40,6 +41,7 @@ import {
4041
PdfAnnotationsProgress,
4142
PdfPrintOptions,
4243
PdfBookmarkObject,
44+
PdfWidgetJavaScriptActionObject,
4345
PdfAddAttachmentParams,
4446
AnnotationAppearanceMap,
4547
ImageDataLike,
@@ -588,6 +590,31 @@ export class WebWorkerEngine implements PdfEngine {
588590
return task;
589591
}
590592

593+
getDocumentJavaScriptActions(doc: PdfDocumentObject) {
594+
this.logger.debug(LOG_SOURCE, LOG_CATEGORY, 'getDocumentJavaScriptActions', doc);
595+
const requestId = this.generateRequestId(doc.id);
596+
const task = new WorkerTask<PdfDocumentJavaScriptActionObject[]>(this.worker, requestId);
597+
598+
const request: ExecuteRequest = createRequest(requestId, 'getDocumentJavaScriptActions', [doc]);
599+
this.proxy(task, request);
600+
601+
return task;
602+
}
603+
604+
getPageWidgetJavaScriptActions(doc: PdfDocumentObject, page: PdfPageObject) {
605+
this.logger.debug(LOG_SOURCE, LOG_CATEGORY, 'getPageWidgetJavaScriptActions', doc, page);
606+
const requestId = this.generateRequestId(doc.id);
607+
const task = new WorkerTask<PdfWidgetJavaScriptActionObject[]>(this.worker, requestId);
608+
609+
const request: ExecuteRequest = createRequest(requestId, 'getPageWidgetJavaScriptActions', [
610+
doc,
611+
page,
612+
]);
613+
this.proxy(task, request);
614+
615+
return task;
616+
}
617+
591618
/**
592619
* {@inheritDoc @embedpdf/models!PdfEngine.createPageAnnotation}
593620
*

0 commit comments

Comments
 (0)