xMova - JS

O projeto xMovaJS é um framework para criar aplicativos móveis usando JSON e JavaScript.

API

Modelo de Dados

O xMova interpreta o modelo de dados para criar as telas do fluxo. No modelo define-se todas as entidades e seus campos. Em cada entidade e campo pode-se definir atributos e eventos.

Formato

O modelo é definido da seguinte forma:

Model JS:

{
      app:{
      id:7885,
              name:'Nome do Aplicativo',
              version:'1.0.53',
              intVersion:37,
              appCode:'L',
              dynamicQuery:1,
              serverUrl:'http://xmova-server-dev.simova.ws/serverjs/m',
              thirdServerUrl:'http://url.do.app/',
              screens:{
                      Main:{
                              type:'main', fields:['descricaoFilial'],
                              actions: {
                                      Entidade1:      {type:'Main', position:'Menu'},
                                      Sincronizar:    {event:'sync()'},
                                      Limpar:         {event:'dropDbAndExit()'},
                                      Sair:           {type:'Back', position:'Menu', event:'exit()'}
                              }
                      }
              }
      },
      entities:{
              Auth:{
                      fields:{
                              idFilial:               {fk:'Filial'}
                      }
              },
              AuthInput:{
                      fields:{
                              id:{},
                              idFilial:               {fk:'Filial'},
                              descricaoFilial:        {type:'text', autoFill:'this.idFilial.descricao'}
                      }
              },
              Teste:{
                      fields:{
                              id:                     {},
                              campo1:                 {}
                      }
              },
              Filial:{
                      label:'Filial',
                      fields:{
                              id:                     {},
                              descricao:              {type:'text'}
                      }
              }
      },
      lang:{
              AuthInput:'Configuração',
              AuthInput_descricaoFilial:'Filial'
      }
}

Tipo de Sincronismo da Entidade

Em cada entidade pode-se definir o tipo de sincronismo. Quando o app faz um sync com o servidor cada entidade será analisada para verificar se os dados dela serão enviados ou recebidos do servidor, ou se a entidade será ignorada no sync.

sync:'in': O servidor retornará os dados desta entidade em todos os sync Foreground.

sync:'out': Em todos os Sync, Foreground ou Background, os dados dessa tabela serão enviados ao servidor.

sync:['in', 'install']: O servidor retornará os dados desta entidade apenas no primeiro sync ANTES da instalação do app. Serve para fluxos em que seja necessário exibir lista de opções durante o processo de configuração inicial do fluxo.

EVENTOS

Eventos Principais

Model JS:

Sincronizar sync():

{event:'sync()'}

Sair exit():

{event:'exit()', type:'Back'}

Limpar dropDbAndExit():

{event:'dropDbAndExit()'}

Eventos de Entidade

afterFinish: Evento chamado após finalizar o preenchimento de uma entidade. Quando o evento terminar, o fluxo precisa chamar crud.afterFinish()

App JS:

Nome_da_Entidade.afterFinish: crud
      ... ...
      crud.afterFinish();

afterSave: Evento chamado após finalizar o preenchimento de uma entidade.

beforeSave: Evento chamado antes de salvar um registro da entidade.

onOpenMenu: Evento chamado ao abrir um menu. Quando o evento terminar, o fluxo precisa chamar crud.showMenu().

App JS:

Nome_da_Entidade.onOpenMenu_: crud
      ... ...
      crud.showMenu();

onShowInfo: Evento usado para alterar a barra de info na entidade e em seus campos, conforme eles são exibidos. Caso seja passado null para o afterOnShowInfo, a barra não é exibida.

App JS:

Nome_da_Entidade.onShowInfo_: mgrs
      ... ...
      mgrs.afterOnShowInfo('Texto informativo');

Eventos de Campo

Note que quando os eventos são em background (simbolizados por terem um underline no fim do nome do evento), o retorno deve ser feito através de mgr.resume(‘valor’);

autoFill: Preenchimento automático do campo com o valor retornado. Se tiver autoFill, pula a fase Fill.

App JS:

Nome_da_Entidade.nome_do_campo.autoFill: mgr, crud
      return 1000;

