Runtime Interativo de Widgets XFA Dinâmicos
TXFAWidgetRuntime fornece um modelo de interação neutro quanto ao host para formulários XFA dinâmicos, sem os converter em campos AcroForm nem achatuar o respetivo conteúdo
O runtime expõe bounds e estado determinísticos dos widgets, para que uma aplicação desktop, um serviço ou um renderer personalizado forneça o respetivo input, pintura, acessibilidade e ciclo de eventos
Criar um runtime
Crie o runtime diretamente a partir de bytes XDP ou chame THotPDF.CreateLoadedXFAWidgetRuntime depois de carregar um PDF cujo AcroForm contenha uma entrada /XFA de stream único ou 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;
A factory de documentos carregados é só de leitura quanto ao grafo de objetos PDF e aos XFAFlattenWarnings existentes; gravar o documento retém as entradas /XFA e /NeedsRendering originais
Modelo de interação
FocusWidgeteClearFocusmantêm um widget com foco, executam scripts enter/exit e publicam callbacks ordenados após o comprometimentoBeginEdit,ReplaceSelection,CancelEditeCommitEditpreservam texto Unicode, incluindo espaços à esquerda e à direitaHitTestmapeia coordenadas da página para o widget visível mais altoOnWidgetInvalidated,OnLayoutChangedeOnFocusChangedpermitem ao host atualizar apenas o estado afetado
Os commits interativos sincronizam valores escalares nativos existentes em aliases hidden e invisible, incluindo escopos reais de dados repetidos e rollback exato a nível de bytes
Validação e cálculo atómicos
Um commit resolve bindings SOM explícitos e o contexto atual de dados de linhas repetidas antes de executar scripts validate e calculate
O valor editado, os valores calculados, os nós de dados, o modelo do widget, o estado de foco e de edição, os avisos e os contadores de passagens publicam-se em conjunto só depois de a validação e o layout estabilizarem
Scripts rejeitados, orçamentos esgotados, limites de seleção UTF-16 inválidos, e exceções de layout ou de medição do host restauram o estado anterior completo e definem LastDiagnostic
Orçamentos
TXFAWidgetRuntimeOptions limita a contagem de widgets, o comprimento do valor editado, passagens de cálculo, passagens de reflow, operações de layout, operações de scripts, tempo decorrido de scripts e outros recursos FormCalc ou JavaScript
O teto de widgets aplica-se enquanto itens de layout e fragmentos de paginação são acrescentados, enquanto a descompressão XFA carregada e a montagem de packets param no limite de entrada do DOM XFA antes do parsing
MaxLayoutOperations assume 200000 por defeito e limita tanto a travessia do documento como o trabalho de layout; a profundidade de layout limita-se a 128, a profundidade de alvos de eventos e de inicialização de instâncias a 64, e o despacho recursivo de eventos é rejeitado
Eventos dinâmicos de literais por defeito
DispatchEvent aceita operações literais separadas por ponto e vírgula em scripts de eventos de campos correspondentes, com content types FormCalc ou JavaScript; estas operações analisam-se diretamente e não exigem uma DLL JavaScript
row.instanceManager.addInstance(true);
row.instanceManager.removeInstance(0);
target.presence = "hidden";
addInstance acrescenta uma instância e aceita true, false, 1 ou 0 como argumento de merge; um argumento omitido usa true, e a forma abreviada _row.addInstance(1) também é aceite
O modelo suportado vincula todos os data groups existentes com o mesmo nome, pelo que uma nova instância recebe um data group novo inicializado a partir dos limites por defeito do template, para qualquer argumento de merge; a criação de instâncias não clona os valores introduzidos da linha anterior
removeInstance usa um índice inteiro de base zero entre os data groups de mesmo nome do subform selecionado; o subform tem de ter um elemento occur com máximo repetível, e ambas as operações impõem o respetivo mínimo e máximo, incluindo max="-1"
A mutação de instâncias exige binding implícito de datasets com nome e nomes de dados XML ASCII; binding explícito por referência de dados e contextos de pais ambíguos são rejeitados antes de publicar a transação
Os alvos resolvem-se através de filhos de templates com nome nos escopos envolventes do evento, incluindo caminhos por pontos e this.parent; um manager aninhado num escopo repetido usa o data group do próprio evento
presence aceita visible, hidden e invisible em campos, draws, subforms e exclusion groups de templates; o conteúdo hidden não ocupa espaço de fluxo, enquanto o conteúdo invisible retém o respetivo espaço e omite-se dos widgets e do output de flattening
Com o parser de literais por defeito, as alterações de presence aplicam-se ao nó de template selecionado e portanto a todas as respetivas ocorrências repetidas; presence indexada por instância, inactive, expressões arbitrárias, variáveis, condicionais, ciclos e outras operações de scripts de eventos exigem um event host adicional
Um lote de eventos publica alterações de dados, cálculos, layout, foco e estado de edição em conjunto, depois de o reflow estabilizar; qualquer operação rejeitada ou orçamento de input, operações, instâncias, valores, widgets, layout ou tempo decorrido esgotado restaura o estado completo anterior do documento e da interação
Remover uma linha preserva o foco e as edições pendentes dos data groups sobreviventes, mesmo quando os respetivos índices de widgets mudam; remover ou ocultar o widget com foco limpa o foco e publica o callback de foco correspondente após o sucesso
Execução geral de eventos JavaScript e FormCalc
Defina TXFAWidgetRuntimeOptions.ScriptOptions.EnableJavaScript para ativar a bridge QuickJS limitada incluída para execução de eventos; os eventos JavaScript passam então a suportar funções, closures, arrays, condições, ciclos e exceções em vez da gramática de literais por defeito
Options := TXFAWidgetRuntimeOptions.Default;
Options.ScriptOptions.EnableJavaScript := True;
Runtime := TXFAWidgetRuntime.Create(XDPBytes, 595, 842, Options);
O event host expõe this, campos e subforms nomeados envolventes, parent, rawValue, presence e access graváveis, instanceManager.count/min/max, addInstance, removeInstance, insertInstance, moveInstance e setInstances, xfa.resolveNode, xfa.resolveNodes, resolução ao nível de nós e xfa.layout.relayout
As listas de nós suportam indexação numérica, length e item; os valores de campos repetidos retêm os respetivos alvos de dataset, e os caminhos SOM aceitam filhos com nome com índices numéricos ou wildcards para nós vivos do 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 tem o respetivo objeto vivo e campos filhos; index, os getters de filhos do pai e as consultas SOM subsequentes seguem imediatamente as operações de inserção, movimento e remoção dentro do script
addInstance e insertInstance devolvem uma subárvore viva inicializada a partir dos limites por defeito do template, pelo que o script pode escrever os valores dos respetivos campos antes de o evento publicar; handles removidos rejeitam leituras ou escritas subsequentes
As alterações de presence e access de scripts gerais persistem no packet form XFA standard por ocorrência, enquanto os valores dos campos e as operações de repetição persistem em datasets; inserir, mover e remover mantêm o estado de formulário correspondente alinhado com os data groups
Com o mesmo opt-in, os scripts de eventos FormCalc compilam para o motor limitado e suportam var, if/elseif/else, for com upto ou downto, while, foreach, func com resultados implícitos, aritmética e comparações, concatenação de cadeias, agregação de nós com wildcards e atribuição implícita de valores de campos
A biblioteca de funções de eventos inclui Sum, Count, Avg, Min, Max, Round, funções matemáticas comuns, corte de cadeias, conversão de maiúsculas e minúsculas, aparar, substituição, HasValue, Exists, Within, Oneof e Choose; os nomes built-in são insensíveis a maiúsculas e minúsculas, At(source, search) segue a ordem de argumentos XFA, incluindo o comportamento de pesquisa vazia, as funções financeiras seguem a ordem de parâmetros XFA, e os catálogos de datas e finanças descrevem-se em FormCalc Functions
As mutações de scripts registam-se dentro do motor, validam-se e reproduzem-se dentro da transação do runtime; exceções, interrupção, Unicode inválido, operações inválidas do host e orçamentos esgotados não publicam alterações parciais do documento
A execução geral de scripts continua desativada por defeito, não usa browser nem processo externo, e não expõe APIs de filesystem, rede ou aplicação; quem chama pode fornecer JavaScriptEvaluator em vez da bridge
Script objects persistentes
Objetos script JavaScript dentro do elemento variables de um subform expõem as respetivas variáveis e funções através do nome do script; variáveis lexicais, estado de objetos e closures aninhadas continuam vivas durante a sessão do runtime, com shadowing lexical normal e diretivas 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>
O código de eventos pode chamar Helpers.next(); as ocorrências repetidas de subforms têm script objects independentes, e as funções resolvem campos com nome contra o contexto vivo atual do formulário
Os nós de campos e managers capturados seguem a identidade estável de dados entre movimentos e a publicação de instâncias recém-criadas; aceder a um nó removido rejeita o evento e reverte o estado do respetivo módulo
Os scripts gerais calculate e validate partilham a sessão e os script objects; o JavaScript suporta valores de conclusão implícitos e return explícito, enquanto o FormCalc devolve a respetiva expressão final
Transações falhadas restauram o estado lexical e de closures reproduzindo o journal virtual comprometido, com tempo e inputs aleatórios registados; o replay e a execução atual partilham o prazo da transação, e os limites por defeito do journal são 64 MiB de scripts/resultados e 8192 entradas
O estado dos script objects vive na sessão do runtime e inicializa-se de novo após o recarregamento do XDP; os valores standard do documento e os overrides de formulários continuam a persistir através de SaveToBytes
Callbacks personalizados de JavaScriptEvaluator retêm o envelope nativo existente de calculate/validate; a sessão persistente é fornecida pelo motor incluído
Configurar transport explícito do host
Defina HostTransport e o OnHostTransactionCompleted opcional em TXFAWidgetRuntimeOptions para executar diálogos, impressão, navegação, submissão e transferência de dados do host através de callbacks da aplicação
Explicit XFA Host Transport fornece xfa.host.messageBox, response, beep, print, gotoURL, submitForm, importData, exportData e FormCalc Get, Post e Put; a aplicação devolve resultados tipados e controla os efeitos externos
Retries e replay de sessão usam respostas registadas, pelo que os callbacks executam uma vez por pedido despachado; a conclusão de falha permite à aplicação descartar efeitos preparados ou compensar operações reversíveis
HostTransportLimits positivos limitam a contagem de pedidos, a contagem de argumentos e os bytes agregados de pedidos/respostas em toda a transação envolvente do runtime
Execução de locales e pictures
Eventos FormCalc gerais e scripts calculate e validate suportam funções de locale e pictures, incluindo Format, Parse, conversões localizadas de data/hora, unidades, encoding, UUIDs e números por extenso em inglês
Dynamic FormCalc Eval executa cálculos fornecidos dinamicamente com variáveis e funções isoladas, acesso relativo a campos, compilação nativa, respostas registadas e rollback transacional
Referências FormCalc explícitas suportam atribuição write-through, rebinding, desanexação null, argumentos de funções e handles estáveis retidos por script objects entre movimentos de instâncias repetidas
Caminhos SOM vivos suportam índices de ocorrências inferidos, absolutos e relativos, seletores de classes e descendentes, contentores transparentes, predicados de candidatos e atribuição indexada direta em FormCalc
O Data DOM nativo expõe datasets através de $data e $record, sincroniza imediatamente leituras e escritas vinculadas de formulários, espelha instâncias repetidas e preserva referências de dados retidas através da publicação nativa de identidades
O Property DOM nativo expõe filhos de propriedades declaradas de valores, tipos de letra, UI e outros, sincroniza valores tipados de campos e persiste atributos por instância usados pela medição de tipos de letra e pelo styling de flattening suportado
O nó em execução herda o respetivo atributo de locale mais próximo; as entradas de localeSet do documento sobrepõem-se a símbolos e padrões do sistema, enquanto os nomes de locale calculados resolvem-se através de pedidos internos limitados e preservam-se no journal da sessão
Num2Date sem picture usa agora o padrão de datas por defeito ambiente; forneça YYYY-MM-DD explicitamente quando for exigida saída ISO
Modelo de host com estado
XFA Host Model fornece metadados da aplicação, contagem real de páginas, navegação de páginas, título Unicode, flags de cálculo/validação, reset com escopo e foco de campos com ciclo de vida transacional enter/exit
TXFAWidgetRuntimeOptions.HostModel configura o estado inicial da aplicação; TXFAWidgetRuntime.HostModel devolve o estado atual, e eventos falhados restauram-no em conjunto com os snapshots de documento e de interação
Um movimento de foco sem script enter/exit, edição pendente ou ciclo de vida inicializado muda o foco sem iniciar cálculo de scripts nem processamento de prazos; o foco com scripts e os commits de edições pendentes continuam a usar orçamentos transacionais, validação e recálculo
Picture clauses avançadas executam-se através das mesmas transações do runtime, do journal de retries de locale e do ciclo de vida de cálculo, com parsing composto limitado
Inicializar e manter o ciclo de vida
Chame InitializeForm depois de configurar o runtime e os callbacks para executar eventos initialize pela ordem do template, depois calculate e validate, eventos form-ready e eventos layout-ready; a chamada é idempotente após o sucesso
Instâncias novas criadas pela inicialização ou por eventos ready recebem os respetivos eventos initialize antes dos handlers ready; a execução de layout-ready repete-se só quando o layout muda, dentro dos orçamentos de reflow e de transações
Após a inicialização, o despacho bem-sucedido de eventos e o commit de edições inicializam instâncias recém-criadas e executam calculate, validate e layout-ready; as ocorrências existentes retêm o respetivo estado de inicialização entre movimentos e rollback transacional
Falhas do ciclo de vida revertem bytes do documento, interação de widgets e registo de inicialização em conjunto, e os callbacks só publicam depois de a transação envolvente ter sucesso
Guardar o formulário atualizado
SaveToBytes devolve o XDP atualizado completo do runtime, incluindo datasets modificados e o estado de formulário standard por instância; as alterações de presence do parser de literais continuam a ser atributos de templates; use estes bytes com SetXFADocument ao gravar um PDF, ou com HPDFXFAFlatten para o output de flattening atualizado
A factory de documentos carregados cria um runtime independente, pelo que os eventos do runtime não alteram automaticamente o grafo de objetos do PDF de origem
Perfil opcional de apresentação de instâncias
Dynamic XFA Instance Presentation acrescenta bindings repetidos explícitos, IDs estáveis por instância, presence e acesso indexados, eventos condicionais limitados, pintura em canvas do host e acessibilidade através de um helper independente; o runtime por defeito e a respetiva gramática restrita de eventos continuam compatíveis
UpdateDocument fornece ações transacionais de documentos; callbacks opcionais de propriedades do runtime, escopo de binding, identidade, início de resolução e validação de documentos suportam o helper, enquanto os valores por defeito nil preservam quem já chama
APIs de eventos e formulários de nível inferior
HPDFXFACompileFormCalcEvent compila a sintaxe de eventos; HPDFXFAExecuteJavaScriptEvent executa o contexto virtual descrito por TXFAEventBinding e TXFAEventBindings
TXFAJavaScriptSession fornece execução persistente e checkpoints limitados para quem chama a nível inferior
Os valores TXFAEventAction devolvidos usam TXFAEventActionKind; o replay transacional é fornecido pelo runtime
HPDFXFAResolveFormInstanceNode e HPDFXFAResolveFormInstanceProperty fornecem pesquisa limitada de form-packets standard
Limites atuais
O runtime é um objeto de host single-thread; a GUI e a pintura continuam a ser responsabilidade do host ou do helper opcional de apresentação
O estado de host suportado, o DOM vivo de formulários e o ciclo de vida ainda não cobrem todas as propriedades de host do Acrobat, pictures de dígitos de eras alternativas e localizadas, consultas síncronas de reflow dinâmico, nem todos os operadores SOM
Ver Bounded XFA FormCalc and JavaScript, XFA Packet DOM e Interactive Document Processing