Page tree
Skip to end of metadata
Go to start of metadata

Cria um objeto para manipular uma página HTML, trocando informações em tempo real entre o SmartClient e o Navegador através do protocolo WebSocket.

Hierarquia

Construtores

Propriedades

Métodos

Observações

  • Disponivel em build superior à 131227A.
  • A comunicação entre o SmartClient e o Navegador é feita através do componente TWebChannel, conforme exemplo a seguir.


Nota 1

Nas plataformas móveis não é possível sobrepor componentes ADVPL sobre o Navegador do TWenEngine, esta é uma característica da biblioteca gráfica Qt.

Depurar a camada HTML/JS do WebEngine

É possível depurar a camada HTML/JS do componente TWebEngine invocando o SmartClient via linha de comando, como no exemplo abaixo:

smartclient --remote-debugging-port=8888

Onde a porta, no exemplo 8888, deverá ser chamada no navegador Chrome, permitindo então a depuração.

http://localhost:8888

Mais detalhes acesse o link abaixo:
Qt WebEngine Debugging and Profiling

O TWebEngine no Youtube

Exemplo completo

Importante

É necessário baixar o arquivo totvstec.js para execução do teste.

Utilizando o exemplo

1. Baixe e salve os conteúdos dos arquivos:
totvstec.js
webengine.prw
webengine.index.html

2. Compile os três arquivos através do TDS - Totvs Development Studio.

3. Execute a função u_webengine

webengine.prw