Nome_da_Entidade.nome_do_campo2.autoFill_: mgr, crud
      mgr.resume(1000);

condition: Condição de preenchimento do campo. Se a condição retornar “false”, passa ao proximo campo. Se não for um método com callback, o retorno padrao é “true”, e o campo deve ser preenchido.

App JS:

Nome_da_Entidade.nome_do_campo.condition: mgr, crud
      if (*condição de preenchimento*) {
              return true;
      } else {
              return false;
      }

Nome_da_Entidade.nome_do_campo.condition_: mgr, crud
      if (*condição de preenchimento*) {
              mgr.resume(true);
      } else {
              mgr.resume(false);
      }

defaultValue: Pré-preenchimento do campo com o valor retornado. Se tiver defaultValue, o valor é apresentado, e pode ser editado.

App JS:

Nome_da_Entidade.nome_do_campo.defaultValue: mgr, crud
      return 1000;

Nome_da_Entidade.nome_do_campo.defaultValue_: mgr, crud
      mgr.resume(1000);

validation: Validação do valor preenchido para campo. Se a validação retornar “false”, não continua, volta ao campo anterior. Se não for um método com callback, o retorno padrao é “true”, a validação foi com sucesso.

App JS:

Nome_da_Entidade.nome_do_campo.validation: mgr, crud, value
      if (entry) {
              return false;
      }

Nome_da_Entidade.nome_do_campo.validation_: mgr, crud, value
      if (entry) {
              mgr.resume(false);
      }

onLoadSrcHtml: Preparação do Html a ser exibido.

App JS:

Nome_da_Entidade.nome_do_campo.onLoadSrcHtml: mgr, crud, entry
      var html = '<html><head>                <meta charset="UTF-8">          <style>                 table {font-family:Arial, Helvetica, sans-serif;  font-size:12px;  text-shadow: 1px 1px 0px #fff;  background:#f6f6f6;  border:#ccc 1px solid;    -moz-border-radius:3px;  -webkit-border-radius:3px;  border-radius:3px;    -moz-box-shadow: 0 1px 2px #d1d1d1;  -webkit-box-shadow: 0 1px 2px #d1d1d1;  box-shadow: 0 1px 2px #d1d1d1;  width: 100%;  display: table;                         }                                               table tr.odd {  font-size:13px;  background: #eaebec;  background: -webkit-gradient(linear, left top, left bottom, from(#f8f8f8), to(#eaebec;));  background: -moz-linear-gradient(top,  #f8f8f8,  #eaebec;);                   }               </style>                        </head>         <body>                          <table> ';

              model.UltimoApontamento.dao().last({delegate:this, callback:function(entry) {
              if (entry) {

                      html += '<tr class="odd"><th colspan="4"> Último Apontamento </th></tr>';
                      html += '<tr> <td>OS:</td> <td>' + entry.os + '</td> </tr>';
                      html += '<tr> <td>Operação:</td> <td>' + entry.operacao + '</td> </tr>';
                      html += '<tr> <td>Data:</td> <td>' + entry.data + '</td> </tr>';

              } else {
                      html += '<tr><td colspan="4">Não encontrou último apontamento!</td></tr>';
              }

      }});
      html += '</table>       </body>  </html>';

