Skip to content
Renato Crivano edited this page Apr 4, 2023 · 8 revisions

Modelos Simples Utilizando Markdown e JModel

Introdução

Tradicionalmente os modelos do Siga-Doc são desenvolvidos utilizando HTML e a linguagem FreeMarker. Embora esta seja uma opção viável e muito flexível, em muitos casos o desenvolvimento dos modelos se torna demasiado complexo.

Surgiu então a necessidade de simplificar os modelos, na esperança de que os próprios usuários, ou pessoas com menos conhecimento de programação, também fossem capazes de produzir modelos. Pelo menos os mais simples.

Em vez de HTML, os modelos simples utilizam Markdown, que é uma linguagem de marcação muito mais simples e concisa, e que é convertida facilmente em HTML. Markdown é utilizado por muitas empresas, como a Wikipedia e o GitHub, que precisam gerar documentos padronizados, sem dar espaço para muitas "invenções", mas mantendo as principais capacidades de formatação que o HTML oferece. Além do link acima, uma lista de comandos e as formatações produzidas pode ser vista aqui.

Em vez do FreeMarker foi desenvolvida uma nova ferramenta de processamento de modelos chamada JModel. O Jmodel tem por objetivo facilitar ao máximo o trabalho de marcar onde entram os campos que devem compor a "entrevista".

Modelos Básicos

O modelo mais simples de todos é composto de um único parágrafo de texto no qual existe a inserção de um campo para perguntar, por exemplo, o nome de uma pessoa. Este modelo pode ser visto abaixo:

Olá, {nome}!

Se, na entrevista, for fornecido o nome "Renato" o documento resultante terá um único parágrafo, que será assim:

Olá Renato!

Claro que é possível criar mais parágrafos, e para isso basta pular uma linha no texto. Também se pode introduzir quantos campos quiser. Só com esse conhecimento, já seria possível criar um modelo bem básico, algo do tipo:

Eu, {nome}, portador do CPF número {cpf}, venho pedir {pedido}.

Alego ao meu favor que {alegacao}.

Uma coisa importante a respeito dos campos é que o nome que é utilizado deve sempre começar com uma letra minúscula e ser composto por letras não acentuadas, números e o caracter sublinhado (_). Este nome é o identificador de uma variável, por isso tem que respeitar estas limitações.

Tipos de Campos

O mais comum é utilizar campos que permitem a informação de uma linha de texto. No entanto, em muitos casos queremos que o campo aceite apenas um CPF, uma data, ou algum outro tipo de dado específico.

Uma tabela com todos os tipos de campos suportados pelo sistema pode ser vista abaixo:

Tipo Prefixo Descrição
texto Campo de texto padrão
selecao Campo de seleção em lista
memo memo Campo de texto de múltiplas linhas
data dt Campo de texto para entrada de data
hora hm Campo de texto para entrada de hora
numero num Campo de texto para entrada de número inteiro
valor val Campo de texto para entrada de valor monetário
checkbox chk Campo do tipo "checkbox" do HTML
radio rad Campo do tipo "radio" do HTML
editor Campo de edição de HTML
cpf cpf Campo de texto para entrada de CPF
cnpj cnpj Campo de texto para entrada de CNPJ
pessoa pessoa Campo de seleção de pessoa
lotacao lotacao Campo de seleção de lotação
cossignatario Campo para seleção de cossignatário (será automaticamente incluído na lista de cossignatários do documento)
funcao funcao Campo para seleção de função gratificada
oculto Campo do tipo "hidden" do HTML

O nome da variável pode ser utilizado para inferir o tipo. Por exemplo, se o nome for "cpf" ou "cpf_servidor" ou "cpfServidor" será automaticamente atribuído o tipo "cpf". Isto acontece porque, como pode ser visto na tabela acima, para alguns tipos de campo existe um "prefixo". O tipo também pode ser especificado diretamente, através do parâmetro "tipo". No exemplo abaixo, todos os campos serão do tipo CPF:

{cpf}
{cpf_servidor}
{cpfServidor}
{codigo kind='cpf'}

Existe um tipo de campo chamado "selecao" que contem uma lista de opções dentre as quais o usuário deve escolher apenas uma. A lista de opções deve ser informada no parâmetro options e precisa estar separada por ";", como pode ser visto no exemplo abaixo:

País: {pais options='Brasil;Argentina'}

Quando o tipo não é informado e nenhum prefixo é reconhecido, se for informado o parâmetro "options" será assumido o tipo "selecao", caso o contrário, será assumido o tipo "texto"

