=============== 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 = ' '; model.UltimoApontamento.dao().last({delegate:this, callback:function(entry) { if (entry) { html += ''; html += ''; html += ''; html += ''; } else { html += ''; } }}); html += '
Último Apontamento
OS: ' + entry.os + '
Operação: ' + entry.operacao + '
Data: ' + entry.data + '
Não encontrou último apontamento!
'; Nome_da_Entidade.nome_do_campo.onLoadSrcHtml_: mgr, crud, entry var html = ' '; model.UltimoApontamento.dao().last({delegate:this, callback:function(entry) { if (entry) { html += ''; html += ''; html += ''; html += ''; } else { html += ''; } }}); html += '
Último Apontamento
OS: ' + entry.os + '
Operação: ' + entry.operacao + '
Data: ' + entry.data + '
Não encontrou último apontamento!
'; 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 está vazio.', VerifyEmptyMessagePlural:'O apontamento não poderá ser realizado pois os cadastros de 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 está vazio.', VerifyEmptyMessagePlural:'O apontamento não poderá ser realizado pois os cadastros de 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}} Retorno de Dados Validados ========================== O sistema de terceiro deve retornar os seguites status: * Sucesso: ``status=0`` * Erro: ``status=1`` * Falha: ``status>=2`` * Não autorizado: ``status=4``