1.18.1.5.6 Chrome HTML Dialog communicates to JavaScript

Summary

In this tutorial, you build the CEF(Chromium Embedded Framework) HTML control dialog to show how to communicate asynchronously or synchronously to Java Script.

Minimum Origin Version Required: Origin 2024b

Creating an CEF HTML Page for Dialog

  1. Open Code Builder, create a new HTML file and save as CefSimpleHtmlDlg.html to the folder CefSimpleHtmlDlg.
  2. Copy the following code and paste it within the CefSimpleHtmlDlg.html:
    <!doctype html>
    <html>
    <head>
    	<meta charset="utf-8">
    	<script src="http://olab/resource/programfolder/JS/jquery.js"></script>
    	<script src="http://olab/resource/programfolder/JS/olab.js"></script>
    	<script language="JavaScript">
    	function setup() {
    	}
    	
    	function alertFromOrigin(msg) {
    		alert(msg)
    		window.O.OnCallbackFromOrigin(msg)
    	}
    	
    	// Send a query to Origin with Asynchronous, recomment use Asynchronous methods.
    	function sendMessageAsync() {
    		window.O.OnDoSomethingReturnObject(3, document.getElementById("messageAsync").value, function(response) {
    			if(response) {
    				document.getElementById('resultAsync').value = 'Response: '+JSON.stringify(response);
    			}
    			else {
    				document.getElementById('resultAsync').value = 'Error';
    			}
    			
    		});
    	}
    
    	// Send a query to Origin with Synchronous, not recomment to use Synchronous methods, use Asynchronous methods instead.
    	function sendMessageSync() {
    		let response = window.O.OnDoSomethingReturnObject(3, document.getElementById("messageSync").value);
    		if(response) {
    			document.getElementById('resultSync').value = 'Response: '+JSON.stringify(response);
    		}
    		else {
    			document.getElementById('resultSync').value = 'Error';
    		}
    	}
    	</script>
    </head>
    
    <body bgcolor="white" onload="setup()">
    	<form id="form">
    		Asynchronous Message: <input type="text" id="messageAsync" value="This is Asynchronous Message">
    		
    		<br/><input type="button" onclick="sendMessageAsync();" value="Send Message to Origin Asynchronous">
    		<br/>You should see the reverse of your Asynchronous message below:
    		<br/><textarea rows="10" cols="40" id="resultAsync"></textarea>
    		
    		<br/>Synchronous Message: <input type="text" id="messageSync" value="This is Synchronous Message"> <span style="color:red">(not recomment to use Synchronous methods, use Asynchronous methods instead)</span>
    		<br/><input type="button" onclick="sendMessageSync();" value="Send Message to Origin Synchronous">
    		<br/>You should see the reverse of your Synchronous message below:
    		<br/><textarea rows="10" cols="40" id="resultSync"></textarea>
    	</form>
    </div>
    </body>
    </html>
    Note:
    • Javascript communicates asynchronously to Origin in function sendMessageAsync, and communicates synchronously in function sendMessageSync. The asynchronize way is recommended to use in CEF HTML Dialog.

Once you finish this step, you can see the html page by opening the CefSimpleHtmlDlg.html with a web browser.

Creating an CEF HTML Dialog