#include "TOTVS.CH"
user function webengine()
	local i
	local cMultGet := ""
	local nPort,lConnected, link
	local aFiles := {"totvstec.js", "webengine.index.html"}
	local _tempPath := GetTempPath()
	PRIVATE oWebChannel
	PRIVATE oWebEngine
	PRIVATE oMultGet

	PRIVATE oDlg := TWindow():New(10, 10, 800, 600, "Exemplo", NIL, NIL, NIL, NIL, NIL, NIL, NIL,;
	                CLR_BLACK, CLR_WHITE, NIL, NIL, NIL, NIL, NIL, NIL, .T. )

	// Baixa arquivos do exemplo do RPO no diretorio temporario
	for i := 1 to len(aFiles)
		cFile := _tempPath + aFiles[i]
		nHandle := fCreate(cFile)
		fWrite(nHandle, getApoRes(aFiles[i]))
		fClose(nHandle)
	next i

	// ------------------------------------------
	// Prepara o conector WebSocket
	// ------------------------------------------
	oWebChannel := TWebChannel():New()
	nPort  		:= oWebChannel::connect() // Efetua conexão e retorna a porta do WebSocket
	lConnected 	:= oWebChannel:lConnected // Conectado ? [.T. ou .F.]

	// Verifica conexão
	if !lConnected
		msgStop("Erro na conexão com o WebSocket")
		return // Aborta aplicação
	endif

	// ------------------------------------------
	// Define o CallBack JavaScript
	// IMPORTANTE: Este é o canal de comunicação 
	//             "vindo do Javascript para o ADVPL"       
	// ------------------------------------------
	oWebChannel:bJsToAdvpl := {|self,codeType,codeContent| jsToAdvpl(self,codeType,codeContent) }

	// Monta link para navegação local inserindo "file:///"
	if subs(_tempPath,1,2) == "C:"
		_tempPath := "file:///" + strTran(_tempPath, "\", "/")
	endif
	link := _tempPath + "webengine.index.html"

	// ------------------------------------------
	// Cria navegador embedado
	// ------------------------------------------
	oWebEngine := TWebEngine():New(oDlg, 0, 0, 100, 100,, nPort)
	oWebEngine:navigate(link)
	oWebEngine:Align := CONTROL_ALIGN_ALLCLIENT

	// Painel inferior
	@ 038, 000 MSPANEL ConOut SIZE 250, 030 OF oDlg COLORS 0, 16777215 RAISED
	ConOut:Align := CONTROL_ALIGN_BOTTOM
	oMultGet := TSimpleEditor():New( 0,0,ConOut, 100,100,"",, {| u | if( pCount() > 0, cMultGet := u, cMultGet )}, , .T.)
	oMultGet:Align := CONTROL_ALIGN_ALLCLIENT
	
	// ------------------------------------------
	// Botão fara o disparo do método runJavaScript
	// que permite a execução via ADVPL de uma função JavaScript
	// ------------------------------------------
	@ 000, 204 BUTTON oButton1 PROMPT "runJavaScript" SIZE 045, 041 OF ConOut;
	     ACTION {|| oWebEngine:runJavaScript("alert('Alert Javascript\ndisparado via ADVPL')") } PIXEL
	oButton1:Align := CONTROL_ALIGN_RIGHT

	oDlg:Activate("MAXIMIZED")
Return

// ------------------------------------------
// Esta função recebera todas as chamadas vindas do Javascript
// através do método dialog.jsToAdvpl(), exemplo:
// dialog.jsToAdvpl("page_started", "Pagina inicializada");
// ------------------------------------------
static function jsToAdvpl(self,codeType,codeContent)
	local i
	local cFunJS
	local oTmpHashProg:= .F.
	local cCommand := ""

	if valType(codeType) == "C"
		_conout("jsToAdvpl->codeType: " + codeType + " = " + codeContent)

		// ------------------------------------------b
		// Recebe mensagem de termino da carga da página/componente
		// ------------------------------------------
		if codeType == "page_started"

			// ------------------------------------------
			// Ao terminar a carga da página inserimos um botão na página HTML
			// que fará a execução de uma função ADVPL via JavaScript
			//
			// Importante: O comando BeginContent permite a criação de pequenos trechos de código
			// facilitando a construção de chamadas, como neste exemplo onde montamos um trecho Javascript
			// ------------------------------------------
			BeginContent var cFunJS
				<a onclick='totvstec.runAdvpl("DtoS(CtoD(\"" +getDate()+ "\"))", runAdvplSuccess);'>
					<div>
						<font size="5">runAdvpl</font><br><br>
					</div>
				</a>
			EndContent

			// ------------------------------------------
			// O método AdvplToJS envia uma mensagem do ADVPL para o JavaScript, para verificar a chegada 
			// desta mensagem procure o trecho a seguir no arquivo webengine.index.html
			// if (codeType == "html") {...
			// ------------------------------------------
			oWebChannel:advplToJs("html", cFunJS)

		endif

		// ------------------------------------------
		// Este trecho vai executar um comando ADVPL vindo do JavaScript
		// ------------------------------------------
		if codeType == "runAdvpl"

			// ------------------------------------------
			// Importante:
			// A informação trafegada pela chamada do metodo Javascript runADVPL é uma variável do tipo JSON
			// assim é necessário seu tratamento, para tanto utilise as funções getJsonHash e getHField, documentadas neste exemplo
			// ------------------------------------------
			if getJsonHash(codeContent, @oTmpHashProg)
			
				cCommand := getHField(oTmpHashProg, "codeBlock") 
				if !empty(cCommand) 
				
					// Transforma o texo em um bloco de código e 
					// em caso de sucesso executa o mesmo 
					xVal := &("{|| " + cCommand + "}")
					if valType(xVal) == "B"
						xRet := eval(xVal)
						xRet := cValToChar(xRet) // Converte pra String
		
						// ------------------------------------------
						// Importante:
						// Este trecho executa do callBack (mensagem de retorno) para o Javascript
						// permitindo o retorno de informações ao HTML após o processamento via ADVPL
						// ------------------------------------------
						fnCallBack = getHField(oTmpHashProg, "callBack")+"('" +xRet+ "')"
						oWebEngine:runJavaScript(fnCallBack)
						
					endif
					
				endif
			endif
		
		endif

	endif

return

/* ---------------------------------------------------------------
 Parseia o Json em um Hash
 
 getJsonHash: recebe o conteudo no formato Texto que será parseado
 oHash: é uma varivel que receberá "por referencia" o conteudo HASH
        contido no Texto inicial, por ser uma variavel utilizada por referencia
        ela deve ter seu valor declarado anteriormente, exemplo: oTmpHashProg:= .F.
---------------------------------------------------------------*/
Static Function getJsonHash(jsonData, oHash)
	Local oJson := tJsonParser():New()
	Local jsonfields := {}
	Local nRetParser := 0

	if empty(jsonData)
		return .F.
	endif

	// Converte JSON pra Hash
	return oJson:Json_Hash(jsonData, len(jsonData), @jsonfields, @nRetParser, @oHash)
return

/* ---------------------------------------------------------------
 Retorna valor do campo no Hash
 
 oHash: variável no formato HASH criada pela função  getJsonHash
 jsonField: nome do campono no formato Texto que se deseja recuperar
 
 retorno: valor do campo encontrado ou "vazio" caso contrário
 ---------------------------------------------------------------*/
Static Function getHField(oHash, jsonField)
	Local xGet := Nil
	// Recupera valor do campo
	if HMGet(oHash, jsonField, xGet)
		return xGet
	else
		return ""
	endif
return

// ---------------------------------------------------------------
// Exibe conout no MultiGet para auxiliar na visualização em tela
// ---------------------------------------------------------------
static function _conout(cText)
	conOut(cText)
	oMultGet:Load(cText)
Return

webengine.index.html

<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
    <style>
        body { font-family: 'Calibri'; }
        a { text-decoration: none; }
        div { display: inline-block; float: left; background-color: #019AC4; color: #FFFFFF; 
              width: 250px; height: 34px; margin: 10px; padding: 10px; }
    </style>

    <script src="totvstec.js"></script>
    <script>
        onload = function () { loadEngine(); }

        function loadEngine() {
            // Conecta WebSocket Server
            totvstec.connectWS( function(){
                // Carrega mensageria exclusiva da pagina
                dialog.advplToJs.connect(function (codeType, codeContent) {
                    if (codeType == "html") {
                    	var page = document.getElementById("main");
                    	page.innerHTML += codeContent; 
                    }
                });

                // Envia sinal informando termino da carga da pagina
                dialog.jsToAdvpl("page_started", "Pagina inicializada");
            });            
        }

		function getDate(){
			var today = new Date();
			var dd = today.getDate();
			var mm = today.getMonth()+1; //January is 0!
			var yyyy = today.getFullYear();
			return mm+'/'+dd+'/'+yyyy;
		}
		
		function runAdvplSuccess(retStr){
			alert("CallBack da função runADVPL: " + retStr);
		}
    </script>
</head>

<body>
    <font face="calibri" color="#FFFFFF">
    <p id="main"></p>
</body>
</html>

Preview

Abrangência

Protheus 11 , TOTVS Application Server

  • No labels