Nome_da_Entidade.nome_do_campo.onLoadSrcHtml_: mgr, crud, entry
      var html = '<html><head>                <meta charset="UTF-8">          <style>                 table {font-family:Arial, Helvetica, sans-serif;  font-size:12px;  text-shadow: 1px 1px 0px #fff;  background:#f6f6f6;  border:#ccc 1px solid;    -moz-border-radius:3px;  -webkit-border-radius:3px;  border-radius:3px;    -moz-box-shadow: 0 1px 2px #d1d1d1;  -webkit-box-shadow: 0 1px 2px #d1d1d1;  box-shadow: 0 1px 2px #d1d1d1;  width: 100%;  display: table;                         }                                               table tr.odd {  font-size:13px;  background: #eaebec;  background: -webkit-gradient(linear, left top, left bottom, from(#f8f8f8), to(#eaebec;));  background: -moz-linear-gradient(top,  #f8f8f8,  #eaebec;);                   }               </style>                        </head>         <body>                          <table> ';

              model.UltimoApontamento.dao().last({delegate:this, callback:function(entry) {
              if (entry) {

                      html += '<tr class="odd"><th colspan="4"> Último Apontamento </th></tr>';
                      html += '<tr> <td>OS:</td> <td>' + entry.os + '</td> </tr>';
                      html += '<tr> <td>Operação:</td> <td>' + entry.operacao + '</td> </tr>';
                      html += '<tr> <td>Data:</td> <td>' + entry.data + '</td> </tr>';

              } else {
                      html += '<tr><td colspan="4">Não encontrou último apontamento!</td></tr>';
              }

      }});
      html += '</table>       </body>  </html>';

      mgr.resume(html);

Eventos de Lista

onEntityListQueryPrepare: Preparação da lista filtrando por relacionamento entre entidades.

App JS:

Nome_da_Entidade.nome_do_campo.onEntityListQueryPrepare: mgr, crud, queryParams
      queryParams.sql = 'SELECT t.* FROM Entidade1 AS e1 JOIN Entidade2 AS e2 on e1.id = e2.id_campo_entidade_1 WHERE e2.id_campo_entidade_2=' + this.id_campo_entidade_2.id;

onFilterListEntry: Preparação da lista filtrando registros por campo.

App JS:

Nome_da_Entidade.nome_do_campo.onFilterListEntry: mgr, crud, entry
      if (entry.campo_a_ser_filtrado) {
              return false;
      }

onListEntries: Preparação de uma nova lista com os registros desejados.

App JS:

Nome_da_Entidade.nome_do_campo.onListEntries: mgr, crud, delegate, callback
      model.Entidade2.dao().list({delegate:this, callback:function(list1) {
              var list2 = [];
              for (var i = 0; i < list1.length; i++) {
                      var entry = list1[i];
                      if (!entry.campo_a_ser_filtrado) {
                              list2.push(entry);
                      }
              }
              callback.call(delegate, list2);
      }});

ATRIBUTOS

Atributos de Entidade

confirmCreate: Confirma criação da entidade. Se não houver o atributo confirmCreate, será mostrada a mensagem para confirmar a criação. Para retirar a mensagem, utilizar confirmCreate:0.

confirmFinish: Confirma finalização da entidade. Se não houver o atributo confirmFinish, será mostrada a mensagem para confirmar a finalização. Para retirar a mensagem, utilizar confirmFinish:0.

descriptionFields: Descrição do campo. Se não houver o atributo descriptionFields, a descrição é preparada com o primeiro campo INT que nao seja o ID se houver, mais o primeiro campo String se houver.

extName: Substitui o nome da entidade para enviar ao servidor.

info: Mostra informação no topo da tela. Utilizar info:’Nome_da_Entidade’, E na entidade adicionar o campo info: {type:’text’} que conterá a mensagem a ser exibida no topo da tela.

label: Texto que será exibido ao chamar o campo ou entidade.

verifyRequired: Verifica se tem registro no banco de dados. O atributo verifyRequired deve ser adicionado a entidade sync:out que será preenchida, para verificar se há alguma entidade do tipo sync:in que está sem dados. Nas entidades sync:in que devem ser verificadas, deve ser adicionado o atributo required:1. Caso alguma entidade obrigatoria esteja vazia, exibe uma mensagem ao usuario e impede o fluxo de prosseguir.

Atributos de Campo

Tipo de Campo

Caso o tipo não seja definido, por default será considerado um campo númerico.

type:'back': Utilizar com na tela Main junto com o evento para sair do aplicativo event:'exit()'.

type:'main': Utilizar com na tela para definir a entiade do tipo Main.

type:'custom': HTML. Utilizar o evento onLoadSrcHtml para preparação o HTML a ser exibido.

type:'lines': Campo de texto com multiplas linhas.

type:'text': Campo de texto.

Atributos de Exibição