Now you are ready to edit the Origin C code to create an CEF HTML dialog.

  1. In Code Builder, create a new cpp file named CefSimpleHtmlDlg.cpp under the folder CefSimpleHtmlDlg.
  2. Copy the following code and paste it within the CefSimpleHtmlDlg.cpp :
    #include <Origin.h>
    #include <../OriginLab/DialogEx.h>
    #define _USE_CEF_AS_HTML_CTRL
    #include <../OriginLab/HTMLDlg.h>
    
    #define CEFSIMPLE_HTML_FILE "CefSimpleHtmlDlg.html"
    #define CEFSIMPLE_TITLE _L("CefSimpleHtmlDlg")
    
    class CefSimpleHtmlDlg;
    static CefSimpleHtmlDlg *s_pDlg = NULL;
    
    class CefSimpleHtmlDlg: public HTMLDlg
    {
    protected:
    	// Return full path and file name to HTML file.
    	string GetInitURL()
    	{
    		string strFile = __FILE__;
    		return GetFilePath(strFile) + CEFSIMPLE_HTML_FILE;
    	}
    	// Return title of dialog.
    	string GetDialogTitle() {return CEFSIMPLE_TITLE;}
    
    	// Called after dialog is created but before it is shown.
    	BOOL OnInitDialog()
    	{
    		if( !HTMLDlg::OnInitDialog() ) // Call base class.
    			return FALSE;
    		
    		ModifyStyle(0, WS_MAXIMIZEBOX|WS_MINIMIZEBOX);
    		ModifyStyleEx(0, WS_EX_DLGMODALFRAME);
    
    		return TRUE;
    	}
    	void OnHTMLReady() //override
    	{
    		HTMLDlg::OnHTMLReady();
    		
    		CallJavaScript("alertFromOrigin('Hello!')");
    	}
    	BOOL OnDestroy()
    	{
    		HTMLDlg::OnDestroy();
    		return TRUE;
    	}
    	void OnMinMaxInfo(MINMAXINFO* lpMMI)
    	{
    		lpMMI->ptMinTrackSize.y = CheckConvertDlgSizeWithDPI(450, false);
    		lpMMI->ptMinTrackSize.x = CheckConvertDlgSizeWithDPI(900, true);
    	}
    	BOOL OnDlgResize(int nType, int cx, int cy) // when you resize the dialog, need to reinit the size and position of each control in dialog
    	{
    		if( !IsInitReady() )
    			return false;
    
    		// MoveControlsHelper _temp(this); // you can uncomment this line, if the dialog flickers when you resize it
    		HTMLDlg::OnDlgResize(nType, cx, cy); //place html control in dialog
    
    		if( !IsHTMLDocumentCompleted() ) //check the state of HTML control
    			return FALSE;
    
    		return TRUE;
    	}
    public:
    	DECLARE_DISPATCH_MAP
    
    	EVENTS_BEGIN_DERIV(HTMLDlg)
    		ON_INIT(OnInitDialog)
    		ON_DESTROY(OnDestroy)
    		ON_SIZE(OnDlgResize)
    		ON_GETMINMAXINFO(OnMinMaxInfo)
    	EVENTS_END_DERIV
    
    
    	// return object must set function name end with "Object"
    	struct STRetObjs
    	{
    		int id;
    		string name;
    		string message;
    		
    		string GetJson()
    		{
    			string strjson;
    			JSON.ToString(*this, strjson);
    			return strjson;
    		}
    	};
    	string OnDoSomethingReturnObject(int nId, string strMessage)
    	{
    		STRetObjs obj;
    		obj.name = "Tom";
    		obj.id = nId;
    		obj.message = strMessage;
    		return obj.GetJson();
    	}
    		
    	void OnCallbackFromOrigin(string strMessage)
    	{
    		// do your work here call from "CallJavaScript("alertFromOrigin('Hello!')");"
    		GetNBoxDisplayInfo displayInfo;
    		displayInfo.lpcszTitle = strMessage;
    		displayInfo.bHideContextHelp = true;
    		GETN_BOX(tr);
    		GETN_STR(message, _L("Message"), strMessage)
    		if(GetNBox(tr, NULL, &displayInfo, GetSafeHwnd()))
    		{
    		}
    	}
    
    private:
    };
    
    BEGIN_DISPATCH_MAP(CefSimpleHtmlDlg, HTMLDlg)
    	DISP_FUNCTION(NewBookTemplate, OnDoSomethingReturnObject, VTS_BSTRA, VTS_I4 VTS_BSTRA)	
    	DISP_FUNCTION(NewBookTemplate, OnCallbackFromOrigin, VTS_VOID, VTS_BSTRA)
    END_DISPATCH_MAP
    
    #pragma labtalk(1) // Enable OC functions for LT calling.
    
    void DoCefSimpleHtmlDlg()
    {
    	if( s_pDlg == NULL )
    	{
    		CefSimpleHtmlDlg dlg;
    		s_pDlg = &dlg;
    		//DWORD dwOptions = DLG_NO_LOAD_TOP_LEFT | DLG_NO_LOAD_WIDTH_HEIGHT | DLG_HIDDEN;
    		//dlg.DoModalEx(GetWindow(), dwOptions);
    		dlg.DoModalEx(GetWindow());
    		s_pDlg = NULL;
    	}
    }
    Note:

    Function OnDoSomethingReturnObject compose a struct to string by JSON.ToString and pass to Java script. Then Java script use JSON.stringify to change it to JSON-compliant string representations of the struct.

Launching The Dialog

Save all the code and build it. Run DoCefSimpleHtmlDlg to lauch the dialog.