Runtime de widgets XFA dinámicos interactivos
TXFAWidgetRuntime aporta 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 deterministas de los widgets para que un renderizador de escritorio, un servicio o uno propio pueda aportar su propia entrada, pintado, accesibilidad y event loop
Creación de un runtime
Cree el runtime directamente desde bytes XDP o llame a THotPDF.CreateLoadedXFAWidgetRuntime tras cargar un PDF cuyo AcroForm contenga una entrada /XFA de stream único o de array 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 de documentos cargados es de solo lectura respecto al grafo de objetos PDF y a los XFAFlattenWarnings existentes; al guardar, el documento conserva sus entradas /XFA y /NeedsRendering originales
Modelo de interacción
FocusWidgetyClearFocusmantienen un único widget enfocado, ejecutan scripts de enter/exit y publican callbacks ordenados tras el commitBeginEdit,ReplaceSelection,CancelEdityCommitEditpreservan el texto Unicode, incluidos los espacios iniciales y finalesHitTestmapea coordenadas de página al widget visible superiorOnWidgetInvalidated,OnLayoutChangedyOnFocusChangedpermiten al host refrescar solo el estado afectado
Los commits interactivos sincronizan los valores escalares nativos existentes en los alias hidden e invisible, incluidos los ámbitos de datos repetidos reales y un rollback byte a byte
Validación y cálculo atómicos
Un commit resuelve los bindings SOM explícitos y el contexto de datos de fila repetida actual antes de ejecutar los scripts validate y calculate
El valor editado, los valores calculados, los nodos de datos, el modelo de widgets, el estado de foco y edición, los avisos y los contadores de pasadas se publican juntos solo después de que la validación y el layout se estabilicen
Los scripts rechazados, los presupuestos agotados, los boundaries de selección UTF-16 no válidos y las excepciones de layout o de medición del host restauran el estado previo completo y establecen LastDiagnostic
Presupuestos
TXFAWidgetRuntimeOptions limita el número 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 límite de widgets se aplica mientras se añaden items de layout 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 entrada del XFA DOM antes del parsing
MaxLayoutOperations vale 200000 por defecto y acota tanto el recorrido del documento como el trabajo de layout; la profundidad de layout se limita a 128, la profundidad de destino de eventos y de inicialización de instancias a 64, y el despacho recursivo de eventos se rechaza
Eventos dinámicos literales por defecto
DispatchEvent acepta operaciones literales separadas por punto y coma en scripts de eventos de campo coincidentes con tipos de contenido FormCalc o JavaScript; estas operaciones se analizan directamente y no requieren una DLL de JavaScript
row.instanceManager.addInstance(true);
row.instanceManager.removeInstance(0);
target.presence = "hidden";
addInstance añade 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 vincula todos los grupos de datos homónimos existentes, de modo 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 introducidos de la fila anterior
removeInstance usa un índice entero basado en cero entre los grupos de datos homónimos del subform seleccionado; el subform debe tener un elemento occur con un máximo repetible, y ambas operaciones hacen cumplir su mínimo y su máximo, incluido max="-1"
La mutación de instancias exige binding implícito de dataset con nombre 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 destinos se resuelven a través de hijos con nombre de la plantilla en los ámbitos que envuelven al evento, incluidas las rutas con puntos y this.parent; un manager anidado dentro de un ámbito repetido usa el grupo de datos propio del evento
presence acepta visible, hidden e invisible en campos, 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 del flatten
Con el parser literal por defecto, los cambios de presence se aplican al nodo de plantilla seleccionado y por tanto a todas sus ocurrencias repetidas; la presence indexada por instancia, inactive, las expresiones arbitrarias, las variables, las condicionales, los bucles y otras operaciones de scripts de evento exigen un host de eventos adicional
Un lote de eventos publica cambios de datos, cálculos, layout, foco y estado de edición juntos después de que el reflow se estabilice; cualquier operación rechazada o presupuesto de entrada, operación, instancia, valor, widget, layout o tiempo transcurrido agotado restaura el estado previo completo del documento y de la interacción
Eliminar una fila preserva el foco y las ediciones pendientes de los grupos de datos supervivientes incluso cuando cambian sus índices de widget; eliminar u ocultar el widget enfocado limpia el foco y publica el callback de foco correspondiente después del éxito
Ejecución general de eventos JavaScript y FormCalc
Establezca TXFAWidgetRuntimeOptions.ScriptOptions.EnableJavaScript para habilitar el puente QuickJS acotado incluido en la ejecución de eventos; los eventos JavaScript soportan entonces funciones, closures, arrays, condicionales, bucles 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 host de eventos expone this, los campos y subforms con nombre que envuelven, parent, rawValue escribible, presence y access, instanceManager.count/min/max, addInstance, removeInstance, insertInstance, moveInstance y setInstances, xfa.resolveNode, xfa.resolveNodes, resolución a nivel de nodo y xfa.layout.relayout
Las listas de nodos soportan indexado numérico, length e item; los valores de campos repetidos retienen sus propios destinos de dataset, y los paths SOM aceptan hijos con nombre 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 posteriores siguen insert, move y remove inmediatamente dentro del script
addInstance e insertInstance devuelven un subárbol vivo inicializado con los defaults de la plantilla, de modo que el script puede escribir los valores de sus campos antes de que el evento publique; los manejadores eliminados rechazan lecturas o escrituras posteriores
Los cambios generales de presence y access de scripts persisten en el packet form estándar de XFA 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 formulario correspondiente alineado con los grupos de datos
Con el mismo opt-in, los scripts de eventos FormCalc se 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 wildcard y asignación implícita de valores de campo
La librería de funciones de eventos incluye Sum, Count, Avg, Min, Max, Round, funciones matemáticas comunes, troceado de cadenas, conversión de mayúsculas y minúsculas, recorte, reemplazo, HasValue, Exists, Within, Oneof y Choose; los nombres integrados no distinguen mayúsculas, At(source, search) sigue el orden de argumentos de XFA incluido el comportamiento de búsqueda vacía, las funciones financieras siguen el orden de parámetros de XFA, y los catálogos de fechas y finanzas se describen en FormCalc Functions
Las mutaciones de scripts se graban dentro del engine, se validan y se reproducen dentro de la transacción del runtime; las excepciones, la interrupción, el Unicode no válido, las operaciones de host no válidas y los presupuestos agotados no publican cambios parciales del documento
La ejecución general de scripts sigue desactivada por defecto, no usa navegador ni proceso externo y no expone APIs de sistema de archivos, red ni aplicación; el llamador puede suministrar JavaScriptEvaluator en lugar del puente
Objetos de script persistentes
Los objetos script de 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 siguen vivos durante la sesión del runtime, con el sombreado léxico normal y las directivas estrictas 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 poseen objetos de script independientes, y las funciones resuelven los campos con nombre contra el contexto vivo actual del formulario
Los nodos de campos y managers capturados siguen identidades de datos estables a través de movimientos y de la publicación de instancias recién creadas; acceder a un nodo eliminado rechaza el evento y hace rollback de su estado de módulo
Los scripts generales de calculate y validate comparten la sesión y los objetos de script; JavaScript soporta valores de finalización 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 reproduciendo el journal virtual comprometido, con tiempos e entradas aleatorias grabados; el replay y la 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 los objetos de script vive en la sesión del runtime y se inicializa de nuevo tras recargar el XDP; los valores estándar del documento y las anulaciones de formulario siguen persistiendo a través de SaveToBytes
Los callbacks personalizados de JavaScriptEvaluator retienen el envolvente nativo existente de calculate/validate; la sesión persistente la suministra el engine incluido
Configurar el transporte de host explícito
Establezca HostTransport y el OnHostTransactionCompleted opcional en TXFAWidgetRuntimeOptions para ejecutar diálogos del host, impresión, navegación, submission y transferencia de datos mediante callbacks de la aplicación
El transporte de host XFA explícito 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 petición despachada; la finalización con fallo permite a la aplicación descartar efectos preparados o compensar operaciones reversibles
Los HostTransportLimits positivos acotan el recuento de peticiones, el de argumentos y los bytes agregados de petición/respuesta a través de la transacción del runtime que los envuelve
Ejecución de locale y pictures
Los eventos generales de FormCalc y los scripts calculate y validate soportan funciones de locale y pictures, incluidos Format, Parse, conversiones localizadas de fecha/hora, unidades, codificación, UUIDs y palabras numéricas en inglés
FormCalc Eval dinámico ejecuta cálculos suministrados dinámicamente con variables y funciones aisladas, acceso relativo a campos, compilación nativa, respuestas grabadas y rollback transaccional
Referencias FormCalc explícitas soportan asignación write-through, rebinding, desvinculación nula, argumentos de funciones y manejadores estables retenidos por objetos de script a través de movimientos de instancias repetidas
Paths SOM vivos soportan índices de ocurrencia inferidos, absolutos y relativos, selectores de clase y descendientes, contenedores transparentes, predicados candidatos y asignación indexada directa de FormCalc
El Data DOM nativo expone los datasets mediante $data y $record, sincroniza inmediatamente las lecturas y escrituras enlazadas del formulario, espeja instancias repetidas y preserva referencias de datos retenidas mediante publicación de identidad nativa
El Property DOM nativo expone hijos declarados de propiedades de valor, fuente, UI y otras, sincroniza valores de campos tipados y persiste 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 calculados se resuelven mediante peticiones internas acotadas y se preservan en el journal de la sesión
Num2Date sin picture usa ahora el patrón de fecha por defecto del entorno; suministre YYYY-MM-DD explícitamente cuando se requiera salida ISO
Modelo de host con estado
El modelo de host XFA suministra metadatos de la aplicación, recuento real de páginas, navegación de páginas, título Unicode, flags de cálculo/validación, reset con ámbito y foco de campo con un ciclo de vida transaccional de 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 las instantáneas del documento y de la interacción
Un movimiento de foco sin script de enter/exit, edición pendiente ni ciclo de vida inicializado cambia el foco sin arrancar cálculo de scripts ni procesado de deadlines; el foco con scripts y los commits con edición pendiente siguen usando presupuestos transaccionales, validación y recálculo
Las cláusulas picture 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
Inicializar y mantener el ciclo de vida
Llame a InitializeForm tras configurar el runtime y los callbacks para ejecutar los eventos initialize en el orden de la plantilla, luego calculate y validate, los eventos form-ready y los eventos layout-ready; la llamada es idempotente tras el é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 cambia el layout, dentro de los presupuestos de reflow y transacción
Tras la inicialización, el despacho exitoso de eventos 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 a través de movimientos y rollback transaccional
Los fallos del ciclo de vida hacen rollback juntos de 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 que los envuelve tenga éxito
Guardar el formulario actualizado
SaveToBytes devuelve el XDP completo actualizado del runtime, incluidos los datasets modificados y el estado de formulario estándar por instancia; los cambios de presence del parser literal permanecen como atributos de plantilla; use estos bytes con SetXFADocument al escribir un PDF o con HPDFXFAFlatten para la salida de flatten actualizada
La fábrica de documentos cargados crea un runtime independiente, de modo que los eventos del runtime no modifican automáticamente el grafo de objetos del PDF de origen
Perfil opcional de presentación de instancias
Presentación de instancias XFA dinámicas añade bindings repetidos explícitos, IDs estables por instancia, presence y acceso indexados, eventos condicionales acotados, pintado en canvas del host y accesibilidad mediante un helper independiente; el runtime por defecto y su gramática de eventos restringida siguen siendo compatibles
UpdateDocument proporciona acciones de documento transaccionales; los callbacks opcionales del runtime de propiedad, ámbito de binding, identidad, resolución iniciada y validación de documentos soportan al helper, mientras que los defaults nil preservan a los llamadores existentes
APIs de eventos y formularios de nivel inferior
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 inferior
Los valores TXFAEventAction devueltos usan TXFAEventActionKind; el replay transaccional lo suministra el runtime
HPDFXFAResolveFormInstanceNode y HPDFXFAResolveFormInstanceProperty proporcionan búsqueda acotada estándar del form packet
Límites actuales
El runtime es un objeto de host de hilo único; 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 todas las propiedades del host de Acrobat, las pictures de dígitos de otra era y localizadas, las consultas síncronas de reflow dinámico ni todos los operadores SOM
Consulte FormCalc y JavaScript de XFA acotados, XFA Packet DOM y Procesamiento de documentos interactivos