Runtime interactivo de widgets XFA dinámicos
TXFAWidgetRuntime proporciona un modelo de interacción neutral al host para formularios XFA dinámicos sin convertirlos en campos AcroForm ni aplanar su contenido
El runtime expone bounds y estado de widgets deterministas, de modo que un renderer de escritorio, un servicio o uno propio pueda aportar su propio input, pintado, accesibilidad y event loop
Creación de un runtime
Cree el runtime directamente desde bytes XDP o llame a THotPDF.CreateLoadedXFAWidgetRuntime después de cargar un PDF cuyo AcroForm contenga una entrada /XFA de stream único o de arreglo de packets
var
Runtime: TXFAWidgetRuntime;
State: TXFAWidgetState;
begin
Runtime := PDF.CreateLoadedXFAWidgetRuntime;
try
if (Runtime <> nil) and (Runtime.WidgetCount > 0) then
begin
State := Runtime.Widgets[0];
Runtime.FocusWidget(State.ID);
Runtime.BeginEdit(State.ID);
Runtime.ReplaceSelection(0, Length(State.Value), 'Updated value');
if not Runtime.CommitEdit then
raise Exception.Create(Runtime.LastDiagnostic);
end;
finally
Runtime.Free;
end;
end;
La fábrica del documento cargado es de solo lectura respecto del grafo de objetos PDF y de los XFAFlattenWarnings existentes; al guardar, el documento conserva sus entradas /XFA y /NeedsRendering originales
Modelo de interacción
FocusWidgetyClearFocusmantienen un único widget con focus, ejecutan scripts enter/exit y publican callbacks ordenados después de la confirmaciónBeginEdit,ReplaceSelection,CancelEdityCommitEditpreservan el texto Unicode incluidos los espacios al inicio y al finalHitTestmapea coordenadas de página al widget visible más altoOnWidgetInvalidated,OnLayoutChangedyOnFocusChangedpermiten al host refrescar solo el estado afectado
Los commits interactivos sincronizan los valores escalares nativos existentes en los aliases ocultos e invisibles, incluyendo los scopes reales de datos repetidos y el rollback exacto byte a byte
Validación y cálculo atómicos
Un commit resuelve los bindings SOM explícitos y el contexto de datos actual de filas repetidas antes de ejecutar los scripts de validate y calculate
El valor editado, los valores calculados, los nodos de datos, el modelo de widgets, el estado de focus y edición, las advertencias y los contadores de pasadas se publican juntos solo después de que la validación y el layout se estabilizan
Los scripts rechazados, los presupuestos agotados, los límites de selección UTF-16 inválidos y las excepciones de layout o de medición del host restauran el estado anterior completo y establecen LastDiagnostic
Presupuestos
TXFAWidgetRuntimeOptions limita la cantidad de widgets, la longitud del valor editado, las pasadas de cálculo, las pasadas de reflow, las operaciones de layout, las operaciones de script, el tiempo transcurrido de script y otros recursos de FormCalc o JavaScript
El tope de widgets se aplica mientras se agregan layout items y fragmentos de paginación, mientras que la descompresión del XFA cargado y el ensamblado de packets se detienen en el límite de input del XFA DOM antes del parseo
MaxLayoutOperations tiene un valor por defecto de 200000 y acota tanto el recorrido del documento como el trabajo de layout; la profundidad del layout se limita a 128, la profundidad de targets de eventos y de inicialización de instancias a 64, y el dispatch recursivo de eventos se rechaza
Eventos dinámicos literales por defecto
DispatchEvent acepta operaciones literales separadas por punto y coma en los event scripts de campo coincidentes con content types de FormCalc o JavaScript; estas operaciones se parsean directamente y no requieren una DLL de JavaScript
row.instanceManager.addInstance(true);
row.instanceManager.removeInstance(0);
target.presence = "hidden";
addInstance agrega una instancia y acepta true, false, 1 o 0 como argumento de merge; un argumento omitido usa true, y la forma abreviada _row.addInstance(1) también se acepta
El modelo soportado hace binding de todos los grupos de datos existentes con el mismo nombre, así que una instancia nueva recibe un grupo de datos nuevo inicializado con los valores por defecto de la plantilla para cualquier argumento de merge; la creación de instancias no clona los valores ingresados de la fila anterior
removeInstance usa un índice entero base cero entre los grupos de datos del mismo nombre del subform seleccionado; el subform debe tener un elemento occur con un máximo repetible, y ambas operaciones hacen cumplir su mínimo y máximo, incluido max="-1"
La mutación de instancias exige binding implícito por nombre al dataset y nombres de datos XML ASCII; el binding explícito por referencia de datos y los contextos de padre ambiguos se rechazan antes de publicar la transacción
Los targets se resuelven a través de hijos con nombre de la plantilla en los scopes que envuelven al evento, incluidos los paths con puntos y this.parent; un manager anidado dentro de un scope repetido usa el grupo de datos del propio evento
presence acepta visible, hidden e invisible en fields, draws, subforms y exclusion groups de la plantilla; el contenido hidden no ocupa espacio de flujo, mientras que el contenido invisible conserva su espacio y se omite de los widgets y de la salida de flatten
Con el parser literal por defecto, los cambios de presence aplican al nodo de plantilla seleccionado y por lo tanto a todas sus ocurrencias repetidas; la presence indexada por instancia, inactive, las expresiones arbitrarias, las variables, los condicionales, los loops y demás operaciones de event scripts exigen un event host adicional
Un lote de eventos publica los cambios de datos, cálculos, layout, focus y estado de edición juntos después de que el reflow se estabiliza; cualquier operación rechazada o presupuesto de input, operación, instancia, valor, widget, layout o tiempo transcurrido agotado restaura el estado anterior completo del documento y la interacción
Al eliminar una fila se preservan el focus y las ediciones pendientes de los grupos de datos que sobreviven incluso cuando sus índices de widget cambian; eliminar u ocultar el widget con focus limpia el focus y publica el callback de focus correspondiente después del éxito
Ejecución general de eventos JavaScript y FormCalc
Establezca TXFAWidgetRuntimeOptions.ScriptOptions.EnableJavaScript para habilitar el puente QuickJS acotado incluido para la ejecución de eventos; los eventos JavaScript pasan a soportar funciones, closures, arrays, condicionales, loops y excepciones en lugar de la gramática literal por defecto
Options := TXFAWidgetRuntimeOptions.Default;
Options.ScriptOptions.EnableJavaScript := True;
Runtime := TXFAWidgetRuntime.Create(XDPBytes, 595, 842, Options);
El event host expone this, los fields y subforms nombrados que envuelven, parent, rawValue, presence y access escribibles, instanceManager.count/min/max, addInstance, removeInstance, insertInstance, moveInstance y setInstances, xfa.resolveNode, xfa.resolveNodes, resolución a nivel de nodos y xfa.layout.relayout
Las listas de nodos soportan indexación numérica, length e item; los valores de campos repetidos retienen sus propios targets de dataset, y los paths SOM aceptan hijos nombrados con índices numéricos o wildcard para nodos vivos del host
const values = xfa.resolveNodes("main.row[*].amount[*]");
let total = 0;
for (const field of values) total += Number(field.rawValue);
xfa.resolveNode("main.total").rawValue = total;
if (total > 100) this.parent.warning.presence = "visible";
Cada subform repetido tiene su propio objeto vivo y campos hijos; index, los getters de hijos del padre y las consultas SOM subsiguientes siguen las operaciones insert, move y remove de inmediato dentro del script
addInstance y insertInstance devuelven un subárbol vivo inicializado con los valores por defecto de la plantilla, así que el script puede escribir los valores de sus campos antes de que el evento publique; los handles eliminados rechazan lecturas o escrituras posteriores
Los cambios generales de presence y access de scripts persisten en el packet estándar XFA form por ocurrencia, mientras que los valores de campos y las operaciones de repetición persisten en datasets; insert, move y remove mantienen el estado de form correspondiente alineado con los grupos de datos
Con el mismo opt-in, los event scripts FormCalc compilan al engine acotado y soportan var, if/elseif/else, for con upto o downto, while, foreach, func con resultados implícitos, aritmética y comparaciones, concatenación de cadenas, agregación de nodos con wildcard y asignación implícita de valores de campos
La librería de funciones de eventos incluye Sum, Count, Avg, Min, Max, Round, funciones matemáticas comunes, slicing de cadenas, conversión de mayúsculas/minúsculas, trimming, replacement, HasValue, Exists, Within, Oneof y Choose; los nombres built-in son insensibles a mayúsculas, At(source, search) sigue el orden de argumentos XFA incluido el comportamiento de búsqueda vacía, las funciones financieras siguen el orden de parámetros XFA, y los catálogos de fechas y finanzas se describen en FormCalc Functions
Las mutaciones de scripts se registran dentro del engine, se validan y se repiten dentro de la transacción del runtime; las excepciones, la interrupción, el Unicode inválido, las operaciones de host inválidas y los presupuestos agotados no publican cambios parciales del documento
La ejecución general de scripts permanece desactivada por defecto, no usa ningún navegador ni proceso externo y no expone APIs de filesystem, red ni aplicación; el llamador puede suministrar JavaScriptEvaluator en lugar del puente
Objetos de scripts persistentes
Los objetos script JavaScript dentro del elemento variables de un subform exponen sus variables y funciones a través del nombre del script; las variables léxicas, el estado de objetos y las closures anidadas permanecen vivas durante la sesión del runtime, con el shadowing léxico normal y las directivas strict preservados
<variables>
<script name="Helpers" contentType="application/x-javascript"><![CDATA[
let count = 0;
const nextPrivate = (() => { let value = 0; return () => ++value; })();
function next() { return ++count + ":" + nextPrivate(); }
]]></script>
</variables>
El código de eventos puede llamar a Helpers.next(); las ocurrencias repetidas de subforms son dueñas de objetos de scripts independientes, y las funciones resuelven los fields nombrados contra el contexto vivo actual del formulario
Los nodos de campos capturados y los managers siguen la identidad estable de datos entre movimientos y la publicación de instancias recién creadas; acceder a un nodo eliminado rechaza el evento y revierte el estado de su módulo
Los scripts generales de calculate y validate comparten la sesión y los objetos de scripts; JavaScript soporta completion values implícitos y return explícito, mientras que FormCalc devuelve su expresión final
Las transacciones fallidas restauran el estado léxico y de closures repitiendo el journal virtual confirmado, con entradas grabadas de tiempo y aleatoriedad; replay y ejecución actual comparten el deadline de la transacción, y los límites por defecto del journal son 64 MiB de scripts/resultados y 8192 entradas
El estado de objetos de scripts vive en la sesión del runtime y se inicializa de nuevo tras el reload de XDP; los valores estándar del documento y los overrides de form siguen persistiendo a través de SaveToBytes
Los callbacks personalizados JavaScriptEvaluator retienen el envelope existente de calculate/validate nativo; la sesión persistente la suministra el engine incluido
Configuración del transporte explícito de host
Establezca HostTransport y el OnHostTransactionCompleted opcional en TXFAWidgetRuntimeOptions para ejecutar diálogos de host, impresión, navegación, submission y transferencia de datos a través de callbacks de la aplicación
Explicit XFA Host Transport suministra xfa.host.messageBox, response, beep, print, gotoURL, submitForm, importData, exportData y FormCalc Get, Post y Put; la aplicación devuelve resultados tipados y controla los efectos externos
Los reintentos y el replay de sesión usan respuestas grabadas, así que los callbacks se ejecutan una vez por request despachado; la finalización por falla permite a la aplicación descartar efectos en escena o compensar operaciones reversibles
Los HostTransportLimits positivos acotan el conteo de requests, el conteo de argumentos y los bytes agregados de request/response dentro de la transacción del runtime que envuelve
Ejecución de locales y pictures
Los eventos generales de FormCalc y los scripts de calculate y validate soportan las funciones de locale y pictures, incluyendo Format, Parse, conversiones de fecha/hora localizadas, unidades, encoding, UUIDs y palabras numéricas en inglés
Dynamic FormCalc Eval ejecuta cálculos suministrados dinámicamente con variables y funciones aisladas, acceso relativo a campos, compilación nativa, respuestas grabadas y rollback transaccional
Las referencias FormCalc explícitas soportan asignación write-through, rebind, desacoplamiento de null, argumentos de funciones y handles estables retenidos por objetos de scripts entre movimientos de instancias repetidas
Los paths SOM vivos soportan índices de ocurrencia inferidos, absolutos y relativos, selectores de clase y descendientes, contenedores transparentes, predicados de candidatos y asignación indexada directa de FormCalc
El Data DOM nativo expone los datasets a través de $data y $record, sincroniza de inmediato las lecturas y escrituras de formularios con binding, refleja las instancias repetidas y preserva las referencias de datos retenidas mediante la publicación de identidades nativas
El Property DOM nativo expone los hijos de propiedades declarados de value, fuentes, UI y demás, sincroniza los valores tipados de campos y persiste los atributos por instancia usados por la medición de fuentes y el styling de flatten soportado
El nodo en ejecución hereda su atributo de locale más cercano; las entradas localeSet del documento anulan los símbolos y patrones del sistema, mientras que los nombres de locale computados se resuelven mediante solicitudes internas acotadas y se preservan en el journal de la sesión
Num2Date sin picture ahora usa el patrón de fecha por defecto del ambiente; suministre YYYY-MM-DD explícitamente cuando se requiera salida ISO
Modelo de host con estado
XFA Host Model suministra metadatos de la aplicación, conteo real de páginas, navegación de páginas, título Unicode, flags de cálculo/validación, reset con scope y focus de campos con ciclo de vida transaccional enter/exit
TXFAWidgetRuntimeOptions.HostModel configura el estado inicial de la aplicación; TXFAWidgetRuntime.HostModel devuelve el estado actual, y los eventos fallidos lo restauran junto con los snapshots de documento e interacción
Un movimiento de focus sin script enter/exit, edición pendiente ni ciclo de vida inicializado cambia el focus sin arrancar cálculo de scripts ni procesamiento de deadline; el focus con scripts y los commits de ediciones pendientes siguen usando presupuestos transaccionales, validación y recálculo
Las cláusulas de pictures avanzadas se ejecutan a través de las mismas transacciones del runtime, el journal de reintentos de locale y el ciclo de vida de cálculo, con parseo compuesto acotado
Inicialización y mantenimiento del ciclo de vida
Llame a InitializeForm después de configurar el runtime y los callbacks para ejecutar los eventos initialize en orden de plantilla, luego calculate y validate, los eventos form-ready y los eventos layout-ready; la llamada es idempotente después del éxito
Las instancias nuevas creadas por la inicialización o por los eventos ready reciben sus propios eventos initialize antes de sus handlers ready; la ejecución de layout-ready se repite solo cuando el layout cambia, dentro de los presupuestos de reflow y transacción
Tras la inicialización, el dispatch de eventos exitoso y el commit de ediciones inicializan las instancias recién creadas y ejecutan calculate, validate y layout-ready; las ocurrencias existentes retienen su estado de inicialización entre movimientos y rollback de transacciones
Las fallas del ciclo de vida revierten juntos los bytes del documento, la interacción de widgets y la contabilidad de inicialización, y los callbacks publican solo después de que la transacción envolvente tenga éxito
Guardar el formulario actualizado
SaveToBytes devuelve el XDP actualizado completo del runtime, incluidos los datasets modificados y el estado estándar de form por instancia; los cambios de presence del parser literal permanecen como atributos de la plantilla; use estos bytes con SetXFADocument al escribir un PDF o con HPDFXFAFlatten para la salida de flatten actualizada
La fábrica del documento cargado crea un runtime independiente, así que los eventos del runtime no modifican automáticamente el grafo de objetos del PDF fuente
Perfil opcional de presentación de instancias
Dynamic XFA Instance Presentation agrega bindings repetidos explícitos, IDs estables por instancia, presence y access indexados, eventos condicionales acotados, pintado en canvas del host y accesibilidad a través de un helper independiente; el runtime por defecto y su gramática restringida de eventos permanecen compatibles
UpdateDocument proporciona acciones transaccionales sobre el documento; los callbacks opcionales del runtime de propiedad, scope de binding, identidad, resolución iniciada y validación de documento soportan al helper mientras los valores por defecto nil preservan a los llamadores existentes
APIs de eventos y formularios de nivel más bajo
HPDFXFACompileFormCalcEvent compila la sintaxis de eventos; HPDFXFAExecuteJavaScriptEvent ejecuta el contexto virtual descrito por TXFAEventBinding y TXFAEventBindings
TXFAJavaScriptSession suministra ejecución persistente y checkpoints acotados para llamadores de nivel más bajo
Los valores devueltos de TXFAEventAction usan TXFAEventActionKind; el replay transaccional lo suministra el runtime
HPDFXFAResolveFormInstanceNode y HPDFXFAResolveFormInstanceProperty proporcionan búsqueda acotada del packet estándar de formularios
Límites actuales
El runtime es un objeto de host de un solo hilo; la GUI y el pintado siguen siendo responsabilidad del host o del helper opcional de presentación
El estado de host soportado, el form DOM vivo y el ciclo de vida aún no cubren cada propiedad del host de Acrobat, las pictures de dígitos de otras eras y localizadas, las consultas síncronas de reflow dinámico ni cada operador SOM
Vea FormCalc y JavaScript acotados de XFA, XFA Packet DOM y Procesamiento interactivo de documentos