position: Posição do campo na tela Main. Pode ser definida como: ‘Menu’, ‘Bar’, ‘Hidden’.

addFixedOptions:1: Usada para definir que as opções fixas do Crud menu devem ser adicionadas após esta opção.

Condição de Preenchimento do Campo

fill:'no': Pula o preenchimento do campo.

fill:'finish': Pede o preenchimento do campo no processo de finalização da entidade.

fill:'manual':

Numeral

Campos com nome Padrão

id: Não é pedido o preenchimento para o usuário. É um campo númerico com valor incremental para cada entidade.

date: Se o campo inicia com “date”, não é pedido o preenchimento para o usuário. É um campo númerico cujo o valor será a data atual em milissegundos.

onlineFlagInicial: Se o campo inicia com “onlineFlag”, não é pedido o preenchimento para o usuário. O campo númerico será preenchido no momento do sincronismo com os valores: 1 (online), 0 (offline).

uuid: Gera identificador único.

decimal: Defini o número de digitos da parte fracionária (à direita do separador).

formatThousand: Formatação de milhar no campo numérico. Para retirar a formatação, adicionar o atributo formatThousand:0.

maxLength: Defini o tamanho máximo de casas decimais

Texto

upperCase: Formatação do texto com letras maiusculas.

Lista

label: Defini o texto que será apresentado ao mostrar o campo.

list: Defini o campo como um item de menu que deve ser listado no menu da entidade em questão, após a criação da mesma. O atributo list:1 deve ser usado indicando a entidade a ser preenchida com fk:nome_da_entidade.

search: Defini o campo que será usado para busca numa lista.

Model JS:

Nome_da_Entidade :{
      sync:'out',
      extName:'Apontamento',
      info:'UltimoApontamento',
      label:'Apontar',
      confirmCreate:0,
      confirmFinish:0,
      verifyRequired:1,
      fields:{
              id: {},
              date: {},
              onlineFlag: {},
              idSeq: {uuid:1},
              campo_nao_pedido: {fill:'no'},
              campo_texto: {type:'text', upperCase:1, label:'Texto simples'},
              campo_texto_multilinha: {type:'lines', fill:'manual',defaultValue:'texto inicial'},
              campo_validacao_online: {onlineValidate:{name:'Metodo_de_validacao', block:1}},
              campo_inteiro_ou_long: {autoFill:10},
              campo_fixed_point: {onlyConfirm:true, saveAppState:true, label:'Confirma chegada?'},
              campo_decimal: {decimal:2, maxLength:9, formatThousand:0},
              campo_assinatura: {fk:'Binary', signature:1, condition:'this.campo_inteiro_ou_long > 10'},
              campo_foto: {fk:'Binary', picture:1},
              campo_foto: {fk:'Binary', list:1},
              campo_html: {type:'custom'},
              campo_entidade: {fk:'Outra_Entidade', fill:'finish'}
      },
      crudMenuActions:{
              campo: {}
      }
},
Outra_Entidade:{
      sync:'in',
      label:'Outra Entidade',
      required:1,
      descriptionFields:['codigo','descricao'],
      fields:{
              id: {},
              codigo: {search:1, label:'código'},
              descricao: {type:'text'}
      }
}

FUNCIONALIDADES

Dates

Formata a data(UTC) em milliseconds para String. Pode ser chamado direto pelo app e model.

formatUTCTimeDate: Retorno no padrao: HH:mm:ss DD/MM/YYYY

App JS:

var dataStr = Dates.formatUTCTimeDate(dateField);

formatUTCDateTime: Retorno no padrao: DD/MM/YYYY HH:mm:ss

App JS:

var dataStr = Dates.formatUTCDateTime(dateField);

formatUTCDate: Retorno no padrao: DD/MM/YYYY

App JS:

var dataStr = Dates.formatUTCDate(dateField);

formatUTCTime: Retorno no padrao: HH:mm

App JS:

var dataStr = Dates.formatUTCTime(dateField);

Fixed Point

Model JS:

Nome_da_Entidade:{
      sync:'out',
      fields:{
              id:     {},
              fixedPoint: {onlyConfirm:true, saveAppState:true, label:'Confirma chegada?'}
      }
}

