Looplex Knowledge Base
Codificação com Office Render
Codificação com Office Render
Introdução
O office-render
é um motor de template inspirado no Mustache, mas focado em arquivos Microsoft Office. Ele funciona expandindo {{tags}}
presentes no template com valores, expressões, funções e subtemplates fornecidos em formato json. Pode ser importado como módulo de serviço em runtime node.js ou função remota serverless utilizando API.
O diferencial desse motor é o uso de Angular Expressions + Angular Filters. Isso quer dizer que, além dos convencionais valores json
e lambdas
do Mustache, também pode-se utilizar expressões parecidas com Javascript ganhando maior flexibilidade, sem deixar de lado a segurança.
TL;DR;
O office-render
segue a arquitetura de requisição e respostas. Seu uso se dá através do envio de um payload
de configuração e recebe uma promessa de entrega de um documento tipo Microsoft Office no caso de sucesso ou erro se não for possível gerar o documento com as configurações enviadas.
// valores marcados entre '/* */' são opcionais// , ... significa que valores adicionais podem ser enviadosconst payload = { "template": "url || base64", "datasource": { "key": "value"/*, ...*/ }, /* "partials": { "name": "url || base64", ... }, */ /* "lambdas": { "name": ["param", ..., "functionBody"], ... }, */ /* "path": "looplex-ged:domain.com/shared/office-render/out/result.docx" */}
Para usar como serviço:
import { generate as createDocument } from "~/path/to/office-render.js";const /* base64 */ document = await createDocument(payload);
Para usar como API:
Definir header Content-Type: application/json; charset=utf-8
e enviar:
POST`${basepath}/api/${version}/office-render`;JSON.stringify(payload);// { "status": "SUCCESS|FAILURE", "message": "base64" }
Por exemplo, imagine o template docx
abaixo hospedado na url https://assets.domain.com/templates/office/congratulation.docx:
Olá {{username}},Parabéns, Você acabou de ganhar {{amount|numberFormat:'pt-BR':'{ "style": "currency", "currency": "BRL" }'}}!{{#in_br}}Bom, {{(amount * 0.3625)|numberFormat:'pt-BR':'{ "style": "currency", "currency": "BRL" }'}}, após pagar os impostos.{{/}}
Dado o seguinte config:
{ "template": "https://assets.domain.com/templates/office/congratulation.docx", "datasource": { "username": "João Ninguém", "amount": 1000.0, "in_br": true }}
Irá produzir:
Olá João Ninguém,Parabéns, Você acabou de ganhar R$ 1.000,00!Bom, R$ 362,50, após pagar os impostos.
MUSTACHE TAGS
Tags são indicadas através da marcação com chave dupla {{tag}}
ou chave tripla {{{tag}}}
. Vejamos seus diferentes tipos:
Undefined
O desacoplamento entre a view criada pelo designer e o model fornecido pela engenharia tem como conseqüencia um caso especial que é quando a view está esperando um valor, mas ele está ausente no model. Nesse caso, a tag não será interpolada e permanecerá no documento final.
Variáveis
O tipo mais simples de tag é a {{variable}}
. Ela vai procurar pelo valor guardado na chave variable
do contexto atual. Se não houver variable
no contexto atual, os contextos superiores serão avaliados recursivamente.
::: important
Variáveis marcadas com chave dupla {{html_escaped}}
passam, por padrão de segurança por HTML escape. Se o autor precisar do conteúdo raw, deve-se utilizar o mustache triplo: {{{unescaped_html}}}
:::
Seções e Seções Invertidas
Seções são úteis para alterar o contexto por uma parte. O comportamento é diferente dependendo do valor associado à chave. Uma seção começa com uma cerquilha #
e termina com uma barra /
. Isto é, {{section}}
começa uma seção e {{/section}}
termina uma seção (também pode ser apenas {{/}}
).
Enquanto as seções são úteis para alterar o contexto por uma parte, as seções invertidas são úteis para capturar a ausência de conteúdo. Uma seção invertida começa com um acento circunflexo ^
e termina com uma barra /
. Isto é, {{^inverted_section}}
começa uma seção invertida e {{/inverted_section}}
termina a seção invertida (também pode ser apenas {{/}}
).
Booleanos
Se a seção {{#boolean}}
for verdadeira, o conteúdo definido na seção será renderizado; se for falsa, o conteúdo será ignorado. Por exemplo:
Template
Parágrafo fixo.{{#boolean}}Parágrafo condicional caso verdadeiro.{{/}}{{^boolean}}Parágrafo condicional caso falso.{{/}}
Config
{ "datasource": { "boolean": false }}
Resultado
Parágrafo fixo.Parágrafo condicional caso falso.
Listas
Se a seção {{#array}}
existir e possuir conteúdo, a parte será reavaliada para cada valor da lista; se estiver vazia, o conteúdo será ignorado. Por exemplo:
Template
{{#array}}* {{.}}{{/}}{{^array}}A lista está vazia{{/}}
Config
{ "datasource": { "list": ["Alice", "Bob", "Charlie"] }}
Resultado
* Alice* Bob* Charlie
Objetos
Se a seção {{#object}}
existir, a parte será reavaliada com o contexto atualizado para object. Por exemplo:
Template:
{{#postalAddress}}{{streetAddress}}{{postOfficeBoxNumber}}{{addressLocality}}, {{addressRegion}} {{postalCode}}{{addressCountry}}{{/}}
Config:
{ "datasource": { "postalAddress": { "streetAddress": "1600 Amphitheatre Pkwy", "postOfficeBoxNumber": "1982", "addressLocality": "Mountain View", "addressRegion": "California", "addressCountry": "USA", "postalCode": "94043" } }}
Resultado:
1600 Amphitheatre PkwyTower Z, 1982Mountain View, California 94043USA
Lambdas
Quando o valor associado à chave é uma função, ela será executada com o atual contexto scope
como primeiro argumento e o gerenciador de contextos scopeManager
como segundo argumento. Por exemplo:
Template:
{{#users}}{{greeter}}{{/}}
Config:
{ "datasource": { "users": [ { "name": "Alice" }, { "name": "Bob" }, { "name": "Charlie" } ] }, "lambdas": { "greeter": "return `Olá ${scope.name}, como vai?`" }}
Resultado:
Olá Alice, como vai?Olá Bob, como vai?Olá Charlie, como vai?
Outro exemplo:
Template:
O recorrente {{fullname}}, {{identidade}} ...
Config:
{ "user": { "fullname": "Alice Bates", "isOrganization": false, "federalTaxNumber": "051-96-9495" }, "lambda": { "identidade": "if (scope.user.isOrganization) { return `SSN: ${scope.user.federalTaxNumber}` } else { return `DUNS: ${scope.user.federalTaxNumber}` }" }}
Resultado:
O recorrente Alice Bates, SSN 051-96-9495 ...
::: tip
Este foi um exemplo ilustrativo de if-else. No contexto anterior, o ideal seria utilizar um operador ternário. e.g. const {isOrganization, federalTaxNumber} = scope.user; return ${isOrganization ? 'DUNS' : 'SSN'} ${federalTaxNumber}
.
:::
ANGULARJS EXPRESSIONS
Em matemática, quando combinamos números e variáveis de uma forma válida, utilizando operadores como adição, subtração, multiplicação, divisão, exponenciação et cetera e funções, damos o nome de expressão matemática à agregação combinada desses símbolos.
Em linguagens de programação, uma expressão é uma unidade de código que pode ser reduzida à um valor. No Javascript, existem dois tipos de expressões: as que produzem efeitos colaterais (como atribuir valor) e aquelas que não (como resultado de um cálculo).
A expressão x = 7
é um exemplo do primeiro tipo. Essa expressão usa o operador =
para atribuir o valor sete para a variável x
. O resultado da expressão resulta em 7
.
A expressão 3 + 4
é um exemplo do segundo tipo. Essa expressão usa o operador +
para adicionar 3
e 4
produzindo o valor 7
conhecido como soma.
Como dito inicialmente, o grande diferencial desse motor é o uso das AngularJS Expressions. Extraídas do código fonte do projeto angular.js, elas permitem a criação simplificada de templates complexos. São exemplos de AngularJS Expressions:
Operadores de atribuição
Um operador de atribuição associa o valor ou resultado do operando direito ao operando esquerdo. O mais simples dos operadores de atribuição é o igual (=
) e um exemplo clássico do uso desse operador é y = f(x)
.
Operador | Descrição | Exemplo |
---|---|---|
Assignment = | Atribui o valor do operando à direita ao operando da esquerda | x = 1 |
Operadores de comparação
Um operador de comparação avalia seus operandos e retorna um valor lógico baseado no fato da comparação se mostrar verdadeira ou não. Os operandos podem ser numéricos, textuais, booleanos ou propriedades de objetos. Valores textuais são comparados utilizando a ordem lexicográfica padrão usando valores unicode.
Operador | Descrição | Exemplo |
---|---|---|
Equal == | Retorna true se os operandos são iguais | 1 == '1' |
Not Equal != | Retorna true se os operandos não são iguais | 1 != 2 |
Strict Equal === | Retorna true se os operandos são iguais e possuem o mesmo tipo | 1 === 1 |
Strict not equal !== | Retorna true se os operandos não são iguais | 1 !== '1' |
Greater than > | Retorna true se o operando da esquerda é maior que o operando da direita | 2 > 1 |
Greater than or equal >= | Retorna true se o operando da esquerda é maior ou igual ao operador da direita | 1 >= 1 |
Less than < | Retorna true se o operando da esquerda é menor que o operando da direita | 1 < 2 |
Less than or equal | Retorna true se o operando da esquerda é menor ou igual ao operando da direita | 1 <= 1 |
Operadores aritméticos
Operadores aritméticos utilizam valores numéricos, tanto literais como variáveis, como seus operandos e entregam como resultado outro valor numérico. Os operadores aritméticos padrão são adição +
, subtração -
, multiplicação *
e divisão /
. Esses operadores funcionam de forma análoga ao esperado em outras linguagens de programação quando consideramos o operador $\circ$:
$$\circ : IEEE754^n \rightarrow IEEE754$$
::: important Uma particularidade da divisão nesse motor é que a divisão por zero produz Infinity devido à natureza aproximada da especificação de ponto flutuante. :::
Além dos já consagrados +
, -
, *
, /
segue abaixo a relação de outros operadores aritméticos disponíveis:
Operador | Descrição | Exemplo |
---|---|---|
Remainder % | Operador binário. Retorna o valor inteiro resto da divisão entre dois operandos | 12 % 5 resulta em 2 |
Unary negation - | Operador unário. Retorna o inverso aditivo do operando | Se x = 1 , o valor de -x é -1 |
Unary plus + | Operador unário. Retorna a versão numérica de um operando | +'1' retorna 1 |
Operadores lógicos
Geralmente, operadores lógicos são utilizados com valores booleanos, mas nesse motor funcionam com valores falsy e truthy. Operandos como &&
e ||
retornam o valor de um dos seus operandos, então se os valores forem não booleanos, as expressões retornam esse valor. Abaixo, segue a definição e tabela de quem são os valores falsy e truthy:
Operador | Descrição |
---|---|
false | Palavra reservada false |
0 | O número ZERO (também 0.0 , 0x0 , i.e. qualquer representação de ZERO) |
-0 | A negação do número ZERO |
"" , '' | Conteúdo textual vazio |
null | Palavra reservada null representa a ausência intencional de objeto |
undefined | Palavra reservada undefined representa que o tipo e valor da variável ainda são desconhecidos |
NaN | Palavra reservada NaN representa um resultado algébrico que não pode ser representado como número. Exemplos: 'render'**2 , 'nagao'/2 |
document.all | Objetos são considerados falsy se, e somente se, possuem um slot interno IsHTMLDDA definidos pelo motor de execução. |
Definidos falsy e truthy, podemos descrever os operadores lógicos a seguir:
Operador | Descrição | Exemplo |
---|---|---|
Logical AND && | Retorna expr1 , se for falsy e expr2 caso contrário. i.e. && resulta em true quando ambos operandos são truthy | expr1 && expr2 |
Logical OR ` | ` | |
Logical NOT ! | Operador unário, retorna false se o operando for truthy | !expr |
Operadores de texto
Além dos operadores de comparação, que também servem para texto, o operador de concatenação +
concatena dois operandos do tipo texto, retornando a união seqüencial da esquerda para direita dos operandos.
'ET, ' + 'telefone, ' + 'minha casa...'// imprime 'ET, telefone, minha casa...'
Operador condicional ternário
Existe apenas um operador padrão que recebe três operandos: o operador condicional ternário. Nele, o resultado varia entre dois valores dependendo da condição. Sua sintaxe é:
condição ? resultado_caso_verdadeira : resultado_caso_falsa
Por exemplo:
idade >= 18 ? 'adulto' : 'menor'
Essa expressão retorna 'adulto' se a variável idade
assumir valor maior ou igual a dezoito anos e 'menor' caso contrário.
Diferenças entre AngularJS Expressions e Javascript Expressions
- Contexto: AngularJS Expressions utilizam como contexto o objeto
scope
; - Indulgente: No Javascript, a avaliação de propriedades com
undefined
disparaReferenceError
ouTypeError
. No AngularJS Expressions, a avaliação é permissiva paraundefined
enull
; - Filters: É possível aplicar transformações adicionais ao valor da expressão antes da impressão;
- Ausência de controladores de fluxo: AngularJS Expressions não oferece suporte a declarações condicionais, loops ou disparo de erros;
- Impossibilidade de declarar funções: Em AngularJS Expressions, não é possível declarar novas funções;
- Impossibilidade de declarar expressões regulares: Em AngularJS Expressions, não é possível declarar expressões regulares;
- Impossibilidade de criação de novos objetos utilizando o operador
new
: AngularJS Expressions não interpreta o operador new; - Ausência da notação de atalho para operações de atribuição: Em AngularJS Expressions, não é possível utilizar
+=
,-=
,*=
,/=
,%=
,**=
,<<=
,>>=
,>>>=
,&=
,^=
,|=
,&&=
,||=
,??=
; - Ausência de operadores aritméticos increment, decrement e exponentiation: Não é possível utilizar operados
++
,--
e**
, - Ausência de operadores bitwise, comma e void: Não é possível utilizar operadores bitwise,
,
, ouvoid
; - Ausência de operadores relacionais: Não é possível utilizar operadores relacionais
in
einstanceof
.
::: tip Para regras complexas, deve-se utilizar expressões lambda que são chamadas pelo nome no template. :::
ANGULARJS FILTERS
Filtros permitem a transformação do resultado da expressão antes de aplicar a interpolação. Para chamar um filtro, deve-se utilizar a seguinte notação:
{{ expression | filter }}
É possível passar argumentos aos filtros. Por exemplo:
{{users|separator:', ':' e '}}
Imprime
Alice, Bob e Charlie
Filtros permitem chaining. Por exemplo:
{{expression | filter_0 | filter_1 | filter_2}}
Segue abaixo a relação de filtros disponíveis:
Identificador | Parâmetros | Exemplo |
---|---|---|
separator | middle, last | `{{users |
uppercase | `{{'Office Render' | |
lowercase | `{{'Office Render' | |
imageSize | width, height | `{{%image |
imageMaxSize | width, height | `{{%image |
IMAGENS
É possível inserir imagens dinamicamente utilizando as tags {{%image}}
para inserção text-level e {{%%image}}
para inserção block-level. São permitidos conteúdos tanto no formato binário base64 como também de url pública. Exemplos:
Template:
Config:
{ "picture": "/9j/4AAQSkZJRgABAQAAAQABAAD//gAgQ29tcHJlc3NlZCBieSBqcGVnLXJlY29tcHJlc3MA/", "fullname": "Angelica Astrom", "role": "Partner", "bio": "Sócia em direito societário, financeiro e de infraestrutura, Angelica é especialista em operações estruturadas e project finance. Altamente experiente em questões envolvendo os setores de transporte, logística e mineração.", "email": "angelica.astrom@example.com", "phone": "(11) 91234-5678", "linkedin": "/in/angelica.astrom", "city": "Nova Iorque, NY", "areas_of_practice": [ "Bancário, seguros e financeiro", "Financiamento de Projetos e infraestrutura", "Mercado de capitais", "Serviços financeiros", "Reestruturação e insolvência", "Contratos e negociações complexas" ], "associations": [ "Ordem dos Advogados do Brasil (OAB);", "International Bar Association (IBA);", "Instituto Brasileiro de Estudos de Direito da Energia (IBDE)." ], // continues ...}
Resultado:
Outra forma ainda é utilizar uma imagem como placeholder para outra imagem. Para isso, clicar com botão direito na imagem placeholder, selecionar Edit Alt Text ... e colocar {{%image}}
como conteúdo.
Botão Direito | Alt Text |
---|---|
{ width=290px } |
WORD
HTML e Markdown
Criadores de conteúdo web podem ficar felizes, pois o motor aceita aplicar valores Markdown e HTML. Em linhas gerais, elementos HTML permitidos no <body>
são de block-level ou text-level (também conhecido por inline). A distinção é fundamentada em diversos conceitos:
- Conteúdo: Geralmente, elementos block-level podem conter outros elementos block-level e também text-level; enquanto os text-level possuem apenas dados e outros elementos text-level. A idéia chave dessa separação estrutural é que elementos block-level criam estruturas maiores que elementos text-level.
- Formatação: Por padrão, a formatação de elementos block-level e text-level é diferente. Elementos block-level começam novas linhas e text-level não.
- Direcionalidade: Por razões técnicas envolvendo o funcionamento do algorítmo de texto bidirecional unicode, os elementos block-level e text-level diferem na forma como trabalham a direcionalidade do conteúdo.
Portanto, é importante utilizar a semântica correta para informar o office-render
na hora de enviar conteúdo HTML. Para indicar que a tag irá receber um valor text-level (imprimir dentro do parágrafo), deve-se utilizar a notação {{~inline}}
e para indicar que a tag irá receber um valor block-level (irá criar um novo parágrafo), deve-se utilizar a notação {{~~block}}
. Analogamente, pode-se utilizar Markdown utilizando {{~inline|markdown}}
para conteúdos text-level e {{~~block|markdown}}
para conteúdos block-level.
O que é Markdown?
Markdown é a ferramenta de conversão text-to-HTML
para escritores que venceu as adversárias no começo dos anos 2000 e se tornou padrão de mercado. Ela define a escrita de conteúdo semântico textual utilizando uma notação fácil-de-ler, fácil-de-escrever que é convertida mecanicamente em HTML. Por exemplo, esse manual foi todo escrito utilizando Markdown. No Wordpress e no GitHub, utiliza-se Markdown para escrever artigos. Para maiores informações sobre sua syntax, visite o playground.
Relação de tags text-level suportadas: <br />
, <span>
, <small>
, <ins>
, <del>
, <strong>
, <em>
, <a>
, <sub>
, <sup>
.
Relação de tags block-level suportadas: <p>
, <h1>
, <h2>
, <h3>
, <h4>
, <h5>
, <h6>
, <ul>
, <ol>
, <li>
, <pre>
, <code>
, <table>
, <thead>
, <tfoot>
, <tr>
, <th>
, <td>
, <img>
.
Relação de propriedade de estilo suportadas: font-family
, font-size
, color
, background-color
, text-decoration
, text-align
, vertical-align
, border
, break-before
, break-after
, width
, height
, padding-left
.
::: important Não é possível utilizar HTML e Markdown em arquivos PowerPoint e Excel. O fato do Word compartilhar da mesma natureza de fluxo linear, facilita a conversão. Já documentos PowerPoint possuem múltiplos slides, cada um armazenado em um arquivo diferente com cada elemento posicionado absolutamente em relação ao slide. :::
Notas de rodapé
Para inserir notas de rodapé em uma página, deve-se utilizar a tag {{:footnote id}}
, onde id
é a chave no datasource que contém a nota de rodapé.
Template:
Grace Brewster Murray Hopper (née Murray; December 9, 1906 – January 1, 1992) was an American computer scientist, mathematician, and United States Navy rear admiral.{{:footnote gracehopper}}
Config:
{ "datasource": { "gracehopper": "<w:r><w:rPr><w:b/></w:rPr><w:t xml:space='preserve'>Amazing Grace: Rear Adm. Grace Hopper, USN, was a pioneer in computer science.</w:t></w:r><w:r><w:rPr><w:i/></w:rPr><w:t xml:space='preserve'>Military Officer. Vol. 12, no. 3. Military Officers Association of America. pp. 52–55, 106. Retrieved March 1, 2014.</w:t></w:r>" }}
Resultado:
Amazing Grace: Rear Adm. Grace Hopper, USN, was a pioneer in computer science. Military Officer. Vol. 12, no. 3. Military Officers Association of America. pp. 52–55, 106. Retrieved March 1, 2014.
Subtemplates E Segments
A operação de transclusão no office-render
é realizada utilizando subtemplates. Ou seja, incluindo outros documentos Word. Para isso, o motor oferece dois tipos diferentes de tags: {{:include id}}
, {{:segment}}
e {{:includesegment}}
.
{ width=480px }
Subtemplates
A tag {{:include id}}
permite a inserção de um documento ou template "ancestral" no corpo do template em construção. Por exemplo:
Templates:
foo
Lorem ipsum{{:include B}}dolor sit amet
Config:
{ "datasource": {}, "partials": { "B": "base64|url" }}
Resultado:
Lorem ipsumfoodolor sit amet
Segments
A tag {{:includesegment id}}
permite a inserção de um trecho de conteúdo ou template dentro do próprio template. Por exemplo:
Template:
Endereço de Cobrança | Endereço de Entrega |
---|---|
{{#billingAddress}}{{:includesegment address}}{{/}} | {{#shippingAddress}}{{:includesegment address}}{{/}} |
Config:
{ "datasource": { "billingAddress": { "name": "HOME", "line1": "1600 Amphitheatre Pkwy", "postOfficeBox": "1982", "city": "Mountain View", "stateOrProvince": "California", "country": "USA", "postalCode": "94043" }, "shippingAddress": { "name": "WORK" "line1": "1600 Amphitheatre Pkwy", "postOfficeBox": "1982", "city": "Mountain View", "stateOrProvince": "California", "country": "USA", "postalCode": "94043" } }}
Resultado:
{ width=290px }
POWERPOINT
É possível criar arquivos PowerPoint através de duas estratégias diferentes: explícita, onde o engenheiro especifica quais slides serão utilizados e com quais conteúdos e implícita, onde o designer utiliza marcações para indicar se um slide deve aparecer condicionalmente, repetir durante o fluxo definido no template original.
Implícito
O uso implícito é inspirado em uma jornada ou story, é muito parecido com o fluxo de um documento Word. Só que no caso do PowerPoint, a estória é contada da esquerda para a direita.
Template:
{ width=290px } | { width=290px } |
---|---|
{ width=290px } | { width=290px } |
Config:
{ "intro": { "motto": "Estamos reinterpretando o trabalho dos advogados no século 21", "company": "Looplex" }, "differentiation": { "title": "Nosso diferencial", "description": "Respostas rápidas, Qualidade, Preço Baixo. Utilizamos tecnologia na construção do seu contrato impecável, da sua contestação que utiliza as melhores estratégias, explora as provas e que não deixa pedra sobre pedra.", "pain": "Chega de desperdiçar horas e horas, buscando teses que mais ou menos funcionam, com copia e cola, ajustes de texto e formatação!", "solution": "Legal Digital Experience (DX) Platform" }, "tooling": { "title": "Complicado virando Simples", "description": "Virando o jogo com o apoio da tecnologia e levando sua prática para um novo patamar diferenciando você dos concorrentes.", "first": { "title": "Engenharia Jurídica", "description": "Conversão do seu conhecimento para o formato digital." }, "second": { "title": "Interfaces Online", "description": "Para advogados, clientes e sistemas interajam." }, "third": { "title": "Smart Documents", "description": "Muito além do documento impresso, os documentos inteligentes realizam tarefas e conversam com outros sistemas." }, "fourth": { "title": "Dados Estruturados", "description": "Conteúdo que permite aplicar estatística, gerar reports e analisar estratégias." }, }, "verifiableCustomerWins": { "title": "Nossos Clientes", "description": "Junte-se ao incrível grupo de vanguarda que está revolucionando a prática do direito e economizando até 95% do tempo sem trabalhos repetitivos.", "brands": [...] }}
Resultado:
{ width=290px } | { width=290px } |
---|---|
{ width=290px } | { width=290px } |
Explícito
O uso explícito é inspirado em lego blocks. Cada slide pode ser considerado um bloco que fica disponível para o engenheiro seqüenciar e repetir ao seu sabor.
Template:
{ width=290px } | { width=290px } |
---|---|
{ width=290px } | { width=290px } |
Config:
{ "datasource": { "slides": [ { "$slide": 1, "subtitle": "action", "title": "office-render" }, { "$slide": 4, "motto": "Criação automática de documentos Microsoft Office focada em pessoas" } ] }}
Resultado:
Slide 1 | Slide 2 |
---|---|
{ width=290px } | { width=290px } |
TÓPICOS AVANÇADOS
Raw OOXML
O padrão que define os arquivos docx
, pptx
e xslx
se chama ECMA-376. Para quem conhece o dialeto, é possível injetar ooxml
s utilizando a notação {{@ooxml}}
. Com essa notação, o parágrafo inteiro (<w:p>
) é substituído pelo conteúdo da chave ooxml
. Por exemplo:
Template:
{{@ooxml}}
Config:
{ "datasource": { "ooxml": "<w:p><w:pPr><w:spacing w:before='120' w:after='120'/><w:ind w:left='720' w:right='720'/><w:rPr><w:sz w:val='18'/></w:rPr></w:pPr><w:r><w:rPr><w:sz w:val='18'/></w:rPr><w:t xml:space='preserve'>Humpty Dumpty sat on a wall. </w:t></w:r></w:p>" }}
Dash Syntax
Geralmente, quando usamos seções, o motor vai supor qual elemento do office que utilizará na iteração. Por exemplo, se entre as {{#tags}} ... {{/}}
:
- Existir uma célula de tabela (
<w:tc>
ou<a:tc>
), o motor irá iterar sobre a linha da tabela (<w:tr>
ou<a:tr>
), - Em outros casos, o motor não expandirá o loop e ficará restrito à parte definida na seção.
Com a notação Dash Syntax o autor pode definir o elemento ooxml
que ele deseja iterar. Por exemplo, se o desejo for criar um novo parágrafo para cada elemento de uma lista, pode-se fazer o seguinte:
{{-w:p paragraphs}}{{.}}{{/}}
Javascript
O motor office-render
, suas extensões e lambdas utilizadas em runtime utilizam a linguagem Javascript. O runtime de execução é continuamente atualizado de acordo com a disponibilidade de novas versões do NodeJS e V8 nos ambientes de hospedagem serverless. Isso faz com que novas funcionalidades que apareçam na camada de motor e linguagem fiquem também disponíveis na confecção dos templates.