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

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