No exemplo abaixo, o campo {cpf} será automaticamente reconhecido e permitirá apenas a entrada de um número válido. E o campo {pedido options='férias;licença médica'} apresentará apenas estas duas opções para o usuário selecionar. Além disso, o campo {alegacao kind='memo'} permitirá que o usuário digite um texto de várias linhas.

Eu, {nome}, portador do CPF número {cpf}, venho pedir {pedido options='férias;licença médica'}.

Alego ao meu favor que {alegacao kind='memo'}.

Outros Parâmetros de Campos

O título de um campo na entrevista pode ser especificado através do parâmetro title:

Servidor: {nome title='Nome do Servidor'}

O número de linhas e colunas de um campo do tipo memo pode ser espeficicado conforme o exemplo abaixo:

{memo columns=80 lines=3}

Por padrão o preenchimento dos campos é opcional, mas se for obrigatório, basta incluir o parâmetro required=true:

Nome: {nome required=true}

Caso deseje informar um valor default para o campo, isso pode ser obtido conforme o exemplo abaixo:

País: {pais default='Brasil'}

Trechos Opcionais com o Comando IF

Quando precisamos que trechos do modelo sejam apresentados, ou não, dependendo do preenchimento de algum campo anterior, podemos utilizar o comando IF. No exemplo abaixo, a Unidade Federativa será perguntada apenas se a esfera for "Estadual". Se a esfera for "Federal", nenhuma pergunta posterior será feita:

Esfera: {esfera options='Federal;Estadual' refresh='esf'}

{if esfera=='Estadual' depend='esf'}
Estado: {uf options='RJ;SP'}
{/if}

Este exemplo introduz uma série de novidades. Vamos estudá-las uma a uma.

Os Parâmetros Refresh e Depend

Temos dois novos parâmetros que são o refresh e o depend. Eles são utilizados para indicar ao sistema que quando é feita uma alteração no campo que tem o parâmetro refresh o comando que tem o depend deve ser atualizado. E, para isso, é importante que o valor informado para o refresh seja o mesmo que foi informado para o depend, no exemplo acima foi utilizado o valor 'esf', que são as 3 primeiras letras de "esfera". Em vez disso, poderia ser qualquer outra coisa como, por exemplo, 'esfera-alterada'.

Se não utilizarmos o refresh e o depend a entrevista não será automaticamente alterada para apresentar o campo "Estado" quando o usuário selecionar a esfera "Estadual". Neste caso, seria necessário dar um OK na edição do documento e depois voltar a editá-lo para que o campo de "Estado" fosse apresentado.

O comando refresh sempre aceita um único valor. Já o depend pode receber uma lista de valores separados por ponto-e-vírgula para indicar que qualquer alteração em um dos campos marcados com refresh causará a atualização do comando. Por exemplo, poderíamos ter um comando assim: {if pais=='Brasil' && esfera=='Estadual' depend='pais;esf'}.

Os Comandos {if} e {/if}

O comando {if esfera=='Estadual' depend='esf'} marca o início do trecho que é opcional, e o comando {/if} marca o final. Tudo que está entre estes dois comando será suprimido caso a expressão esfera=='Estadual' não seja verdadeira.

No exemplo acima estamos comparando o valor da variável esfera com a constante 'Estadual'. Observe que o último está entre aspas simples. Isso é necessário para que o valor da constante não se confunda com o nome de outra variável.

Estamos usando o operador de igualdade, ==, mas muitos outros operadores poderiam ser utilizados como, por exemplo, o de desigualdade: !=. Todas as expressões do FreeMarker estão disponível para uso e, inclusive, podem conter operadores lógicos como "e" (&&), "ou" (||) e "não" (!).

Repetição com o Comando FOR

Em algumas situações é necessário repetir um trecho do documento ou da entrevista diversas vezes, por exemplo, se desejarmos colher o nome de várias pessoas. Uma maneira comum de fazer isso é perguntando primeiro quantas pessoas são e depois usando o comando for para repetir várias vezes o trecho do documento que contém o campo que pergunta o nome. Um exemplo deste tipo de modelo pode ser visto abaixo:

Número de Pessoas: {num options='1;2;3;4;5' refresh='num'}

{for num depend='num'}
Nome: {nome}
{/for}

A primeira coisa que percebemos no exemplo acima é que precisamos usar a mesma lógica de refresh e depend que usamos no caso do if. Ela é necessária para que os campos sejam criados dinamicamente na entrevista, conforme o usuário escolhe o número de pessoas.

O comando for recebe como parâmetro uma variável que deve conter um número inteiro. O trecho entre o for e o /for será repetido o número de vezes indicado por esse parâmetro.

Os campos que estiverem dentro de um for terão seus nomes acrescidos de um sufixo que varia de 1 até o número final da repetição. Por exemplo, se o usuário selecionar o número 3, em um {for 3} os 3 campos de nome gerados ganhariam o nomes nome1, nome2 e nome3.