Info

Model JS:

Nome_da_Entidade:{
      sync:'out',
      info:'UltimoApontamento',
      fields:{
              id:     {},
              campo_crud: {fk:'ApontamentoServico', list:1, label:'Serviço', info:'UltimoApontamento'}
      }
}

Location

Campos enviados: long, lat, alt, gpsTime, time

Model JS:

Nome_da_Entidade:{
      sync:'out',
      fields:{
              id:     {},
              location:       {fk:'Location'}
      }
}

Picture

Model JS:

Nome_da_Entidade:{
      sync:'out',
      fields:{
              id:     {},
              binaryId: {fk:'Binary', picture:1}
      }
}

Signature

Model JS:

Nome_da_Entidade:{
      sync:'out',
      fields:{
              id:     {},
              binaryId: {fk:'Binary', signature:1}
      }
}

Crud

crud: gera um novo registro da entidade passada como atributo

App JS:

crud(entity, delegate);
entity: entidade do modelo para criar o registro
delegate: quem irá executar o callback(onCrudFinish)

Exemplo:

      Main.Boletim:
              crud(model.Boletim);

crudFields: preenche apenas os campos da entidade que foram especificados em ‘fieldsNames’

App JS:

crudFields(entity, entry, fieldsNames, delegate, callback);

entity: entidade do modelo para criar o registro
entry: registro a ser preenchido, ou null se quiser que seja criado um registro
fieldsNames: array de nomes que deseja que sejam preenchidos Exemplo: ['id', 'date']
delegate: quem irá executar o callback
callback: função que deverá ser chamada quando o crud finalizar o preenchimento, pode ser definido também no delegate com o listener de nome onCrudFinish

Exemplo:

      Boletim.onOpenMenu_: crudController
              this.onCrudFinish= function(entry, crud) {
                      crudController.showMenu();
              };
              var entry = {name: 'test'};
              var c = crudFields(model.entity, entry, ['id', 'date', 'onlineFlag', 'location'], this);

Criação Dados

installData: Deve ser escrido alternando aspas duplas para os valores e aspas simples para o sql.

Model JS:

installData:[
                'INSERT INTO Nome_da_Entidade VALUES(1,"descricao_do_campo")'
        ]

LANG

É possivel modificar os titulos, labels e mensagens padrão do fluxo, para isso é usado o atributo lang do sistema.

Exemplo de entidades:

Model JS:

Turno:{
        sync:'out', extName:'Boletim',
        fields:{
                id:                                             {},
                idSeqBoletim:                   {uuid:1},
                dateAbertura:                   {},
                onlineFlagInicial:              {},
                location:                               {fk:'Location'},
                apontamentoOS:                  {fk:'ApontamentoOS', list:1, label:'OS'},
                apontamentoTG:                  {fk:'ApontamentoTG', list:1, label:'Tarefas Gerais'}
                dateFechamento:                 {fill:'finish'},
                onlineFlagFinal:                {fill:'finish'},
        }
},
ApontamentoDeslocamento:{
        sync:'out',
        fields:{
                id:                                             {},
                apontamentoOS:                  {fk:'ApontamentoOS'},
                idSeqBoletim:                   {type:'text', autoFill:'this.apontamentoOS.idSeqBoletim'},
                idSeqOS:                                {type:'text', autoFill:'this.apontamentoOS.idSeqOS'},
                idOS:                                   {type:'text', autoFill:'this.apontamentoOS.idOS'},
                idSeqApontamento:               {uuid:1},
                dateSaida:                              {},
                onlineFlagSaida:                {},
                location:                               {fk:'Location'},
                idModal:                                {fk:'Modal'},
                idTipoTransporte:               {fk:'TipoTransporte', label:'Tipo de Transporte'},
                fornecedor:                             {fk:'Fornecedor', label:'Fornecedor', condition:'this.idTipoTransporte.fgFornecedor == 1'},
                placa:                                  {type:'text', upperCase:1, label:'Placa', condition:'this.idTipoTransporte.fgPlaca == 1', maxLength:250},
                kmAnterior:                             {decimal:2, maxLength:9, label:'Km Anterior', formatThousand:0},
                kmSaida:                                {decimal:2, maxLength:9, label:'Km Saída', formatThousand:0, condition:'this.idTipoTransporte.fgKM == 1', validation:'this.kmSaida > 0'},
                idLocalSaida:                   {fk:'Local', label:'Local Saída'},
                chegou:                                 {onlyConfirm:true, saveAppState:true, label:'Confirma chegada?'},
                idLocalChegada:                 {fk:'Local', label:'Local Chegada'},
                kmChegada:                              {decimal:2, maxLength:9, label:'Km Chegada', formatThousand:0, condition:'this.idTipoTransporte.fgKM == 1'},
                dateChegada:                    {condition:'this.chegou == 1'},
                onlineFlagChegada:              {condition:'this.chegou == 1'},
                opcoesEscolhaOS:                {fk:'OpcoesEscolhaOS', label:'Finalizar deslocamento e:'}
        }
},

