Files

1626 lines
59 KiB
Markdown
Raw Normal View History

2026-05-06 13:35:47 -03:00
---
title: WCMAPI
source: https://tdn.totvs.com/display/fluig/WCMAPI
path: \Plataforma Documentação técnica\Recurso de Páginas e Widgets (WCM)\WCMAPI.md
---
- 1 [Visão Geral](#WCMAPI-VisãoGeral)
- 1.1 [Como Começar](#WCMAPI-ComoComeçar)
- 1.2 [Contexto de Dados (Tenant e Página)](#WCMAPI-ContextodeDados(TenantePágina))
- 1.3 [Contexto da Página](#WCMAPI-ContextodaPágina)
- 1.4 [Usuário Atual](#WCMAPI-UsuárioAtual)
- 1.5 [Contexto do Usuário](#WCMAPI-ContextodoUsuário)
- 1.6 [Sessão e Autenticação](#WCMAPI-SessãoeAutenticação)
- 1.7 [Ambiente](#WCMAPI-Ambiente)
- 1.8 [Interface (UI)](#WCMAPI-Interface(UI))
- 1.9 [Carregamento de Recursos (CSS e JS)](#WCMAPI-CarregamentodeRecursos(CSSeJS))
- 1.10 [Renderização de Templates FTL](#WCMAPI-RenderizaçãodeTemplatesFTL)
- 1.11 [Ciclo de Vida de Widgets](#WCMAPI-CiclodeVidadeWidgets)
- 1.12 [Sistema de Eventos](#WCMAPI-SistemadeEventos)
- 1.13 [Requisições AJAX](#WCMAPI-RequisiçõesAJAX)
- 1.14 [OAuth](#WCMAPI-OAuth)
- 1.15 [Atributos de Sessão no Servidor](#WCMAPI-AtributosdeSessãonoServidor)
- 1.16 [Utilitários JavaScript](#WCMAPI-UtilitáriosJavaScript)
- 1.17 [Utilitários de URL](#WCMAPI-UtilitáriosdeURL)
- 1.18 [Configurações Globais jQuery](#WCMAPI-ConfiguraçõesGlobaisjQuery)
- 1.19 [Namespace WCM](#WCMAPI-NamespaceWCM)
- 1.20 [Boas Práticas](#WCMAPI-BoasPráticas)
- 1.21 [Erros Comuns](#WCMAPI-ErrosComuns)
- 1.22 [Dicas de Performance](#WCMAPI-DicasdePerformance)
# Visão Geral
---
O `WCMAPI` é a **API JavaScript central da plataforma Fluig WCM**. Ele expõe um objeto singleton global disponível em todos os widgets, temas e formulários da plataforma.
Por meio do `WCMAPI` você consegue:
- Saber quem é o usuário logado e qual é o tenant (empresa) ativo
- Ler o contexto da página atual (código, tipo, layout)
- Carregar dinamicamente arquivos CSS e JavaScript
- Renderizar templates FreeMarker (`.ftl`) de forma síncrona ou assíncrona
- Instanciar widgets via `loadWidgets()`
- Publicar e assinar eventos entre widgets (pub/sub)
- Realizar chamadas AJAX com autenticação JWT automática
- Validar tokens OAuth de integrações externas
- O objeto é acessível em **qualquer script carregado após este arquivo**:
```
// Sempre use o singleton - nunca instancie o WCMAPI diretamente
const usuarioLogado = WCMAPI.getUserLogin();
const tenant        = WCMAPI.getTenantCode();
```
## Como Começar
---
O `WCMAPI` já estará disponível como variável global no momento em que seu widget ou tema for executado. **Não é necessário importar, instanciar ou configurar nada.**
### Dentro de um widget Fluig
```
// Verificar se o usuário está logado antes de fazer qualquer operação
if (WCMAPI.getUserIsLogged()) {
    const login = WCMAPI.getUserLogin();
    const nome  = `${WCMAPI.getUserFirstName()} ${WCMAPI.getUserLastName()}`;
    console.log(`Bem-vindo, ${nome}!`);
}
```
### Renderizando um template FTL no widget
```
// Renderizar o template view.ftl do app "meuWidget" e injetar no elemento #conteudo
WCMAPI.convertFtlAsync('meuWidget', 'view.ftl', { filtro: 'ativo' }, (html) => {
    $('#conteudo').html(html);
    WCMAPI.loadWidgets();
});
```
### Verificando feature flags
```
if (WCMAPI.isFeatureEnabled('NOVO_PAINEL')) {
    carregarNovoPainel();
} else {
    carregarPainelLegado();
}
```
## Contexto de Dados (Tenant e Página)
---
Estes valores são fornecidos automaticamente pela plataforma antes de qualquer widget ser inicializado.
**Regra fundamental:** nunca acesse ou modifique propriedades do `WCMAPI` diretamente (ex.: `WCMAPI.tenantCode`). Utilize **sempre** os métodos getter/setter correspondentes. O acesso direto às propriedades é considerado legado e pode ser removido em versões futuras.
### getTenantCode() / setTenantCode(value)
**Descrição:** Retorna ou define o código único que identifica o tenant (empresa) ativo. Preenchido automaticamente pela plataforma; raramente é necessário usar o setter em widgets.
**Retorno de `getTenantCode()`:** `string` — ex.: `'minhaempresa'`
**Parâmetros de `setTenantCode()`:**
- `value` (`string`): novo código do tenant
```
const tenant = WCMAPI.getTenantCode();
const url = `/api/public/2.0/${tenant}/users`;
```
### getTenantId() / getOrganizationId() / setOrganizationId(value)
**Descrição:** Retorna ou define o identificador numérico do tenant. `getTenantId()` é um alias para `getOrganizationId()`. Use `setOrganizationId()` para definir o valor — não existe `setTenantId()`.
**Retorno:** `number` — valor padrão `-1` quando não há tenant carregado.
**Parâmetros de `setOrganizationId()`:**
- `value` (`number`): identificador numérico do tenant
```
const idTenant = WCMAPI.getTenantId();
```
### getTenantURI() / setTenantURI(value)
**Descrição:** Retorna ou define o segmento de URI do tenant usado nas URLs de páginas da plataforma.
**Retorno de `getTenantURI()`:** `string` — ex.: `'/portal/p/minhaempresa'`
```
// Redirecionar para a home do tenant
window.location.href = `${WCMAPI.getTenantURI()}/home`;
```
### getTenantURL() / setTenantURL(value)
**Descrição:** Retorna ou define a URL completa do tenant (esquema + host + caminho do tenant).
**Retorno de `getTenantURL()`:** `string` — ex.: `'https://minhaempresa.fluig.com/minhaempresa'`
### getTenantPATH() / setTenantPATH(value)
**Descrição:** Retorna ou define apenas o segmento de caminho do tenant (sem esquema e host).
**Retorno de `getTenantPATH()`:** `string` — ex.: `'/minhaempresa'`
### getServerURL() / setServerURL(value)
**Descrição:** Retorna ou define a URL base do servidor (esquema + host), sem nenhum caminho adicional.
**Retorno de `getServerURL()`:** `string` — ex.: `'https://minhaempresa.fluig.com'`
### getServerContextURL() / setServerContextURL(value)
**Descrição:** Retorna ou define a URL completa do contexto do servidor (esquema + host + context path do portal).
**Retorno de `getServerContextURL()`:** `string`
### getContextPath() / setContextPath(value)
**Descrição:** Retorna ou define o context path do portal no servidor de aplicação.
**Retorno de `getContextPath()`:** `string` — ex.: `'/portal'`
### getHomePage()
**Descrição:** Monta e retorna a URL completa da página inicial do tenant.
**Retorno:** `string` — equivale a `getTenantURI() + '/' + getHomePageCode()`
```
// Redirecionar o usuário para a home
window.location.href = WCMAPI.getHomePage();
```
### getPageCode() / setPageCode(code) / getPageId() / setPageId(id) / getPageType() / setPageType(type) / getPageLayout() / setPageLayout(layoutId)
**Descrição:** Retornam ou definem informações sobre a página WCM atualmente renderizada. Os setters são utilizados internamente pela plataforma; em widgets, utilize apenas os getters.
| | | | |
| --- | --- | --- | --- |
| Getter | Setter | Retorno | Exemplo |
| `getPageCode()` | `setPageCode(code)` | `string|null` | `'home'` |
| `getPageId()` | `setPageId(id)` | `number|null` | `42` |
| `getPageType()` | `setPageType(type)` | `string|null` | `'public'` |
| `getPageLayout()` | `setPageLayout(layoutId)` | `number|null` | `3` |
| `getPageTitle()` | `setPageTitle(title)` | `string|null` | `'Início'` |
| `getParentPageCode()` | `setParentPageCode(code)` | `string|null` | `'portal'` |
| `getFriendlyURL()` | `setFriendlyURL(url)` | `string|null` | `'/inicio'` |
```
// Evitar exibir avisos na página de boas-vindas
if (WCMAPI.getPageCode() !== 'welcome') {
    mostrarAvisoImportante();
}
```
### getSpaceAlias() / setSpaceAlias(value)
**Descrição:** Retorna ou define o alias (identificador curto) do espaço Fluig atual.
**Retorno de `getSpaceAlias()`:** `string` — ex.: `'default'`
```
const alias = WCMAPI.getSpaceAlias();
```
### getSpaceId() / setSpaceId(id)
**Descrição:** Retorna ou define o identificador numérico do espaço Fluig atual.
**Retorno de `getSpaceId()`:** `number|null`
```
const spaceId = WCMAPI.getSpaceId();
```
### getHomePageCode() / setHomePageCode(value)
**Descrição:** Retorna ou define o código da página configurada como home/landing page do tenant. Usado por `getHomePage()` para montar a URL completa.
**Retorno de `getHomePageCode()`:** `string` — padrão `'home'`
```
const homeCode = WCMAPI.getHomePageCode(); // 'home'
window.location.href = WCMAPI.getHomePage();
```
### getUploadURL() / setUploadURL(value)
**Descrição:** Retorna ou define a URL utilizada para operações de upload de arquivos na plataforma.
**Retorno de `getUploadURL()`:** `string`
```
const uploadEndpoint = WCMAPI.getUploadURL();
```
### getProtectedContextPath() / setProtectedContextPath(value)
**Descrição:** Retorna ou define o context path para recursos protegidos (que requerem autenticação).
**Retorno de `getProtectedContextPath()`:** `string`
```
const protectedPath = WCMAPI.getProtectedContextPath();
```
### getDomainId() / setDomainId(value) / getDomainName() / setDomainName(value)
**Descrição:** Retornam ou definem o identificador numérico e o nome legível do domínio atual, preenchidos pela plataforma no carregamento da página.
| | | |
| --- | --- | --- |
| Getter | Setter | Retorno |
| `getDomainId()` | `setDomainId(id)` | `number|null` |
| `getDomainName()` | `setDomainName(name)` | `string|null` |
```
const domainId   = WCMAPI.getDomainId();
const domainName = WCMAPI.getDomainName();
```
### getDefaultDomainURL() / setDefaultDomainURL(value)
**Descrição:** Retorna ou define a URL base padrão do domínio atual.
**Retorno de `getDefaultDomainURL()`:** `string|null`
```
const domainUrl = WCMAPI.getDefaultDomainURL();
```
### getIsSAMLEnabled() / setIsSAMLEnabled(value)
**Descrição:** Indica se a autenticação SAML/SSO está habilitada para o tenant. Quando `true`, o login é delegado ao Identity Provider configurado. Use `getIsSAMLEnabled()` no lugar do acesso à propriedade `isSAMLEnabled` diretamente.
> Veja também `isIdentityEnabled()`, que é um alias para `getIsSAMLEnabled()`.
> **Retorno de `getIsSAMLEnabled()`:** `boolean`
```
if (WCMAPI.getIsSAMLEnabled()) {
    // exibir botão "Entrar com SSO"
}
```
### getIdpHomePageURL() / setIdpHomePageURL(value)
**Descrição:** Retorna ou define a URL da página inicial do Identity Provider (IdP), usada nos fluxos de logout com SAML ativo.
**Retorno de `getIdpHomePageURL()`:** `string`
```
const idpUrl = WCMAPI.getIdpHomePageURL();
```
### getFluigPaas() / setFluigPaas(value)
**Descrição:** Indica se a plataforma está rodando em modo PaaS (Fluig em nuvem). Quando `true`, certos recursos e caminhos específicos de PaaS são ativados.
**Retorno de `getFluigPaas()`:** `boolean`
```
if (WCMAPI.getFluigPaas()) {
    usarRecursosDePaas();
}
```
### getApplicationCode() / setApplicationCode(value)
**Descrição:** Retorna ou define o código de aplicação usado para escopo de caminhos de recursos estáticos. Padrão: `'fluig'`.
**Retorno de `getApplicationCode()`:** `string`
```
const appCode = WCMAPI.getApplicationCode(); // 'fluig'
```
### getEnvType() / setEnvType(value)
**Descrição:** Retorna ou define o identificador do ambiente de implantação, como `'production'` ou `'staging'`.
**Retorno de `getEnvType()`:** `string`
```
if (WCMAPI.getEnvType() !== 'production') {
    console.log('[DEV] Modo de diagnóstico ativo');
}
```
### getTenantLocales() / setTenantLocales(value)
**Descrição:** Retorna ou define a lista de códigos de idioma disponíveis para o tenant. Útil para renderizar seletores de idioma em widgets.
**Retorno de `getTenantLocales()`:** `string[]` — ex.: `'pt_BR', 'en_US'.`
```
const locales = WCMAPI.getTenantLocales();
locales.forEach((locale) => adicionarOpcaoDeIdioma(locale));
```
### isFeatureEnabled(featureFlag)
**Parâmetros:**
- `featureFlag` (`string`): identificador da feature a verificar
**Retorno:** `boolean`
```
if (WCMAPI.isFeatureEnabled('EXPORTAR_RELATORIO_PDF')) {
    $('#btn-exportar-pdf').show();
}
```
### getIsEditMode() / setIsEditMode(value)
**Descrição:** Indica se a página está atualmente em modo de edição WCM. Quando `true`, a plataforma exibe controles de edição e a engrenagem dos widgets.
**Não acesse `WCMAPI.isEditMode` diretamente.** Use `getIsEditMode()` para leitura e `setIsEditMode()` para escrita.
**Retorno de `getIsEditMode()`:** `boolean`
**Parâmetros de `setIsEditMode()`:**
- `value` (`boolean`): `true` para ativar o modo de edição
```
if (WCMAPI.getIsEditMode()) {
    mostrarControlesDeEdicao();
}
// Ativar programaticamente (raramente necessário em widgets):
WCMAPI.setIsEditMode(true);
```
## Contexto da Página
---
Essas informações são fornecidas automaticamente pela plataforma no carregamento da página e devem ser tratadas como somente leitura. O uso dos setters não tem efeito no comportamento da plataforma.
### getIsPreviewMode() / setIsPreviewMode(value)
**Somente leitura** — fornecido automaticamente pela plataforma.
**Descrição:** Indica se a página está sendo renderizada em modo de pré-visualização. Neste modo, as alterações ainda não foram publicadas e a URL geralmente contém o parâmetro `?preview=true`.
**Retorno de `getIsPreviewMode()`:** `string` — `'true'` ou `'false'` (chega como string do FreeMarker, não como boolean nativo).
```
if (WCMAPI.getIsPreviewMode() === 'true') {
    mostrarAvisoPreVisualizacao();
}
```
### getPageAuthType() / setPageAuthType(value)
**Somente leitura** — fornecido automaticamente pela plataforma.
**Descrição:** Indica o tipo de autenticação exigido para acesso à página atual.
**Retorno de `getPageAuthType()`:** `string` — ex.: `'PUBLIC'`, `'PRIVATE'`
```
if (WCMAPI.getPageAuthType() === 'PUBLIC') {
    exibirConteudoPublico();
}
```
### getIsResponsiveLayout() / setIsResponsiveLayout(value)
**Somente leitura** — fornecido automaticamente pela plataforma.
**Descrição:** Indica se o layout da página atual é responsivo (adapta-se a diferentes tamanhos de tela).
**Retorno de `getIsResponsiveLayout()`:** `boolean`
```
if (WCMAPI.getIsResponsiveLayout()) {
    aplicarEstilosResponsivos();
}
```
### getIsNewBuilder() / setIsNewBuilder(value)
**Somente leitura** — fornecido automaticamente pela plataforma.
**Descrição:** Indica se a página foi construída com o editor New Builder da plataforma Fluig. Pode ser usado para ativar funcionalidades exclusivas do New Builder.
**Retorno de `getIsNewBuilder()`:** `boolean`
```
if (WCMAPI.getIsNewBuilder()) {
    habilitarRecursosNewBuilder();
}
```
### getPageIsInternal() / setPageIsInternal(value)
**Somente leitura** — fornecido automaticamente pela plataforma.
**Descrição:** Indica se a página está marcada como interna, ou seja, visível apenas para usuários autenticados. Quando `true`, o acesso anônimo deve ser bloqueado. Padrão `false` quando a variável não está presente no modelo do servidor.
**Retorno de `getPageIsInternal()`:** `boolean`
```
if (WCMAPI.getPageIsInternal() && !WCMAPI.getUserIsLogged()) {
    window.location.href = WCMAPI.getContextPath() + '/login';
}
```
## Usuário Atual
---
### getUserLogin() / setUserLogin(login)
**Descrição:** Retorna ou define o login (identificador único) do usuário autenticado.
**Retorno de `getUserLogin()`:** `string|null` — `null` se o usuário não estiver autenticado.
```
const login = WCMAPI.getUserLogin();
if (login) {
    buscarPerfilUsuario(login);
}
```
### getUserId() / setUserId(id)
**Descrição:** Retorna ou define o identificador numérico do usuário autenticado.
**Retorno de `getUserId()`:** `number|null`
```
const idUsuario = WCMAPI.getUserId();
```
### getUserCode() / setUserCode(code)
**Descrição:** Retorna ou define o código do usuário (equivalente ao login na maioria dos casos).
**Retorno de `getUserCode()`:** `string`
### getUserFirstName() / setUserFirstName(value) / getUserLastName() / setUserLastName(value) / getUser() / setUser(value)
**Descrição:** Retornam ou definem as partes do nome do usuário autenticado.
| | |
| --- | --- |
| Getter | Setter |
| `getUserFirstName()` | `setUserFirstName(value)` |
| `getUserLastName()` | `setUserLastName(value)` |
| `getUser()` | `setUser(value)` |
```
const nomeCompleto = `${WCMAPI.getUserFirstName()} ${WCMAPI.getUserLastName()}`;
$('#saudacao').text(`Olá, ${nomeCompleto}!`);
```
### getUserEmail() / setUserEmail(email)
**Descrição:** Retorna ou define o e-mail do usuário autenticado.
**Retorno de `getUserEmail()`:** `string`
### getUserLocationId() / setUserLocationId(id) / getUserLocationCode() / setUserLocationCode(code) / getUserLocationUrl() / setUserLocationUrl(url)
**Descrição:** Retornam ou definem informações sobre a localização (unidade/empresa) associada ao usuário.
```
const codigoFilial = WCMAPI.getUserLocationCode();
const idFilial     = WCMAPI.getUserLocationId();
```
### getLocale() / setLocale(value) / getLocaleDisplayName() / setLocaleDisplayName(value)
**Descrição:** Retornam ou definem informações sobre o idioma configurado para o usuário.
| | | |
| --- | --- | --- |
| Getter | Setter | Exemplo |
| `getLocale()` | `setLocale(value)` | `'pt_BR'` |
| `getLocaleDisplayName()` | `setLocaleDisplayName(value)` | `'português (Brasil)'` |
```
const locale = WCMAPI.getLocale(); // 'pt_BR'
```
### getTimezone() / setTimezone(value)
**Descrição:** Retorna ou define o identificador de fuso horário IANA configurado para o usuário.
**Retorno de `getTimezone()`:** `string|null` — ex.: `'America/Sao_Paulo'`
```
const tz = WCMAPI.getTimezone(); // 'America/Sao_Paulo'
```
### isAdmin()
**Descrição:** Verifica se o usuário atual possui privilégios de administrador da plataforma Fluig.
**Retorno:** `boolean`
> **Atenção:** Esta operação é **síncrona** e faz uma chamada ao servidor. Evite utilizá-la em loops ou em caminhos críticos de renderização.
```
if (WCMAPI.isAdmin()) {
    $('#painel-admin').show();
}
```
### isIdentityEnabled()
**Descrição:** Indica se a autenticação SAML/SSO está habilitada para o tenant.
**Retorno:** `boolean`
## Contexto do Usuário
---
Essas informações são fornecidas automaticamente pela plataforma no carregamento da página e devem ser tratadas como somente leitura.
> Disponíveis apenas quando `WCMAPI.getUserIsLogged()` retorna `true`.
> Para os métodos completos de acesso aos dados do usuário (login, email, nome etc.), consulte a seção [Usuário Atual](https://tdn.totvs.com/pages/viewpage.action?pageId=1060213081#WCMAPIAtualiza%C3%A7%C3%A3odadocumenta%C3%A7%C3%A3o-usu%C3%A1rio-atual).
### getUserType() / setUserType(value)
**Somente leitura** — fornecido automaticamente pela plataforma.
**Descrição:** Retorna o tipo de conta do usuário autenticado, conforme cadastrado na plataforma.
**Retorno de `getUserType()`:** `string` — ex.: `'interno'`, `'externo'`
```
const tipo = WCMAPI.getUserType();
if (tipo === 'externo') {
    ocultarMenusInternos();
}
```
### getIsMobileAppMode()
**Somente leitura** — fornecido automaticamente pela plataforma.
**Descrição:** Indica se a plataforma está sendo executada dentro de um aplicativo móvel Fluig. O valor é determinado em tempo de renderização pelo servidor e não muda após o carregamento da página.
**Retorno:** `boolean` — `true` se executando dentro do app móvel
```
if (WCMAPI.getIsMobileAppMode()) {
    ocultarFuncionalidadesDesktop();
    ativarInterfaceMobile();
}
```
## Sessão e Autenticação
---
### getUserIsLogged() / setUserIsLogged(value)
**Descrição:** Retorna ou define se o usuário está autenticado na sessão atual. O setter aceita `boolean` ou as strings `'true'`/`'false'` para compatibilidade com valores vindos de templates JSP/FreeMarker.
**Retorno de `getUserIsLogged()`:** `boolean`
```
if (!WCMAPI.getUserIsLogged()) {
    window.location.href = `${WCMAPI.getContextPath()}/login`;
}
```
### getIsStateless() / setIsStateless(value)
**Descrição:** Indica ou define se a plataforma está operando em modo stateless (sem sessão HTTP, apenas JWT). Nesse modo, as verificações de sessão e o ping de keep-alive são desativados automaticamente.
**Retorno de `getIsStateless()`:** `boolean`
```
if (WCMAPI.getIsStateless()) {
    // autenticação baseada apenas em JWT
}
```
### extendSession()
**Descrição:** Reinicia os contadores de expiração da sessão. Deve ser chamado em resposta a interações do usuário para evitar logout por inatividade.
Internamente, agenda:
- Um aviso após **28 minutos** de inatividade
- O logout forçado após **29 minutos** de inatividade
- Não tem efeito no modo stateless ou quando cookies SAML estão presentes.
```
$(document).on('mousemove keydown click', () => {
    WCMAPI.extendSession();
});
```
### login(user, password)
**Descrição:** Autentica o usuário com login e senha. Em caso de sucesso, recarrega a página; em caso de falha, exibe um alerta nativo do navegador.
**Parâmetros:**
- `user` (`string`): login do usuário
- `password` (`string`): senha em texto plano
**Retorno:** `boolean|*` — `true` em caso de sucesso
> A senha é transmitida em texto plano para o `WCMSpaceAPI`. Certifique-se de usar HTTPS.
```
var ok = WCMAPI.login('admin', 'minhasenha');
```
### logoff()
**Descrição:** Encerra a sessão do usuário e redireciona para o endpoint de logout da plataforma. A operação é imediata e irrecuperável — o usuário será redirecionado para a tela de login.
```
$('#btn-sair').on('click', () => WCMAPI.logoff());
```
### hasPermissionToChangePermission(callback)
**Descrição:** Verifica de forma assíncrona se o usuário logado tem o direito de gerenciar permissões na plataforma (recurso `PermissionsAdmin` com ação `execute`).
**Parâmetros:**
- `callback` (`Function`): chamado com `(err, result)` onde `result.content` é `boolean`
**Retorno:** `jqXHR` — o objeto de deferred do jQuery
```
WCMAPI.hasPermissionToChangePermission((err, result) => {
    if (result?.content) {
        $('#btn-gerenciar-permissoes').show();
    }
});
```
## Ambiente
---
Essas informações são fornecidas automaticamente pela plataforma no carregamento da página e devem ser tratadas como somente leitura. Elas refletem a configuração da instância no momento da renderização.
### getVersion() / setVersion(value)
**Somente leitura** — fornecido automaticamente pela plataforma.
**Descrição:** Retorna a versão da plataforma Fluig. Útil para lógica condicional baseada em versão ou para exibição em painéis de diagnóstico.
**Retorno de `getVersion()`:** `string` — ex.: `'1.7.0'`
```
const versao = WCMAPI.getVersion(); // '1.7.0'
```
### getFluigVersion() / setFluigVersion(value) / getFluigInstanceVersionName() / setFluigInstanceVersionName(value) / getFluigVersionBuild() / setFluigVersionBuild(value) / getFluigVersionStatus() / setFluigVersionStatus(value) / getFluigVersionStatusInfo() / setFluigVersionStatusInfo(value)
**Somente leitura** — disponível apenas quando informações detalhadas de versão estiverem configuradas na plataforma.
**Descrição:** Informações detalhadas da versão da instância WCM, mais granulares do que `getVersion()`. Se não estiverem configuradas, os métodos retornam string vazia.
| | | |
| --- | --- | --- |
| Getter | Setter | Exemplo de retorno |
| `getFluigVersion()` | `setFluigVersion(value)` | `'2.0.0-260417'` |
| `getFluigInstanceVersionName()` | `setFluigInstanceVersionName(value)` | `'Voyager'` |
| `getFluigVersionBuild()` | `setFluigVersionBuild(value)` | `'788'` |
| `getFluigVersionStatus()` | `setFluigVersionStatus(value)` | `'0'`, `'1'` |
| `getFluigVersionStatusInfo()` | `setFluigVersionStatusInfo(value)` | texto descritivo |
```
const ver    = WCMAPI.getFluigVersion();       // '2.0.0-260417'
const build  = WCMAPI.getFluigVersionBuild();  // '6727'
const status = WCMAPI.getFluigVersionStatus(); // '0'
```
### getNocodeActive() / setNocodeActive(value)
**Somente leitura** — fornecido automaticamente pela plataforma.
**Descrição:** Indica se o módulo No-Code está ativo para o tenant atual. Quando `true`, funcionalidades de criação de aplicações sem código estão habilitadas. Padrão `false` quando a variável não estiver presente no modelo do servidor.
**Retorno de `getNocodeActive()`:** `boolean`
```
if (WCMAPI.getNocodeActive()) {
    habilitarMenuNoCode();
}
```
### getGoogleAnalyticsEnabled() / setGoogleAnalyticsEnabled(value) / getGoogleAnalyticsAccount() / setGoogleAnalyticsAccount(value)
**Somente leitura** — fornecidos automaticamente pela plataforma.
**Descrição:** Indicam se o Google Analytics está ativo e qual é o ID da conta configurada para o tenant. Use em conjunto para inicializar o rastreamento.
| | | |
| --- | --- | --- |
| Getter | Setter | Retorno |
| `getGoogleAnalyticsEnabled()` | `setGoogleAnalyticsEnabled(value)` | `boolean` |
| `getGoogleAnalyticsAccount()` | `setGoogleAnalyticsAccount(value)` | `string`, ex.: `'UA-XXXXX-Y'` |
```
if (WCMAPI.getGoogleAnalyticsEnabled()) {
    inicializarGoogleAnalytics(WCMAPI.getGoogleAnalyticsAccount());
}
```
## Interface (UI)
---
Essas informações são fornecidas automaticamente pela plataforma no carregamento da página e devem ser tratadas como somente leitura. Refletem a configuração visual do tema ativo e as funcionalidades de edição de texto do tenant.
### getThemeId() / setThemeId(id)
**Somente leitura** — fornecido automaticamente pela plataforma.
**Descrição:** Retorna o identificador numérico do tema aplicado à página atual. Chega como string do FreeMarker; converta com `parseInt()` se necessário.
**Retorno de `getThemeId()`:** `string` (número como string) — ex.: `'3'`
```
const themeId = parseInt(WCMAPI.getThemeId(), 10);
```
### getColorMenu() / setColorMenu(value) / getColorBackground() / setColorBackground(value)
**Somente leitura** — fornecidos automaticamente pela plataforma.
**Descrição:** Retornam as cores definidas pelo tema ativo — a cor do menu de navegação e a cor de fundo da página, respectivamente. Úteis para personalização dinâmica de componentes que precisam combinar com o tema.
| | | |
| --- | --- | --- |
| Getter | Setter | Descrição |
| `getColorMenu()` | `setColorMenu(value)` | Cor do menu de navegação, ex.: `'#003366'` |
| `getColorBackground()` | `setColorBackground(value)` | Cor de fundo da página, ex.: `'#f5f5f5'` |
```
const corMenu = WCMAPI.getColorMenu();
$('.meu-componente-header').css('background-color', corMenu);
```
### getImageBackground() / setImageBackground(value) / getImageLogo() / setImageLogo(value)
**Somente leitura** — fornecidos automaticamente pela plataforma.
**Descrição:** Retornam as URLs das imagens configuradas no tema ativo — imagem de fundo da página e logotipo exibido no cabeçalho. Vazios quando não configurados.
| | | |
| --- | --- | --- |
| Getter | Setter | Descrição |
| `getImageBackground()` | `setImageBackground(value)` | URL da imagem de fundo da página |
| `getImageLogo()` | `setImageLogo(value)` | URL do logotipo do cabeçalho |
```
const logo = WCMAPI.getImageLogo();
if (logo) {
    $('#logo-customizado').attr('src', logo);
}
```
### getIsDisabledRichEditor() / setIsDisabledRichEditor(value)
**Somente leitura** — fornecido automaticamente pela plataforma.
**Descrição:** Indica se o editor de texto rico (rich editor) foi substituído pelo editor simples (simple editor) para o tenant. Quando `true`, o `loadJS` troca automaticamente caminhos contendo `'richeditor'` por `'simpleeditor'`.
**Retorno de `getIsDisabledRichEditor()`:** `boolean`
```
if (WCMAPI.getIsDisabledRichEditor()) {
    inicializarEditorSimples();
} else {
    inicializarEditorRico();
}
```
### getEnableRichEditorSanitizer() / setEnableRichEditorSanitizer(value)
**Somente leitura** — fornecido automaticamente pela plataforma.
**Descrição:** Indica se a sanitização XSS está ativa no editor de texto rico. Quando `true`, o conteúdo gerado pelo usuário passa por sanitização antes de ser salvo, prevenindo a injeção de scripts maliciosos.
**Retorno de `getEnableRichEditorSanitizer()`:** `boolean`
```
if (WCMAPI.getEnableRichEditorSanitizer()) {
    // sanitização XSS já está ativa no editor rico do tenant
    console.log('XSS sanitizer habilitado');
}
```
## Carregamento de Recursos (CSS e JS)
### loadCSS(path)
**Descrição:** Injeta dinamicamente um arquivo CSS no `<head>` da página, evitando duplicatas.
**Quando usar:** sempre que um widget ou componente precisar de um arquivo CSS específico.
**Parâmetros:**
- `path` (`string`): URL ou caminho do arquivo CSS
```
WCMAPI.loadCSS('/wcm/resources/css/meu-widget.css');
```
### loadJS(path, callback)
**Descrição:** Carrega dinamicamente um arquivo JavaScript com cache habilitado, evitando carregamentos duplicados.
**Quando usar:** sempre que um widget precisar de um script externo. Prefira sempre `WCMAPI.loadJS()` em vez de `$.getScript()` dentro da plataforma — o WCMAPI garante controle de duplicatas e cache correto.
**Parâmetros:**
- `path` (`string`): URL ou caminho do arquivo JavaScript
- `callback` (`Function`, opcional): executado após o carregamento
```
WCMAPI.loadJS('/my_custom_path/resources/js/meu-script.js', () => {
   // faça algo
});
```
### jsBasePath()
**Descrição:** Retorna o diretório base da última tag `<script>` adicionada à página no momento da chamada. Útil para resolver caminhos relativos dentro de scripts inline de widgets que não possuem acesso a um sistema de módulos.
**Retorno:** `string`
```
const base = WCMAPI.jsBasePath();
WCMAPI.loadJS(`${base}/helpers.js`);
```
## Renderização de Templates FTL
---
### convertFtlAsync(appCode, fileNameFtl, pars, callback, errorCallback)
**Descrição:** Renderiza um template FreeMarker (`.ftl`) de um aplicativo Fluig de forma **assíncrona** (não bloqueante) e entrega o HTML resultante por meio de um callback.
CSS e JS declarados pelo template são carregados automaticamente após a resposta.
**Parâmetros:**
- `appCode` (`string`): código do aplicativo Fluig, ex.: `'wcm_meupainel'`
- `fileNameFtl` (`string`): nome do arquivo FTL, ex.: `'view.ftl'`
- `pars` (`Object|string`): parâmetros passados ao template (serializado automaticamente se for objeto)
- `callback` (`Function`): chamado com o HTML renderizado — `callback(html)`
- `errorCallback` (`Function`, opcional): chamado em caso de erro — `errorCallback(err)`
```
WCMAPI.convertFtlAsync(
    'meuApp',
    'view.ftl',
    { usuarioId: WCMAPI.getUserId(), filtro: 'ativo' },
    (html) => {
        $('#meu-container').html(html);
        WCMAPI.loadWidgets();
    },
    (erro) => {
        console.error('Falha ao renderizar o template', erro);
    }
);
```
> ✅ **Prefira este método** ao `convertFtl()` em qualquer situação onde o bloqueio da thread do navegador seja indesejável.
### convertFtl(appCode, fileNameFtl, pars, component, callback)
**Descrição:** Renderiza um template FTL de forma **síncrona** (bloqueante) e injeta o HTML resultante em um elemento da página. Também carrega os recursos CSS e JS declarados pelo template.
**Parâmetros:**
- `appCode` (`string`): código do aplicativo Fluig
- `fileNameFtl` (`string`): nome do arquivo FTL
- `pars` (`Object|string`): parâmetros para o template
- `component` (`string|jQuery`): ID do elemento ou objeto jQuery onde o HTML será injetado. Passe `undefined` para receber o HTML como string de retorno
- `callback` (`Function`, opcional): executado após todos os recursos JS serem carregados
**Retorno:** `string` — HTML renderizado quando `component` é `undefined`; caso contrário, `""`
```
WCMAPI.convertFtl('meuApp', 'edit.ftl', { id: 10 }, 'div-edicao', () => {
    console.log('Widget em modo de edição pronto');
});
const html = WCMAPI.convertFtl('meuApp', 'partial.ftl', { id: 10 });
$('#lista').append(html);
```
> **Atenção:** Esta versão bloqueia o navegador durante o round-trip ao servidor. Use `convertFtlAsync()` sempre que possível.
### extractHtmlContentAndResources(html, appCode) *(interno)*
**Descrição:** Método interno utilizado por `convertFtl` e `convertFtlAsync` para separar o HTML renderizado em nós de conteúdo DOM e descritores de recursos (CSS/JS). Não deve ser chamado diretamente por widgets.
## Ciclo de Vida de Widgets
---
### loadWidgets()
**Descrição:** Inicializa os widgets presentes na página. Chamado automaticamente pela plataforma no carregamento da página e ao final de `convertFtl` / `convertFtlAsync`.
**Quando usar:** sempre que widgets forem carregados dinamicamente — por exemplo, após injetar HTML via `convertFtlAsync`, `convertFtl` ou uma requisição AJAX.
```
$.get('/minha-api/widget-html', (html) => {
    $('#container').html(html);
    WCMAPI.loadWidgets();
});
```
### openEditMode(instId, slot) / openViewMode(instId, slot)
**Descrição:** Re-renderizam sincronamente uma instância de widget em modo de edição ou visualização, substituindo o nó DOM atual.
**Parâmetros:**
- `instId` (`number`): ID numérico da instância do widget
- `slot` (`string`): ID do elemento slot container
```
// Abrir o widget de ID 42 em modo de edição
WCMAPI.openEditMode(42, 'slot-principal');
```
### editContent(control, instanceId)
**Descrição:** Re-renderiza um widget em modo de edição quando acionado pelo ícone de engrenagem no modo de visualização. Diferente de `openEditMode()`, este método também carrega os recursos CSS e JS declarados pelo template de edição antes de injetar o HTML.
**Parâmetros:**
- `control` (`Element|string`): elemento DOM clicado, usado para localizar o slot pai
- `instanceId` (`number`): ID numérico da instância
### updateWidgetPreferences(instanceId, prefs)
**Descrição:** Salva as preferências de um widget para **todos os usuários** e re-renderiza o widget em modo de edição imediatamente, para que o usuário veja o resultado da configuração.
**Parâmetros:**
- `instanceId` (`number`): ID numérico da instância do widget
- `prefs` (`Object`): pares chave/valor das preferências a salvar
**Retorno:** `boolean` — `true` em caso de sucesso, `false` em caso de falha
```
const salvo = WCMAPI.updateWidgetPreferences(12, {
    cor: '#003366',
    exibirCabecalho: true,
    quantidadeItens: 5
});
if (!salvo) {
    alert('Erro ao salvar as configurações. Tente novamente.');
}
```
### updateUserWidgetPreferences(instanceId, prefs)
**Descrição:** Idêntico a `updateWidgetPreferences()`, porém as preferências são salvas **apenas para o usuário logado**, permitindo personalização individual.
**Parâmetros:**
- `instanceId` (`number`): ID numérico da instância
- `prefs` (`Object`): pares chave/valor das preferências
**Retorno:** `boolean`
```
// Salvar preferência de idioma apenas para este usuário
WCMAPI.updateUserWidgetPreferences(12, { idioma: 'en_US' });
```
## Sistema de Eventos
---
O `WCMAPI` oferece um barramento de eventos pub/sub para comunicação desacoplada entre widgets e temas. Os nomes dos eventos padrão (como `WCMAPI.LISTENER_LOGIN`) são constantes injetadas pela plataforma.
### Eventos disponíveis
| | |
| --- | --- |
| Constante | Quando dispara |
| `WCMAPI.LISTENER_LOGIN` | Quando o usuário efetua login |
| `WCMAPI.LISTENER_LOGOUT` | Quando o usuário efetua logout |
| `WCMAPI.LISTENER_EDITMODEON` | Quando o modo de edição é ativado |
| `WCMAPI.LISTENER_EDITMODEOFF` | Quando o modo de edição é desativado |
| `WCMAPI.LISTENER_SAVEWIDGETPREFS_OPEN` | Quando o painel de preferências de widget é aberto |
| `WCMAPI.LISTENER_SAVEWIDGETPREFS_CLOSE` | Quando o painel de preferências de widget é fechado |
| `WCMAPI.LISTENER_BEFORE_SAVEWIDGETPREFS` | Antes de salvar as preferências de widget |
| `WCMAPI.LISTENER_AFTER_SAVEWIDGETPREFS` | Após salvar as preferências de widget |
### addListener(oObj, eventName, callback, listenerName)
**Descrição:** Registra uma função de callback para ser chamada quando o evento indicado for disparado. Se um listener com o mesmo `listenerName` já estiver registrado para o mesmo evento, ele será atualizado em vez de duplicado.
**Parâmetros:**
- `oObj` (`Object`): contexto (`this`) para o callback
- `eventName` (`string`): nome do evento (ex.: `WCMAPI.LISTENER_LOGIN`)
- `callback` (`Function`): função chamada com `(eventName, data)`
- `listenerName` (`string`, opcional): nome único do listener, padrão `'DEFAULT'`
**Retorno:** `boolean` — sempre `true`
```
WCMAPI.addListener(
    this,
    WCMAPI.LISTENER_EDITMODEON,
    (eventName, data) => meuWidget.mostrarControlesDeEdicao(),
    'meuWidget-editmode'
);
```
### removeListener(eventName, listenerName)
**Descrição:** Remove um listener registrado pelo nome.
**Parâmetros:**
- `eventName` (`string`): nome do evento
- `listenerName` (`string`, opcional): nome do listener a remover, padrão `'DEFAULT'`
```
// Remover o listener ao destruir o widget
WCMAPI.removeListener(WCMAPI.LISTENER_EDITMODEON, 'meuWidget-editmode');
```
### fireEvent(eventName, data)
**Descrição:** Dispara todos os listeners registrados para o evento informado. Erros dentro de callbacks individuais são silenciados para não impedir a notificação dos demais listeners.
**Parâmetros:**
- `eventName` (`string`): nome do evento a disparar
- `data` (`*`, opcional): payload enviado para todos os listeners
```
WCMAPI.fireEvent('DOCUMENTO_SELECIONADO', { id: 99, titulo: 'Contrato 2024' });
WCMAPI.addListener(this, 'DOCUMENTO_SELECIONADO', (evt, data) => {
    console.log('Documento selecionado:', data.titulo);
}, 'visualizador-docs');
```
### containsListener(eventName, listener, varIdx)
**Descrição:** Verifica se um listener com o nome informado já está registrado para um evento. Método interno, raramente necessário em widgets.
**Retorno:** `boolean`
## Requisições AJAX
---
O `WCMAPI` oferece métodos CRUD padronizados que já aplicam as configurações padrão da plataforma (JSON content-type, tratamento de erros, serialização automática).
> **JWT Automático:** Todas as requisições jQuery feitas na plataforma recebem automaticamente o header `Authorization: Bearer <token>` via `$.ajaxSetup()`, desde que o cookie `jwt.token` esteja presente.
### Create(options) / Read(options) / Update(options) / Delete(options)
**Importante:** Os métodos WCMAPI.Create(), WCMAPI.Read(), WCMAPI.Update() e Delete(options) estão depreciados. Use FLUIGC.ajax() ou $.ajax() que fornece uma API mais robusta e moderna.
**Descrição:** Wrappers padronizados para chamadas AJAX com os verbos HTTP correspondentes (`POST`, `GET`, `PUT`, `DELETE`). Qualquer `options.data` que seja objeto ou array é automaticamente serializado para JSON antes do envio.
**Parâmetros:**
- `options` (`Object`): configuração jQuery.ajax. `url` é obrigatório.
- `options.data`: payload da requisição (auto-serializado se for objeto)
- `options.success`: callback de sucesso com a resposta parseada
```
WCMAPI.Create({
    url: '/api/public/2.0/posts',
    data: { titulo: 'Meu Post', conteudo: 'Texto aqui' },
    success: (resposta) => {
        console.log('Post criado com ID:', resposta.content.id);
    }
});
WCMAPI.Read({
    url: `/api/public/2.0/documents/${documentoId}`,
    success: (resposta) => {
        exibirDocumento(resposta.content);
    }
});
WCMAPI.Update({
    url: `/api/public/2.0/documents/${documentoId}`,
    data: { titulo: 'Título Atualizado' },
    success: () => mostrarMensagemSucesso()
});
WCMAPI.Delete({
    url: `/api/public/2.0/documents/${documentoId}`,
    success: () => removerDaLista(documentoId)
});
```
### callCommand(command, data, oObj, callback, errorCallback, dataType)
**Descrição:** Realiza uma requisição GET simples, prefixando o `command` com o valor retornado por `WCMAPI.getServerURL()`. O errorCallback é opcional; se omitido, erros são ignorados silenciosamente.
**Parâmetros:**
- `command` (`string`): caminho da URL (anexado ao valor de `getServerURL()`)
- `data` (`*`): dado repassado ao callback de sucesso e erro
- `oObj` (`Object`): contexto (`this`) para os callbacks
- `callback` (`Function`): `callback(response, data)`
- `errorCallback` (`Function`, opcional): `errorCallback(xhr, textStatus, errorThrown, data)`
- `dataType` (`string`, opcional): tipo de dado esperado, padrão `'json'`
```
WCMAPI.callCommand(
    '/wcm/api/rest/wcm/usuario/atual',
    null,
    this,
    (response) => console.log('Usuário:', response)
);
```
### readHtml(options)
**Descrição:** Atalho para fazer uma requisição AJAX com as configurações padrão da plataforma, mescladas com as opções fornecidas.
```
WCMAPI.readHtml({
    url: '/wcm/api/rest/wcm/minha-rota',
    dataType: 'html',
    success: (html) => $('#container').html(html)
});
```
### syncAjax(url)
**Descrição:** Realiza uma requisição GET síncrona (bloqueante) e retorna o texto da resposta.
**Parâmetros:**
- `url` (`string`): URL da requisição
**Retorno:** `string|false` — texto da resposta, ou `false` se o objeto XHR não puder ser criado
> Use com extrema moderação
>
> Requisições síncronas bloqueiam completamente a thread do navegador e estão obsoletas nos padrões modernos. Este método é usado internamente apenas nos pings de keep-alive de sessão.
### failHandler(args, styleGuide) *(usado internamente)*
**Descrição:** Tratador centralizado de erros AJAX, chamado automaticamente pelo objeto padrão retornado por `ajaxRequestDefault()`. Inspeciona o Content-Type e o status HTTP da resposta para exibir a mensagem de erro correta.
- Quando `styleGuide = true`: usa componentes FLUIGC (modais e mensagens)
- Quando `styleGuide = false`: usa os componentes legados WCMC
- Raramente você precisará chamar este método diretamente.
```
$.ajax({
    url: '/minha-api',
    error: (xhr) => WCMAPI.failHandler(xhr, true)
});
```
## OAuth
---
### validateAndAuthenticateOAuth(consumerKey)
**Descrição:** Valida o token OAuth para uma chave de consumer e, caso o token esteja ausente ou inválido, inicia o fluxo de autorização abrindo a URL do provedor em uma nova aba.
Use este método antes de fazer chamadas a APIs de terceiros integradas via OAuth (ex: Google Drive, Dropbox).
**Parâmetros:**
- `consumerKey` (`string`): chave do consumer OAuth da integração
**Retorno:** `boolean` — `true` se o token é válido; `false` se o fluxo de autorização foi iniciado
```
// Verificar e autenticar antes de usar o Google Drive
if (WCMAPI.validateAndAuthenticateOAuth('google-drive')) {
    carregarArquivosGoogleDrive();
} else {
    // O usuário será redirecionado para autorizar o acesso
    mostrarMensagem('Autorizando acesso ao Google Drive...');
}
```
### validateOAuth(consumerKey)
**Descrição:** Verifica a validade do token OAuth **sem iniciar o fluxo de autorização**. Use quando você precisa apenas verificar o status para, por exemplo, exibir um botão "Conectar".
**Parâmetros:**
- `consumerKey` (`string`): chave do consumer OAuth
**Retorno:** `boolean` — `true` se o token é válido
```
if (!WCMAPI.validateOAuth('minha-integracao')) {
    $('#btn-conectar').show();
} else {
    $('#btn-conectar').hide();
    carregarDadosDaIntegracao();
}
```
## Atributos de Sessão no Servidor
---
### setSessionAttribute(name, value) / getSessionAttribute(name)
**Descrição:** Armazena e recupera atributos na sessão HTTP do servidor via chamadas síncronas ao `WCMSpaceAPI.SessionService`.
**Parâmetros:**
- `name` (`string`): chave do atributo de sessão
- `value` (`*`): valor a armazenar (somente para `setSessionAttribute`)
```
// Salvar o ID do último documento visualizado
WCMAPI.setSessionAttribute('ultimo-documento', 42);
// Recuperar o valor posteriormente (em outra página/widget)
var ultimoDoc = WCMAPI.getSessionAttribute('ultimo-documento');
if (ultimoDoc) {
    reabrirDocumento(ultimoDoc);
}
```
> **Atenção:** Não funciona em modo stateless (`WCMAPI.getIsStateless() === true`).
## Utilitários JavaScript
---
### Verificação de tipos
**Legado.** Prefira os recursos nativos do JavaScript moderno: `typeof`, `Array.isArray()`, `=== null`, `=== undefined`, etc. Evite utilizar estes métodos em novos desenvolvimentos.
| | | |
| --- | --- | --- |
| Método | Equivalente nativo | Retorno |
| `isUndefined(o)` | `o === undefined` | `boolean` |
| `isNull(o)` | `o === null` | `boolean` |
| `isString(o)` | `typeof o === 'string'` | `boolean` |
| `isNumber(o)` | `typeof o === 'number'` | `boolean` |
| `isArray(obj)` | `Array.isArray(obj)` | `boolean` |
| `isObject(o)` | — | `boolean` |
| `isJSON(o)` | — | `boolean` |
| `isEmpty(o)` | — | `boolean` |
```
// Antes de serializar dados para envio ao servidor:
const payload = obterDados();
if (WCMAPI.isObject(payload)) {
    WCMAPI.Create({ url: '/api/salvar', data: payload, success: cb });
} else {
    console.error('Dados inválidos:', payload);
}
```
### cloneObject(source)
**Descrição:** Cria uma cópia profunda (deep clone) de um objeto ou array simples. Não copia propriedades chamadas `'clone'` para evitar referências circulares.
**Limitação:** Não clona corretamente `Date`, `RegExp`, `Map`, `Set` ou outras classes built-in complexas — esses são copiados por referência.
**Parâmetros:**
- `source` (`Object|Array`): objeto ou array a clonar
**Retorno:** `Object|Array`
```
const configuracaoOriginal = { cor: 'azul', icone: { nome: 'star', tamanho: 16 } };
const copia = WCMAPI.cloneObject(configuracaoOriginal);
copia.icone.tamanho = 32;
console.log(configuracaoOriginal.icone.tamanho); // 16 — intocado
```
### replaceAll(str, de, para)
**Descrição:** Substitui todas as ocorrências de uma substring por outra. Alternativa a `String.prototype.replaceAll()` para compatibilidade com ambientes legados. Usa abordagem iterativa em vez de regex global, evitando problemas com caracteres especiais.
```
var resultado = WCMAPI.replaceAll('a.b.c.d', '.', '/');
// 'a/b/c/d'
```
### stringify(o)
**Descrição:** Serializa para JSON e então aplica `encodeURI()`. Útil para passar objetos complexos como parâmetros de URL.
```
const dados = { filtro: 'ativo', pagina: 1 };
const url = `/minha-api?params=${WCMAPI.stringify(dados)}`;
```
### validateXSS(data, replace)
**Descrição:** Sanitiza um valor de string ou campo de formulário contra ataques XSS usando o utilitário `FLUIGC.utilities.preventXSS`.
Suporta dois modos:
- **String:** recebe e retorna uma string sanitizada
- **Elemento de formulário:** recebe um elemento DOM ou jQuery com `.value`, atualiza o valor no lugar e retorna o objeto jQuery
- O parâmetro `replace` quando `true` também remove as entidades `>` e `<` do resultado sanitizado.
```
// Modo string — sanitizar dados antes de exibir
var textoSeguro = WCMAPI.validateXSS(comentarioDoUsuario, false);
$('#area-comentario').text(textoSeguro);
// Modo input — sanitizar o campo diretamente ao perder o foco
$('#campo-titulo').on('blur', function() {
    WCMAPI.validateXSS(this, false);
});
```
### emailIsValid(email)
**Descrição:** Valida se uma string é um endereço de e-mail sintaticamente válido. Não verifica a existência do domínio.
**Retorno:** `boolean`
```
const email = $('#campo-email').val();
if (!WCMAPI.emailIsValid(email)) {
    mostrarErro('Informe um e-mail válido.');
    return;
}
```
### formatDateUtc(date)
**Descrição:** Formata uma data como string localizada usando a meia-noite UTC para evitar que o deslocamento de fuso horário do cliente altere o dia exibido.
**Parâmetros:**
- `date` (`string|number|Date`): valor de data aceito por `new Date()`
**Retorno:** `string` — data formatada conforme o locale do navegador
```
// Em pt-BR: '15/06/2024'
var dataFormatada = WCMAPI.formatDateUtc('2024-06-15T00:00:00Z');
$('#data-publicacao').text(dataFormatada);
```
### generateId()
**Descrição:** Gera uma string de identificador DOM único e incremental no formato `'wcmid<n>'`. Útil ao criar elementos dinamicamente que precisam de um atributo `id` garantidamente único na página.
**Retorno:** `string` — ex.: `'wcmid2'`, `'wcmid3'`, ...
```
const id = WCMAPI.generateId();
const $div = $('<div>').attr('id', id).addClass('meu-componente');
$('body').append($div);
WCMAPI.loadJS('/meuapp/componente.js', () => {
    new MeuComponente({ target: `#${id}` });
});
```
### getZIndex()
**Descrição:** Retorna o maior valor de `z-index` em uso por elementos absolutamente ou fixamente posicionados na página. Útil ao criar modais ou overlays que precisam aparecer acima de todo o conteúdo existente.
**Retorno:** `number` — mínimo `1`
```
const $meuModal = $('#meu-modal');
$meuModal.css('z-index', WCMAPI.getZIndex() + 10);
$meuModal.show();
```
### getSourceImage(imageSource, options, callback)
**Descrição:** Carrega uma imagem e corrige sua orientação com base nos metadados EXIF, entregando uma URL de dados (Base64) ao callback quando necessário. Se a imagem não tiver dados EXIF de orientação, a URL original é retornada sem processamento.
Requer a biblioteca `blueimp-load-image` carregada na página.
**Parâmetros:**
- `imageSource` (`string`): URL ou data URL da imagem
- `options` (`Object`): opções para `loadImage()`, ex.: {{
Unknown macro: { maxWidth}}}
- `callback` (`Function`): `callback(src)` onde `src` é a URL original ou o Base64 corrigido
```
WCMAPI.getSourceImage('/uploads/foto.jpg', { maxWidth: 400 }, function(src) {
    $('img.foto-perfil').attr('src', src);
});
```
## Utilitários de URL
---
### \_get(name)
**Descrição:** Extrai o valor de um parâmetro de query string da URL da página atual. Retorna `null` quando o parâmetro não está presente.
```
// URL: https://exemplo.com/pagina?filtro=ativo&pagina=2
var filtro = WCMAPI._get('filtro');  // 'ativo'
var pagina  = WCMAPI._get('pagina'); // '2'
var outro   = WCMAPI._get('outro');  // null
```
### \_getParam(url, name)
**Descrição:** Extrai o valor de um parâmetro de query string de uma URL específica (não da URL atual). Usado internamente para verificar parâmetros de versão antes de adicioná-los.
```
var versao = WCMAPI._getParam('/recursos/script.js?v=1.7.1', 'v');
// '1.7.1'
```
### \_getAllParams(url)
**Descrição:** Extrai todos os parâmetros de uma URL e os retorna como objeto.
**Retorno:** `Object.<string, string>`
```
var params = WCMAPI._getAllParams('https://exemplo.com/p?a=1&b=hello');
// { a: '1', b: 'hello' }
```
### getURLParameter(name) *(função global)*
**Descrição:** Extrai o valor de um parâmetro da URL atual. Diferente de `WCMAPI._get()`, esta é uma **função global** (não método do WCMAPI).
> **Atenção:** Quando o parâmetro não existe, esta função retorna a **string** `'null'` (e não `null`). Prefira `WCMAPI._get()` em novo código para evitar comparações indevidas.
```
var modoEdicao = getURLParameter('edit');
// Se o parâmetro não existir: modoEdicao === 'null' (string!)
// Forma segura com WCMAPI._get():
var modoEdicao = WCMAPI._get('edit'); // null (tipo correto)
```
## Configurações Globais jQuery
---
### $.cachedScript(url, options)
**Descrição:** Extensão do jQuery que carrega um script com cache habilitado no navegador. Diferente do `$.getScript()` padrão (que desabilita o cache), este helper é essencial para performance em uma plataforma onde os mesmos scripts de widget podem ser solicitados em cada carregamento de página.
```
$.cachedScript('/wcm/recursos/js/minha-lib.js').done(function() {
    // biblioteca disponível — instanciar componente
    new MinhaLib({ target: '#app' });
});
```
## Namespace WCM
---
O objeto global `WCM` é um namespace legado mantido por compatibilidade retroativa. Ele expõe URLs de conveniência derivadas do contexto atual do `WCMAPI`.
```
// WCM.contextUrl — ex.: '/portal/wcm'
// WCM.restUrl    — ex.: '/wcm/api/rest/wcm/'
$.get(WCM.restUrl + 'meu-endpoint', function(data) {
    // ...
});
```
## Boas Práticas
---
### Use sempre getters e setters — nunca acesse propriedades diretamente
Todas as propriedades do `WCMAPI` devem ser acessadas e modificadas exclusivamente pelos métodos `get...()` e `set...()` correspondentes. O acesso direto às propriedades (ex.: `WCMAPI.userId`) é considerado **legado**, não está documentado como API pública e pode ser removido em versões futuras.
```
// ❌ Incorreto — acesso direto à propriedade (legado)
var id    = WCMAPI.userId;
var login = WCMAPI.userLogin;
var tenant = WCMAPI.tenantCode;
// ✅ Correto — use sempre os métodos getter
var id    = WCMAPI.getUserId();
var login = WCMAPI.getUserLogin();
var tenant = WCMAPI.getTenantCode();
// ✅ Correto — para modificar, use o setter
WCMAPI.setPageTitle('Minha Página Customizada');
```
### Use sempre o singleton `WCMAPI`
Nunca instancie `TLib` diretamente. O objeto `WCMAPI` é criado pela plataforma com uma guarda contra instanciação dupla.
```
// ✅ Correto
var login = WCMAPI.getUserLogin();
// ❌ Incorreto
var api = new TLib();
```
### Prefira `convertFtlAsync` ao `convertFtl`
A versão assíncrona não bloqueia a interface enquanto aguarda a resposta do servidor.
```
// ✅ Correto — não bloqueia o navegador
WCMAPI.convertFtlAsync('meuApp', 'view.ftl', params, function(html) {
    $('#container').html(html);
    WCMAPI.loadWidgets();
});
// Usar com cautela — bloqueia o navegador
var html = WCMAPI.convertFtl('meuApp', 'view.ftl', params);
```
### Sempre chame `loadWidgets()` após injetar HTML
Qualquer HTML que contenha elementos com a classe `wcm-widget-class` precisa que `loadWidgets()` seja chamado após a injeção para que os widgets sejam inicializados.
```
$('#container').html(htmlRenderizado);
WCMAPI.loadWidgets(); // não esqueça!
```
### Use nomes únicos para seus listeners de eventos
O sistema de eventos atualiza um listener existente quando o nome já está registrado. Nomes descritivos e únicos por widget evitam conflitos silenciosos.
```
// ✅ Nome específico para este widget
WCMAPI.addListener(this, WCMAPI.LISTENER_EDITMODEON, handler, 'widgetCalendario-editmode');
// ❌ Nome genérico pode conflitar com outros widgets
WCMAPI.addListener(this, WCMAPI.LISTENER_EDITMODEON, handler, 'meu-listener');
```
### Remova listeners ao destruir widgets
Para evitar memory leaks e comportamentos indesejados, remova os listeners ao destruir ou esconder um widget.
```
destroyWidget() {
    WCMAPI.removeListener(WCMAPI.LISTENER_EDITMODEON, 'widgetCalendario-editmode');
    WCMAPI.removeListener(WCMAPI.LISTENER_LOGOUT, 'widgetCalendario-logout');
    // limpeza do DOM...
};
```
### Verifique o login antes de operações sensíveis
```
if (!WCMAPI.getUserIsLogged()) {
    return;
}
const login = WCMAPI.getUserLogin();
```
### Sanitize inputs do usuário com `validateXSS`
Antes de inserir qualquer conteúdo gerado pelo usuário no DOM, sanitize-o:
```
var conteudo = WCMAPI.validateXSS($('#campo-descricao').val(), false);
$('#area-preview').html(conteudo);
```
## Erros Comuns
---
### "WCMAPI is not defined"
**Causa:** O script do widget está sendo executado antes do `wcmapi.js` ser carregado.
**Solução:** Verifique a ordem de carregamento dos recursos no template do widget ou tema. O `wcmapi.js` deve aparecer antes dos scripts dos widgets.
### Listener disparando múltiplas vezes
**Causa:** `addListener` está sendo chamado mais de uma vez com o nome `'DEFAULT'` (padrão quando `listenerName` não é informado), e cada chamada atualiza o listener existente — mas se diferentes widgets usam o mesmo nome, os callbacks podem se acumular.
**Solução:** Sempre informe um `listenerName` único e específico para seu widget.
### `getURLParameter` retornando `'null'` em vez de `null`
**Causa:** Esta função global retorna a string `'null'` quando o parâmetro não existe.
**Solução:** Use `WCMAPI._get()` que retorna o tipo nulo correto.
```
// ❌ Armadilha
if (getURLParameter('modo') == null) { /* nunca entra aqui */ }
// ✅ Correto
if (WCMAPI._get('modo') === null) { /* funciona */ }
```
### Widget não inicializa após injeção de HTML
**Causa:** `loadWidgets()` não foi chamado após a injeção do HTML.
**Solução:**
```
$('#container').html(htmlRenderizado);
WCMAPI.loadWidgets(); // essencial
```
### Sessão expirando mesmo com o usuário ativo
**Causa:** `extendSession()` não está sendo chamado em resposta às interações do usuário, ou o interceptor foi removido.
**Solução:** Vincule `extendSession()` aos eventos de interação de forma global no tema:
```
let timerSessao;
$(document).on('mousemove keydown click', () => {
    clearTimeout(timerSessao);
    timerSessao = setTimeout(() => WCMAPI.extendSession(), 500);
});
```
### Requisições AJAX falhando com 401 em modo stateless
**Causa:** O cookie `jwt.token` não está presente ou está expirado. O `$.ajaxSetup` global injeta o token automaticamente, mas ele precisa existir.
**Solução:** Verifique se o fluxo de autenticação está renovando o JWT corretamente. Em modo stateless (`WCMAPI.getIsStateless() === true`), toda autenticação depende do token JWT.
## Dicas de Performance
---
### Evite `isAdmin()` em loops ou na inicialização
`isAdmin()` faz uma chamada síncrona ao servidor. Guarde o resultado em cache:
```
const userAdmin = WCMAPI.isAdmin();
minhaLista.forEach((item) => {
    if (ehAdmin) {
        exibirBotaoExcluir(item);
    }
});
```
### Prefira `convertFtlAsync` para templates pesados
Templates que carregam muitos dados ou recursos devem usar a versão assíncrona para não travar a interface enquanto o servidor processa.
### Use `WCMAPI.loadJS` para scripts de widgets, nunca `$.getScript`
`$.getScript` desabilita o cache do navegador. `WCMAPI.loadJS` usa `$.cachedScript` internamente, permitindo que o navegador faça cache dos scripts entre carregamentos de página.
### Use `WCMAPI._getParam` para verificar parâmetros de versão em URLs
Ao montar URLs para recursos externos, verifique se já existe um parâmetro `v` antes de adicionar:
```
const urlRecurso = '/meu-recurso/arquivo.js';
if (!WCMAPI._getParam(urlRecurso, 'v')) {
    urlRecurso += `?v=${WCMAPI.getVersion()}`;
}
```
### Nomeie e remova listeners para evitar memory leaks
Em widgets com ciclo de vida bem definido (criação e destruição), sempre remova os listeners ao destruir o widget para liberar memória.
### Integração com outras APIs do Fluig
O `WCMAPI` é a **porta de entrada** — use-o para obter o contexto e, a partir dele, construa chamadas para:
- **REST API pública:** `/api/public/2.0/...` — use `WCMAPI.Read()` / `WCMAPI.Create()` etc.
- **WCMSpaceAPI:** API síncrona de baixo nível (use com cautela)
- **FLUIGC:** componentes visuais do guia de estilo Fluig
- **WCMSpaceAPI.OAuthService:** para integrações OAuth, utilize os helpers `validateOAuth` e `validateAndAuthenticateOAuth` do próprio `WCMAPI`