Se houver a necessidade de utilizar esse contador em alguma expressão do FreeMarker, ou simplesmente imprimi-lo no documento final, o contador fica disponível na variável automática _index.

Por exemplo, se desejarmos incluir o número do contador no título do campo que aparece na entrevista, podemos fazer assim:

{nome title='Nome '+_index}

Selecionando o Estilo do Documento

Até agora vimos como se faz para criar o texto do documento e não consideramos outros aspectos como brasão, cabeçalho, assinatura, rodapé, etc.

Existem alguns estilos pré-definidos para os documentos e para inserirmos nosso texto dentro de um deles utilizaremos o comando set. O que este comando faz é atribuir valores para algumas variáveis que controlarão a seleção do estilo e alguns parâmetros para configurar detalhes de formatação.

Existem algumas variáveis que são padrão do JModel e é fácil identificá-las pois os nomes são em inglês e elas são escritas em letras todas maiúsculas. A principal variável que precisa ser definida se chama STYLE e é utilizada para escolher o estilo do documento. A tabela completa pode ser vista abaixo:

Variável Objetivo
STYLE Define o estilo do documento e aceita as seguintes opções, todas entre aspas simples: memorando, assentamentoFuncional, requerimento, processo, provimento, portaria, oficio e solicitacao. Se nenhum valor for informado será criado um documento do estilo default apenas com brasão centralizado e assinatura.
PAGE_SIZE Define o formato da página, o valor default é 'A4'
PAGE_ORIENTATION Define a orientação da página que por padrão é 'portrait' mas pode também ser 'landscape'
MARGIN_LEFT Margem esquerda que por padrão é '3cm'
MARGIN_RIGHT Margem direita que por padrão é '2cm'
MARGIN_TOP Margem superior que por padrão é '1cm'
MARGIN_BOTTOM Margem inferior que por padrão é '2cm'

Também existem parâmetros complementares que são específicos do Siga-Doc e podem ser vistos na tabela abaixo:

Variável Objetivo
_fecho Indica o fecho de um memorando, requerimento ou ofício, o valor default é 'Atenciosamente,' para memorando e requerimento
_tamanhoLetra Permite aumentar ou diminuir o tamanho do fonte, as opções são Pequena, Normal e Grande, o valor default é 'Normal'
_tipo Sobrescreve o tipo do documento que é apresentado logo antes do número
_formatarOrgao Apresenta o nome do órgão junto aos dados da assinatura
_ementa Texto da ementa, apenas para provimento
_titulo Título, apenas para provimento
_subtitulo Subtítulo, apenas para provimento
_dispoeSobre Texto informado sobre o que dispõe a portaria
_abertura Texto de abertura da portaria
_tipoAutoridade Tipo de autoridade do ofício
_genero Gênero da autoridade do ofício
_vocativo Vocativo da autoridade do ofício
_enderecamentoDest Endereçamento do destinatário do ofício
_nomeDest Nome do destinatário do ofício
_cargoDest Cargo do destinatário do ofício
_orgaoDest Órgão destinatário do ofício
_enderecoDest Endereço do destinatário do ofício
_assunto Assunto da solicitação
_exibeAssinatura Indica se o estilo default deve exibir assinatura, o default é true
_orgaoCabecalho Indica se o estilo default deve apresentar o nome do órgão no cabeçalho, o valor default e true
_numeracaoCentralizada Indica se a numeração do estilo default deve ser centralizada, o valor default é false
_dataAntesDaAssinatura Indica se a data deve ser exibida logo antes da assinatura no estilo default, o valor default é false
_incluirMioloDJE Indica se o "miolo" do documento deve ser exportado para o Diário no estilo default, o valor default é false
_omitirCodigo Indica se o código do documento deve ser omitido no estilo default, o valor default é false
_omitirData Indica se a data do documento deve ser omitido no estilo default, o valor default é false
_topoPrimeiraPagina Texto a ser incluído no topo da primeira página do documento no estilo default
_incluirAssinaturaBIE Indica se a assinatura deve ser incluída no Boletim Interno no estilo default, o valor default é true
_exibeClassificacaoDocumental Indica se o código da classificação documental deve ser incluída no documento no estilo default, o valor default é true
_exibeRodapeEnderecamento Indica se o rodapé de endereçamento deve ser incluída no documento no estilo default, o valor default é false

Um memorando bem simples poderia ser gerado da seguinte forma:

{set STYLE='memorando' _fecho='Cordialmente,'}

Eu, {nome}, estou de acordo.

Executando Operações em Momentos do Ciclo de Vida com o Comando HOOK