Exemplo de Lang:

Model JS:

lang:{
        ApontamentoDeslocamento:'Deslocamento',
        ApontamentoDeslocamento_idModal:'Modal',
        ApontamentoDeslocamento_idTipoTransporte:'Tipo de transporte',
        ApontamentoDeslocamento_chegou_input:'Confirma Chegada?',
        ApontamentoDeslocamento_chegou_confirm:'Sim',
        Turno_MsgCreateConfirm:'Confirma abertura de turno?',
        Turno_MsgFinishConfirm:'Confirma fechamento de turno?',
        Turno_LblFinish:'Finalizar/Pausar OS',
        VerifyEmptyMessage:'O apontamento não poderá ser realizado pois o cadastro de <entities> está vazio.',
        VerifyEmptyMessagePlural:'O apontamento não poderá ser realizado pois os cadastros de <entities> estão vazios.',
        codigoTecnico_MsgOnlineValidateFail:'Matricula inválida para filial selecionada.'
}

Titulo da Entidade: Usado para alterar o titulo do menu da entidade, similar a colocar o atributo ‘label’ na entidade.

Model JS:

NomeDaEntidade:'Titulo da Entidade',

Titulo do Campo: Usado para alterar o titulo de um campo da entidade, exibido conforme este é preenchido. Similar a colocar o atributo ‘label’ no campo.

Model JS:

NomeDaEntidade_campo:'Campo da Entidade',

Confirmação de criação: Usado para alterar o texto na tela de confirmação de criação da entidade.

Model JS:

NomeDaEntidade_MsgCreateConfirm:'Confirma a criação da entidade?',

Confirmação de finalização: Usado para alterar o texto na tela de confirmação de finalização da entidade.

Model JS:

NomeDaEntidade_MsgCreateConfirm:'Confirma a finalização da entidade?',

Label de finalização: Altera o texto da opção de “Finalizar Entidade” do menu.

Model JS:

NomeDaEntidade_LblFinish:'Fechar menu de Entidade',

Falha no sincronismo: Altera o texto exibido quando ocorre algum erro no sincronismo de dados com o servidor. Usado junto com o atributo required das entidades.

Model JS:

VerifyEmptyMessage:'O apontamento não poderá ser realizado pois o cadastro de <entities> está vazio.',
VerifyEmptyMessagePlural:'O apontamento não poderá ser realizado pois os cadastros de <entities> estão vazios.',

Falha na validação: Altera o texto exibido num toast quando ocorre um erro na validação de um campo.

Model JS:

campoEntidade_MsgOnlineValidateFail:'Opção invalida selecionada.'

VALIDAÇÃO ONLINE

O xMova pode fazer validação online dos valores inseridos nos campos de uma entidade. Basta adicionar ao campo o atributo onlineValidate.

Model JS:

campo: {onlineValidate:{name:’Metodo_de_validacao’, block:1}}

O sistema de terceiro deve retornar os seguites status:

  • Sucesso: status=0
  • Erro: status=1
  • Falha: status>=2
  • Não autorizado: status=4