Skip to content

Codificação com Office Render

This content is not available in your language yet.

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 enviados
const 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>:
```js
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 Pkwy
Tower Z, 1982
Mountain View, California 94043
USA

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).

OperadorDescriçãoExemplo
Assignment =Atribui o valor do operando à direita ao operando da esquerdax = 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.

OperadorDescriçãoExemplo
Equal ==Retorna true se os operandos são iguais1 == '1'
Not Equal !=Retorna true se os operandos não são iguais1 != 2
Strict Equal ===Retorna true se os operandos são iguais e possuem o mesmo tipo1 === 1
Strict not equal !==Retorna true se os operandos não são iguais1 !== '1'
Greater than >Retorna true se o operando da esquerda é maior que o operando da direita2 > 1
Greater than or equal >=Retorna true se o operando da esquerda é maior ou igual ao operador da direita1 >= 1
Less than <Retorna true se o operando da esquerda é menor que o operando da direita1 < 2
Less than or equalRetorna true se o operando da esquerda é menor ou igual ao operando da direita1 <= 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:

OperadorDescriçãoExemplo
Remainder %Operador binário. Retorna o valor inteiro resto da divisão entre dois operandos12 % 5 resulta em 2
Unary negation -Operador unário. Retorna o inverso aditivo do operandoSe 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:

Falsy: um valor que é considerado false quando aplicado no contexto booleano

Truthy: valores complementares aos Falsy

OperadorDescrição
falsePalavra reservada false
0O número ZERO (também 0.0, 0x0, i.e. qualquer representação de ZERO)
-0A negação do número ZERO
"", ''Conteúdo textual vazio
nullPalavra reservada null representa a ausência intencional de objeto
undefinedPalavra reservada undefined representa que o tipo e valor da variável ainda são desconhecidos
NaNPalavra reservada NaN representa um resultado algébrico que não pode ser representado como número. Exemplos: 'render'**2, 'nagao'/2
document.allObjetos 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:

OperadorDescriçãoExemplo
Logical AND &&Retorna expr1, se for falsy e expr2 caso contrário. i.e. && resulta em true quando ambos operandos são truthyexpr1 && 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 dispara ReferenceError ou TypeError. No AngularJS Expressions, a avaliação é permissiva para undefined e null;
  • 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, ,, ou void;
  • Ausência de operadores relacionais: Não é possível utilizar operadores relacionais in e instanceof.

::: 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:**
![Template Curriculum Vitae](./office-render/inline-image.png)
**Config:**
```json
{
"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 ...
}

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 DireitoAlt Text
Right Click Menu width=290px[Edit Alt Text Screen]

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, 1906January 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}}.

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 ipsum
foo
dolor 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:**
```json
{
"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:**
![Segments Result](./office-render/segments-result.png){ 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:**
| ![Slide 1](./office-render/implicit-slide-1.png){ width=290px } | ![Slide 2](./office-render/implicit-slide-2.png){ width=290px } |
| - | - |
| ![Slide 3](./office-render/implicit-slide-3.png){ width=290px } | ![Slide 4](./office-render/implicit-slide-4.png){ width=290px } |
**Config:**
```json
{
"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:**
| ![Slide 1](./office-render/implicit-slide-1-result.png){ width=290px } | ![Slide 2](./office-render/implicit-slide-2-result.png){ width=290px } |
| - | - |
| ![Slide 3](./office-render/implicit-slide-3-result.png){ width=290px } | ![Slide 4](./office-render/implicit-slide-4-result.png){ 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:**
| ![Template Slide 1](./office-render/explicit-slide-1.png){ width=290px } | ![Template Slide 2](./office-render/explicit-slide-2.png){ width=290px } |
| - | - |
| ![Template Slide 3](./office-render/explicit-slide-3.png){ width=290px } | ![Template Slide 4](./office-render/explicit-slide-4.png){ width=290px } |
**Config:**
```json
{
"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 |
| ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| ![Slide 1](https://kb.looplex.com.br/pt-BR/technical/code/office-render/explicit-slide-1-result.png){ width=290px } | ![Slide 2](https://kb.looplex.com.br/pt-BR/technical/code/office-render/explicit-slide-4-result.png){ width=290px } |
# TÓPICOS AVANÇADOS
## Raw OOXML
O padrão que define os arquivos `docx`, `pptx` e `xslx` se chama [ECMA-376](https://www.ecma-international.org/publications-and-standards/standards/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:**
```js
{{@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.