É comum acrescentarmos trechos de código FreeMarker que são executados em determinados momentos do ciclo de vida de um documento. Por exemplo, podemos querer iniciar um procedimento de Workflow quando o documento é assinado, ou validar o preenchimento de algum perfil antes da assinatura. Para isso existe o comando hook. No exemplo abaixo, temos o hook sendo utilizado exatamente para esse fim:

{hook 'BEFORE_SIGN'}
  [#if !doc.getResponsaveisPorPapel("gestor")??]
    ${exbl.appException("Não é permitido assinar este documento antes de definir uma pessoa ou lotação com o papel de Gestor para representar o proponente da solicitação de deslocamento")}
  [/#if]
{/hook}

{hook 'AFTER_SIGN'}
  [#assign criado = func.criarWorkflow('TRF2: Solicitação de Deslocamento', doc, cadastrante, titular, lotaCadastrante, lotaTitular) /]
{/hook}

As etapas do ciclo de vida que são interceptadas pelo hook são as seguintes:

Identificador Etapa
BEFORE_SAVE Imediatamente antes de gravar o documento
AFTER_DRAFT Quando o documento em elaboração é finalizado
BEFORE_SIGN Imediatamente antes de gravar a assinatura
AFTER_SIGN Imediatamente depois de gravar a assinatura

Organizando os Campos na Entrevista com o Comando GROUP

Se desejarmos agrupar alguns campos da entrevista, ou se quisermos acrescentar um aviso ao usuário que vai minutar o documento, podemos utilizar o comando group:

{group title='Identificação' warning='Seus dados serão mantidos em sigilo'}
Nome: {nome}
CPF: {cpf}
{/group}

Organizando os Campos da Entrevista em Colunas

Por padrão cada campo ocupará uma linha inteira na página de entrevista. Muitas vezes este tamanho todo é desnecessário. Para criar campos menores, podemos utilizar o parâmetro col. Para o sistema, uma linha da entrevista contém o equivalente a 12 colunas. Sendo assim, poderíamos criar 2 campos, cada um com a largura de 6 colunas para que eles dividam a linha meio-a-meio:

Nome: {nome col=6}
CPF: {cpf col=6}

Outras opções podem ser exploradas, por exemplo, o nome poderia ocupar 2/3 da linha e o CPF o terço restante:

Nome: {nome col=8}
CPF: {cpf col=4}

Inserindo os Modelos no Siga-Doc

Existem duas maneiras para inserir Modelos Simples no Siga-Doc.

A primeira consiste em selecionar a opção "FreeMarker" e incluir o modelo diretamente. O Siga-Doc faz uma avaliação do modelo e concluirá que se trata de um modelo simples desde que ele não encontre nenhuma das macros @entrevista, @documento, @descricao, @markdown ou @dadosComplementares.

Por outro lado, pode ser interessante misturar o Modelo Simples com outras definições feitas diretamente em FreeMarker, do jeito antigo. A segunda opção, portanto, consiste em incluir o Modelo Simples entre as pseudo macros [@markdown] e [/@markdown]. Dizemos que são pseudo macros porque elas não são processadas pelo FreeMarker com as macros comuns, elas são detectadas pelo Siga-Doc e o conteúdo é convertido em FreeMarker e Markdown pelo JModel. Um exemplo de uso desta segunda opção seria:

[@entrevista]
  [@campo var="nome" /]
[/@entrevista]

[@markdown]
  Olá {print nome}!
[/@markdown]

Limitações do Markdown e do JModel

Em determinadas situações pode ser necessário criar algum tipo de diagramação não suportada pelo Markdown.

De maneira geral, isso provavelmente significa que estamos querendo criar um documento digital como se ele fosse um daqueles antigos formulários para serem preenchidos a mão. Por favor, não façam isso. A estética desses documento é coisa de outra época. Mesmo assim, ainda existem pessoas que acreditam que é assim que fica bonito. Fazer documentos digitais com caixinhas como se eles fossem ser preenchidos manualmente dificulta, complica e é muito contraproducente.

Se, mesmo assim, for detectada a necessidade de usar algum tipo de diagramação não suportada pelo Markdown, a boa notícia é que código HTML pode ser escrito junto com o Markdown, sem problema algum:

<p style="color: red">Olá, {nome}</p>

Por outro lado, pode ser necessário usar IFs ou FORs ou expressões mais complexa. Neste caso, é possível aplicar código FreeMarker diretamente no Modelo Simples, conforme pode ser visto abaixo:

País: {pais options='Brasil;Argentina'}

[#if pais=='Brasil']
  Ótimo lugar para se morar!
[/#if]
Clone this wiki locally