Files
apitdn/fluig_rag_docs/Plataforma Documentação técnica/Recurso de Páginas e Widgets (WCM)/Construção de Widgets e Layouts.md
T
2026-05-06 13:35:47 -03:00

427 lines
19 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: Construção de Widgets e Layouts
source: https://tdn.totvs.com/pages/viewpage.action?pageId=113803693
path: \Plataforma Documentação técnica\Recurso de Páginas e Widgets (WCM)\Construção de Widgets e Layouts.md
---
# Índice
- 1 [Objetivo](#ConstruçãodeWidgetseLayouts-Objetivo)
- 2 [Vídeos How To](#ConstruçãodeWidgetseLayouts-VídeosHowTo)
- 3 [Construção de componentes WCM no Eclipse](#ConstruçãodeWidgetseLayouts-ConstruçãodecomponentesWCMnoEclipse)
- 3.1 [Criação do Widget](#ConstruçãodeWidgetseLayouts-CriaçãodoWidget)
- 3.2 [Estrutura dos diretórios de widgets](#ConstruçãodeWidgetseLayouts-Estruturadosdiretóriosdewidgetstabelaestruturawidget)
- 3.3 [Exemplo de código JavaScript](#ConstruçãodeWidgetseLayouts-ExemplodecódigoJavaScript)
- 3.4 [Exemplo de código HTML com FreeMarker (view.ftl)](#ConstruçãodeWidgetseLayouts-ExemplodecódigoHTMLcomFreeMarker(view.ftl))
- 3.5 [Criação de Layout](#ConstruçãodeWidgetseLayouts-CriaçãodeLayout)
- 3.6 [Exemplo de código FreeMarker (layout.ftl)](#ConstruçãodeWidgetseLayouts-ExemplodecódigoFreeMarker(layout.ftl))
- 3.7 [Exemplo de código JavaScript](#ConstruçãodeWidgetseLayouts-ExemplodecódigoJavaScript.1)
- 3.8 [Exemplo de códigos para inclusão de componentes nos layouts (view.ftl)](#ConstruçãodeWidgetseLayouts-Exemplodecódigosparainclusãodecomponentesnoslayouts(view.ftl))
- 4 [Snippets](#ConstruçãodeWidgetseLayouts-Snippets)
- 5 [Autocompletar para FreeMarker e JavaScript](#ConstruçãodeWidgetseLayouts-AutocompletarparaFreeMarkereJavaScript)
- 6 [Exportar componente para o servidor Fluig](#ConstruçãodeWidgetseLayouts-ExportarcomponenteparaoservidorFluig)
# Objetivo
O objetivo deste guia é possibilitar ao desenvolvedor criar componentes WCM via Eclipse ou Fluig Studio.
# Vídeos How To
Assista!
Confira os vídeos How To sobre [Criação de páginas com layouts e widgets](https://tdn.totvs.com/pages/viewpage.action?pageId=270925442).
Compatibilidade no modo escuro
Este recurso ainda não é compatível com o modo escuro lançado na atualização [Voyager 2.0](https://tdn.totvs.com/x/6HxjN). Para mais detalhes, consulte a documentação em: add link
# Construção de componentes WCM no Eclipse
Para iniciar o desenvolvimento de um componente WCM no Eclipse ou [Fluig Studio](../Instalação e Atualização/Guia de instalação Fluig Studio.md), é necessário acessar a perspectiva Fluig e criar um novo projeto.
- Acionar o menu ***Window*** na barra de menu.
- Selecionar ***Perspective*** → ***Open Perspective*** → ***Other*...**.
- Selecionar **Fluig** e acionar **OK**.
![](..\..\images\open_fluig_perspective.gif)
**Perspectiva Fluig no Eclipse**
- Clicar com o botão direito do *mouse* no espaço *Package Explorer*.
- Selecionar ***New*** → **Projeto Fluig**.
- Informar o nome do projeto no campo *Project name*.
- Acionar ***Finish***.
![](..\..\images\create_new_project.gif)
**Criação de um novo projeto Fluig**
### Criação do Widget
Com o ambiente de desenvolvimento preparado, pode ser iniciada a criação do *widget* no projeto conforme os passos a seguir.
- Clicar com o botão direito do *mouse* sobre o projeto Fluig criado.
- Selecionar ***New*** → ***Widget***.
![](..\..\images\new_widget_1.png)
- Informar o código do *widget* no campo **Código**. Este campo é uma **chave única** e obrigatório.
O campo Código aceita apenas letras, números e sublinhado.
- Informar o nome do *widget* no campo **Nome**.
- Informar uma breve descrição do *widget* no campo **Descrição**.
- Escolher um dos *templates* disponíveis para o desenvolvimento do *widget* no campo **Template** ou manter o padrão "Nenhum" para não utilizar um modelo de desenvolvimento.
- Acionar ***Next*** para avançar.
![](..\..\images\new_widget_2.png)
- Informar o código, nome e URL para identificação do desenvolvedor do componente (Opcional).
- Informar a categoria do *widget* (Opcional).
As categorias funcionam como filtros para localizar *widgets* mais rapidamente e são listadas no painel esquerdo da janela de seleção de *widgets* exibido ao incluir novos *widgets* em um *slot*.
- Apenas um renderizador é disponibilizado atualmente (FreeMarker).
- Acionar ***Finish*** para concluir a criação do *widget*.
![](..\..\images\new_widget_3.png)
- Concluída a etapa de criação do *widget*, uma estrutura de diretórios será gerada abaixo da pasta "wcm/widget" do projeto.
A descrição dos arquivos gerados está disponível no item [Estrutura dos diretórios de *widgets*](https://tdn.totvs.com/pages/viewpage.action?pageId=113803693).
![](..\..\images\new_widget_4.png)
### Estrutura dos diretórios de *widgets*
| Arquivo/Pasta | Descrição |
| --- | --- |
| [código\_do\_widget] | Nome/Identificador do *widget*. |
| src/main/java | Localização das classes Java, caso exista alguma regra de negócio específica do *widget*. |
| src/main/resources/application.info | Arquivo de configuração do *widget* onde são gravados o código, título e desenvolvedor do *widget*, entre outros dados. Este arquivo será detalhado nas próximas páginas deste documento. |
| src/main/resources/view.ftl | Arquivo de *template* do FreeMarker que será interpretado durante a renderização do *widget*. |
| src/main/resources/edit.ftl | Arquivo que será interpretado durante a renderização do *widget* em modo de edição. Usado para configurar opções específicas para renderização do *widget*, como por exemplo, filtros de data, cotação do dólar, etc. Este arquivo é opcional. Caso não exista, será considerado que o *widget* não possui modo de edição, somente visualização. |
| src/main/resources/[código\_do\_widget].properties | Arquivo de *strings* traduzíveis utilizadas pelo *widget*. Deve possuir derivações de acordo com o idioma suportado pelo *widget*. O padrão será sempre o código do *widget* seguido do sufixo referente à sua linguagem. Por exemplo: um arquivo de tradução para o idioma inglês ficaria “código-do-widget\_EN\_US.properties”. |
| src/main/webapp/icon.png | Ícone utilizado para representar o *widget* no menu lateral da aplicação, ou em qualquer tela que necessite de uma representação visual do componente. Deve possuir a dimensão 55 x 30 *pixels*. |
| src/main/webapp/WEB-INF/web.xml | Descritor padrão de uma aplicação Java para *web*. |
| src/main/webapp/WEB-INF/jboss-web.xml | Descritor específico para o servidor de aplicação. Deve conter obrigatoriamente a propriedade “context-root”. O context-root representa o contexto *web* do *widget* e o recomendado é que o valor seja o próprio código do *widget*. |
| src/main/webapp/resources/css/[código\_do\_widget].css | Folha de estilo do *widget*. |
| src/main/webapp/resources/js/[código\_do\_widget].js | Arquivo JavaScript do *widget* (caso seja necessário). |
| src/main/webapp/resources/images | Pasta específica de imagens do *widget*, caso necessário. |
| src/test/java | Pasta específica para a construção de testes unitários. |
Atenção!
**01.** Não devem ser criadas novas pastas no diretório *"*src/main/resources*"*. O recomendado é que sejam utilizadas as pastas já existentes no projeto.
**02.** Ao criar um *widget*, os itens abaixo devem possuir o mesmo nome. Este nome deve ser **único**, ou seja, não pode ser utilizado em nenhum outro *widget*, pois a duplicidade pode causar problemas durante o *deploy* dos componentes:
- Nome do *widget*.
- Propriedade "context-root" do arquivo jboss-web.xml.
- Propriedade "application.code" do arquivo application.info.
### Exemplo de código JavaScript
```
var HelloWorld = SuperWidget.extend({
message: null,
init: function () {
//code
},
bindings: {
local: {
'show-message': ['click_showMessage']
}
},
showMessage: function () {
$div = $('#helloMessage_' + this.instanceId);
$message = $('<div>').addClass('message').append(this.message);
$div.append($message);
}
});
 
```
### Exemplo de código HTML com FreeMarker (view.ftl)
```
<div id="HelloWorld_${instanceId}" class="super-widget wcm-widget-class fluig-style-guide"
data-params="HelloWorld.instance({message: 'Hello world'})">
<!-- efetua a tradução do texto do objeto i18n -->
<h1>${i18n.getTranslation('hello.example.hello')}</h1>
<div>
<button type="button" class="btn btn-default" data-show-message>${i18n.getTranslation('hello.button.showMessage')}</button>
</div>
<div id='helloMessage_${instanceId}'>
</div>
</div>
```
### Criação de Layout
Com o ambiente de desenvolvimento preparado, pode ser iniciada a criação do *layout* no projeto conforme os passos a seguir.
- Clicar com o botão direito do *mouse* sobre o projeto Fluig criado.
- Selecionar ***New*** → ***Layout***.
![](..\..\images\new_layout_1.png)
- Informar o código do *layout* no campo **Código**. Este campo é uma chave única e obrigatório.
O campo Código aceita apenas letras, números e sublinhado.
- Informar o nome do *layout* no campo **Nome**.
- Informar uma breve descrição do *layout* no campo **Descrição**.
- Escolher um dos *templates* disponíveis para o desenvolvimento do *layout* no campo **Template** ou manter o padrão "Nenhum" para não utilizar um modelo de desenvolvimento.
- Acionar ***Next*** para avançar.
![](..\..\images\new_layout_2.png)
- Informar o código, nome e URL para identificação do desenvolvedor do componente (Opcional).
- Informar a categoria do *layout* (Opcional).
- Apenas um renderizador é disponibilizado atualmente (FreeMarker).
- Acionar ***Finish*** para concluir a criação do *layout*.
![](..\..\images\new_layout_3.png)
- Concluída a etapa de criação do *layout*, uma estrutura de diretórios será gerada abaixo da pasta "wcm/layout" do projeto.
Observação
A estrutura de pastas e arquivos de um componente *Layout* é praticamente a mesma de um componente *Widget*. A principal diferença encontra-se no caminho src/main/resources/ onde os arquivos view.ftl e edit.ftl são substituídos pelo arquivo layout.ftl.
![](..\..\images\new_layout_4.png)
### Exemplo de código FreeMarker (layout.ftl)
```
<div class="fluig-style-guide">
<div id="wcm_header" class="wcm-header-background wcm-header">
<!-- Group left -->
<div class="header-grouper-left">
<a href="home" class="wcm_logo" title="${i18n.getTranslation('layout.label.pagetitle')}">
<#if '${imageLogo}'=='true'>
<img src="${serverContextURL}/resources/images/${pageRender.user.tenantId}/logo_image.png"></img>
<#else>
<img src="${serverContextURL}/resources/images/logo.png"></img>
</#if>
</a>
</div>
<!-- Group right -->
<div class="header-grouper-right">
<!-- Container login -->
<div id="SlotLogin" slot="true" class="slot-header-actions">
<#list (pageRender.getInstancesIds("SlotLogin"))! as id>
${pageRender.renderInstanceNoDecorator(id)}
</#list>
</div>
</div>
</div>
<!-- WCM Wrapper content -->
<div class="wcm-wrapper-content">
<!-- Menu esquerdo -->
<nav class="wcm-navigation wcm-menu-background">
<div id="SlotMenu" slot="true">
<#list (pageRender.getInstancesIds("SlotMenu"))! as id>
${pageRender.renderInstanceNoDecorator(id)}
</#list>
</div>
</nav>
<!-- Wrapper -->
<div class="wcm-all-content">
<div id="wcm-content" class="clearfix wcm-background">
<!--WIDGETS DO LAYOUT -->
<link type="text/css" rel="stylesheet" href="${contextPath}/resources/css/wcm_layout.css"/>
<!-- Onde deverá estar a barra de formatação -->
<#if pageRender.isEditMode()=true>
<div name="formatBar" id="formatBar"></div>
<!-- Div geral -->
<!-- Há CSS distinto para Edição/Visualização -->
<div id="edicaoPagina" class="clearfix">
<#else>
<div id="visualizacaoPagina" class="clearfix">
</#if>
<!-- Titulo da página -->
<div class="slotfull layout-1-1">
<span class="titleArea">${i18n.getTranslation('wcm.layoutdefault.title')}</span>
<h2 class="pageTitle">${pageTitle}</h2>
</div>
<!-- Slot 1 -->
<div class="editable-slot slotfull layout-1-1" id="slotFull1">
<div id="SlotC" slot="true" class="slotint" decorator="false" editableSlot="true">
<#list (pageRender.getInstancesIds("SlotC"))! as id>
${pageRender.renderInstanceNoDecorator(id)}
</#list>
</div>
</div>
<!-- Slot 2 -->
<div class="editable-slot slotfull layout-1-1" id="slotFull2">
<div id="SlotB" slot="true" class="slotint" decorator="false" editableSlot="true">
<#list (pageRender.getInstancesIds("SlotB"))! as id>
${pageRender.renderInstanceNoDecorator(id)}
</#list>
</div>
</div>
<!-- Slot 3 -->
<div class="editable-slot slotfull layout-1-1" id="slotFull3">
<!-- Widget -->
<div id="SlotA" slot="true" class="slotint" decorator="true" editableSlot="true">
<#list (pageRender.getInstancesIds("SlotA"))! as id>
${pageRender.renderInstance(id)}
</#list>
</div>
</div>
</div>
<!-- FIM DAS WIDGETS DO LAYOUT -->
<div id="wcm_footer" class="wcm_footer"></div>
</div>
</div>
</div>
</div>
```
Dica
Para compreender melhor os elementos de um código de layout, leia a [sessão de layouts](http://tdn.totvs.com/display/fluig/Layouts).
### Exemplo de código JavaScript
```
var HelloWorld = SuperWidget.extend({
message: null,
init: function () {
//code
},
bindings: {
local: {
'show-message': ['click_showMessage']
}
},
showMessage: function () {
$div = $('#helloMessage_' + this.instanceId);
$message = $('<div>').addClass('message').append(this.message);
$div.append($message);
}
});
```
### Exemplo de códigos para inclusão de componentes nos layouts (view.ftl)
Os *layouts* customizados do Fluig Plataforma permitem que o desenvolvedor reutilize alguns componentes padrão da plataforma, como o cabeçalho contendo as informações do usuário, campo de busca e notificações globais, rodapé, menu e outros componentes.
Quando o desenvolvedor inicia a criação de um *layout* pelo Eclipse ou Fluig Studio, é possível utilizar alguns exemplos de *layouts* existentes. Em alguns destes *layouts* pré definidos é necessário verificar quais componentes estão presentes e quais foram inseridos, pois algumas vezes é necessário configurar o *slots* no arquivo "src/main/resources/application.info".
Abaixo estão disponíveis alguns exemplos de trechos de código para montagem de componentes no *layout*. Cada um destes códigos possui particularidades e não podem apenas ser incluídos no arquivo view.ftl, pois precisam estar dentro de tags <div> para funcionar de forma correta.
**Inclusão do componente de busca**
- O trecho abaixo deve ser inserido dentro da *tag* <div class="header-grouper-right">, que por sua vez deverá estar dentro da *tag* <div id="wcm\_header" class="wcm-header-background wcm-header">.
- No arquivo src/main/resources/application.info o desenvolvedor deverá incluir: slot.SlotInstantSearch=suggestsearch.
**Componente de Busca**
```
<div id="SlotInstantSearch" slot="true" class="slotint slot-header-actions">
<#list (pageRender.getInstancesIds("SlotInstantSearch"))! as id>
${pageRender.renderInstanceNoDecorator(id)}
</#list>
</div>
```
**Inclusão do componente de notificação/alerta global**
- O trecho abaixo deve ser inserido dentro da *tag* <div class="header-grouper-right">, que por sua vez deverá estar dentro da **tag** <div id="wcm\_header" class="wcm-header-background wcm-header">.
- No arquivo src/main/resources/application.info o desenvolvedor deverá incluir: slot.SlotGlobalAlert=alertpopover.
**Componente de Notificação**
```
<div id="SlotGlobalAlert" slot="true" class="slotint slot-header-actions">
<#list (pageRender.getInstancesIds("SlotGlobalAlert"))! as id>
${pageRender.renderInstanceNoDecorator(id)}
</#list>
</div>
```
# Snippets
A opção Snippets fornece ao desenvolvedor um pequeno trecho de código-exemplo relacionado a um determinado recurso. O objetivo é fornecer um modo rápido e simples para que o desenvolvedor visualize um exemplo de código e dê início à construção do componente.
- Acionar o menu ***Window*** na barra de menu.
- Selecionar ***Show View*** → ***Other*...**
- Expandir a pasta ***General***, selecionar ***Snippets*** e acionar **OK**.
![](..\..\images\show_view_snippets.gif)
A visão Snippets apresentará as opções para Componentes WCM conforme o tipo de arquivo em foco (JavaScript ou FTL):
![](..\..\images\snippets_javascript.png)
![](..\..\images\snippets_ftl.png)
# Autocompletar para FreeMarker e JavaScript
Os arquivos Freemarker (extensão ".ftl"), quando abertos com o editor Freemarker do Fluig Plataforma, dispõe do recurso autocompletar para as diretivas básicas do FTL (iniciadas em "<#") e para as variáveis de contexto nas interpolações do Freemarker ("${}"). Os nomes contextuais disponíveis para o autocompletar são widgetRender e pageRender.
Os arquivos JavaScript (extensão ".js"), quando abertos em um Projeto Fluig, também dispõe do recurso autocompletar para as APIs nativas do JavaScript e do Fluig Plataforma.
Utilize o atalho do teclado CTRL + Barra de espaço para forçar a exibição do autocompletar no Eclipse ou Fluig Studio.
![](..\..\images\autocomplete_javscript.png)
![](..\..\images\autocomplete_ftl.gif)
# Exportar componente para o servidor Fluig
A partir deste momento é possível gerar o pacote e instalar o componente no servidor, ou seja, fazer o *deploy*.
- Selecionar a pasta do *widget* ou *layout* que será exportado e clicar sobre ela com o botão direito do *mouse*.
- Acionar ***Export*...**
- Selecionar a opção **Exportar para servidor Fluig** e acionar ***Next**.*
- Selecionar o servidor desejado dentre os servidores cadastrados no Eclipse ou Fluig Studio.
- Acionar ***Finish***.
Após a exportação, o componente estará disponível para utilização na [criação](http://tdn.totvs.com/pages/viewpage.action?pageId=234455933) e [edição](http://tdn.totvs.com/pages/viewpage.action?pageId=234455936) de páginas do Fluig Plataforma.
![](..\..\images\deploy_widget.gif)
Third Party Trademarks
*JavaScript is a trademark of Oracle Corporation.*
*Firefox and Mozilla are registered trademarks of the Mozilla Foundation.*
*Google, Android and Google Chrome are trademarks of the Google Inc.*
*Oracle, Java and [OpenOffice.org](http://OpenOffice.org) are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of their respective owners.*
*Red Hat and JBoss are registered trademarks of Red Hat, Inc. in the United States and other countries.*
*Any other third party trademarks are the property of their respective owners.*