Introduction

A5WD is a library for building next generation desktop applications using Alpha Anywhere.

Built using Alpha Anywhere's Xbasic. Fast, lightweight, and easy to use.

Download

Download the compressed file using the link below.

Filename: A5WD.zip
File Size: 22 KB
Version: 1.0.0
MD5: 793be12d8b61f5970fec2382c626b699
  DOWNLOAD

How to Use?

Unzip then copy the file "A5WD.AEX" to your workspace.

copy-a5wd

Open the workspace then click on "File" and "Workspace Properties ...".

workspace-properties

Click on the "Compiled Libraries" tab then click on "Add" button.

Navigate to your workspace. Select the A5WD.AEX file then click "Open".

open-a5wd

Finally, click "OK" button.

workspace-properties-2

The library is now ready to be used.

Using HTML Content

Set HTML content by setting the value of cp.html.

Example

Download Workspace

Xbasic

XBM' autoexec
'
' Instantiate and set xdialog title.
dim xdsMyDialog as P =RN new a5wd::xdialog::RNFUNCmodeless("My Dialog")RN
'
' Set HTML content.
xdsMyDialog.cp.html =XBM PPPhtml%
	HMM<style>
			div, button { margin: 20px 0 0 100px; }
	</style>
	
	<form>
		<div>
			<label for="first_name_fld">First Name:</label><br>
			<input type="text" id="first_name_fld">
		</div>
		<div>
			<label for="last_name_fld">Last Name:</label><br>
			<input type="text" id="last_name_fld">
		</div>
		<button type="button" onclick="xDialogEvent('submit')">Submit</button>
	</form>
	
	<script>								
		(function() {
			document.getElementById('first_name_fld').focus();
		})();
	</script>HMM
XBM%html%

' Set EventCode.
xdsMyDialog.EventCode = PPPcode%
	' Note: evt = a_dlg_button
	' Handle events.
	if evt = "submit"
		dim new_user as C =RN cp.GetValue("first_name_fld") + " " + cp.GetValue("last_name_fld")
		ui_msg_box("Xbasic", "Welcome " + new_user + ".", UI_INFORMATION_SYMBOL+UI_OK)
	end if
%code%
'
' Open the xdialog using the desired size and default position.
xdsMyDialog.Open("4", "2.4")
XBM

Using Online Resources

Load online resources such as CSS/Javascript on your HTML.

Example

Download Workspace

Xbasic

XBM' autoexec
'
'Instantiate and set xdialog title.
dim xdsMyDialog as P =RN new a5wd::xdialog::RNFUNCmodeless("My Dialog")RN
'
' Set HTML content.
xdsMyDialog.cp.html =XBM PPPhtml%
	HMM<!-- load bootstrap CSS from CDN -->
	<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css">
	
	<!-- load jquery and bootstrap from CDN -->
	<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
	<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js"></script>
	
	<div class="container-fluid">
		<form>
			<div class="form-group mt-5">
				<label for="first_name_fld">First Name</label>
				<input type="text" class="form-control" id="first_name_fld">
			</div>
			<div class="form-group">
				<label for="last_name_fld">Last Name</label>
				<input type="text" class="form-control" id="last_name_fld">
			</div>
			<button type="button" onclick="xDialogEvent('submit')" class="btn btn-primary">Submit</button>
		</form>	
	</div>
	
	<script>								
		(function() {
			$('#first_name_fld').focus();
		})();
	</script>HMM
XBM%html%

' Set EventCode.
xdsMyDialog.EventCode = PPPcode%
	if evt = "submit"
		dim new_user as C =RN cp.GetValue("first_name_fld") + " " + cp.GetValue("last_name_fld")
		ui_msg_box("Xbasic", "Welcome " + new_user + ".", UI_INFORMATION_SYMBOL+UI_OK)
	end if
%code%

' Open the xdialog using the desired size and default position.
xdsMyDialog.Open("5", "3.5")
XBM

Using Local Resources

Load local resources such as CSS/Javascript on your HTML.

You must copy all resources to your workspace.

Example

Download Workspace

Xbasic

XBM' autoexec
'
'Instantiate and set xdialog title.
dim xdsMyDialog as P =RN new a5wd::xdialog::RNFUNCmodeless("My Dialog")RN
'
' Set HTML content.
dim html as C =XBM PPPhtml%
	HMM<!-- load bootstrap CSS from local location -->
	<link rel="stylesheet" href="{AppPath}\html\js\bootstrap\4.5.0\css\bootstrap.min.css">
	
	<!-- load jquery and bootstrap from local location -->
	<script src="{AppPath}\html\js\jquery-3.5.1.slim.min.js"></script>
	<script src="{AppPath}\html\js\bootstrap\4.5.0\js\bootstrap.min.js"></script>
	
	<div class="container-fluid">
		<form>
			<div class="form-group mt-5">
				<label for="first_name_fld">First Name</label>
				<input type="text" class="form-control" id="first_name_fld">
			</div>
			<div class="form-group">
				<label for="last_name_fld">Last Name</label>
				<input type="text" class="form-control" id="last_name_fld">
			</div>
			<button type="button" onclick="xDialogEvent('submit')" class="btn btn-primary">Submit</button>
		</form>	
	</div>
	
	<script>								
		(function() {
			$('#first_name_fld').focus();
		})();
	</script>HMM
XBM%html%
'
dim app_path as C =RN "a5file://" + FUNCa5.Get_Path()	
'
html = strtran(html, "{AppPath}", app_path)	
'
xdsMyDialog.cp.html = html		

' Set EventCode.
xdsMyDialog.EventCode = PPPcode%
	if evt = "submit"
		dim new_user as C =RN cp.GetValue("first_name_fld") + " " + cp.GetValue("last_name_fld")
		ui_msg_box("Xbasic", "Welcome " + new_user + ".", UI_INFORMATION_SYMBOL+UI_OK)
	end if
%code%

' Open the xdialog.
xdsMyDialog.Open("5", "3.5")
XBM

Hosting All Files Locally

This is the best way to go for heavy HTML contents.

Create a folder named "html" and put everything inside it (html files, images, js files, css files, etc.).

Example

Download Workspace

Xbasic

XBM' autoexec
'
'Instantiate and set xdialog title.
dim xdsMyDialog as P =RN new a5wd::xdialog::RNFUNCmodeless("My Dialog")RN

' Point url to local html file.
xdsMyDialog.cp.url = a5.Get_Path() + "\html\my_dialog.html"

' Set EventCode.
xdsMyDialog.EventCode = PPPcode%
	if evt = "submit"
		dim new_user as C =RN cp.GetValue("first_name_fld") + " " + cp.GetValue("last_name_fld")
		ui_msg_box("Xbasic", "Welcome " + new_user + ".", UI_INFORMATION_SYMBOL+UI_OK)
	end if
%code%		

' Open the xdialog.
xdsMyDialog.Open("5", "4.6")
XBM

Hosting Front-End Files Online

You may do this if you want the internet to be the common place for your front-end.

Put all your html files online then simply point to the url.

Example

Download Workspace

Xbasic

XBM' autoexec
'
' Instantiate and set xdialog title.
dim xdsMyDialog as P =RN new a5wd::xdialog::RNFUNCmodeless("My Dialog")RN

' Point url to online location.
xdsMyDialog.cp.url = "http://hiddentools.com/a5wd/app/my_dialog.php"

' Set EventCode.
xdsMyDialog.EventCode = PPPcode%
	if evt = "submit"
		dim new_user as C =RN cp.GetValue("first_name_fld") + " " + cp.GetValue("last_name_fld")
		ui_msg_box("Xbasic", "Welcome " + new_user + ".", UI_INFORMATION_SYMBOL+UI_OK)
	end if
%code%

' Open the xdialog.
xdsMyDialog.Open("5", "4.6")
XBM

Getting HTML Data

Use the function cp.GetValue() to get field values.

Use the function cp.GetInnerHtml() to get inner HTML code.

Use the function cp.ExecuteJavascriptResult() to get the result of a Javascript execution.

Another way is to get the data at the client side and then pass it with the event.

Example

Download Workspace

Xbasic

XBM' autoexec
'
' Instantiate and set xdialog title.
dim xdsMyDialog as P =RN new a5wd::xdialog::RNFUNCmodeless("My Dialog")RN
'
' Set HTML content.
xdsMyDialog.cp.html =XBM PPPhtml%
	HMM<!-- load bootstrap CSS from CDN -->
	<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css">
	
	<!-- load jquery and bootstrap from CDN -->
	<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
	<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js"></script>
	
	<div class="container-fluid">
		<form>
			<div class="form-group mt-5">
				<label for="first_name_fld">First Name</label>
				<input type="text" class="form-control" id="first_name_fld">
			</div>
			<div class="form-group">
				<label for="last_name_fld">Last Name</label>
				<input type="text" class="form-control" id="last_name_fld">
			</div>
			<div class="form-group">
				<label>User ID:</label>
				<span id="user_id" class="ml-3"></span>
			</div>
			<button type="button" onclick="submit_form()" class="btn btn-primary">Submit</button>
		</form>	
	</div>
	
	<script>								
		(function() {
			$('#user_id').html(Math.random().toString(26).slice(2));
			$('#first_name_fld').focus();
		})();

		/* Pass the data with the event. */
		/* Note: Do not use the function submit(). */								
		function submit_form() {
			var first_name = $('#first_name_fld').val();
			var last_name = $('#last_name_fld').val();
			var user_id = $('#user_id').html();
			xDialogEvent('submit|' + first_name + '|' + last_name + '|' + user_id);
		}
	</script>HMM
XBM%html%

' Set EventCode.
xdsMyDialog.EventCode = PPPcode%
	if *first(evt, "submit|")
		' Get the data.
		dim first_name as C =RN cp.GetValue("first_name_fld")
		dim last_name as C =RN cp.GetValue("last_name_fld")
		dim user_id as C =RN cp.GetInnerHtml("user_id")								
	
		' Show obtained data.
		ui_msg_box("Obtained Data", "First Name: " + first_name + GRScrlfQPCPGRE + "Last Name: " + last_name + GRScrlfQPCPGRE + "User ID :" + user_id)
		
		' Show Javascript execution result.
		ui_msg_box("ExecuteJavascriptResult", GRScp.ExecuteJavascriptResultQPGRE"OQHello OQ + $QPOQ#first_name_fldOQCP.valQPCP + OQ OQ + $QPOQ#last_name_fldOQCP.valQPCP"GP)
		
		' Extract passed data.
		first_name = word(evt, 2, "|")
		last_name = word(evt, 3, "|")
		user_id = word(evt, 4, "|")
		
		' Show passed data.
		ui_msg_box("Passed Data", "First Name: " + first_name + GRScrlfQPCPGRE + "Last Name: " + last_name + GRScrlfQPCPGRE + "User ID :" + user_id)
	end if
%code%

' Open the xdialog.
xdsMyDialog.Open("5", "4")
XBM

Setting HTML Data

Use the function cp.SetValue() to set field values.

Use the function cp.SetInnerHtml() to set inner HTML code.

Another way is to use Javascript.

Example

Download Workspace

Xbasic

XBM' autoexec
'
' Instantiate and set xdialog title.
dim xdsMyDialog as P =RN new a5wd::xdialog::RNFUNCmodeless("My Dialog")RN
'
' Set HTML content.
xdsMyDialog.cp.html =XBM PPPhtml%
	HMM<!-- load bootstrap CSS from CDN -->
	<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css">
	
	<!-- load jquery and bootstrap from CDN -->
	<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
	<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js"></script>
	
	<div class="container-fluid">
		<form>
			<div class="form-group mt-5">
				<label for="first_name_fld">First Name</label>
				<input type="text" class="form-control" id="first_name_fld">
			</div>
			<div class="form-group">
				<label for="last_name_fld">Last Name</label>
				<input type="text" class="form-control" id="last_name_fld">
			</div>
			<div class="form-group">
				<label for="department_fld">Department</label>
				<select class="form-control" id="department_fld"></select>
			</div>
			<button type="button" onclick="submit_form()" class="btn btn-primary">Submit</button>
		</form>	
	</div>
	
	<script>								
		(function() {
			$('#name_fld').focus();
		})();
	</script>HMM
XBM%html%

' Set ReadyCode.
xdsMyDialog.ReadyCode = PPPcode%
	' Set first_name_fld value.
	cp.SetValue("first_name_fld", "John")
	
	' Set last_name_fld value using Javascript.
	cp.ExecuteJavascript("document.getElementById(OQlast_name_fldOQ).value = OQSmithOQ")
	
	' Set dropdown options.
	dim dropdown as C =RN PPPhtml%XBM
							HMM<option value="admin">Admin</option>
							<option value="delivery">Delivery</option>
							<option value="engineering">Engineering</option>
							<option value="production">Production</option>
							<option value="maintenance">Maintenance</option>HMM
						%html%XBM		
						
	cp.SetInnerHtml("department_fld", dropdown)
	
	' Set department_fld selected value.
	cp.SetValue("department_fld", "engineering")					
%code%

' Open the xdialog.
xdsMyDialog.Open("5", "5")
XBM

Executing Javascript

Use the function cp.ExecuteJavascript to execute a Javascript or jQuery code.

Example

Download Workspace

Xbasic

XBM' autoexec
'
' Instantiate and set xdialog title.
dim xdsMyDialog as P =RN new a5wd::xdialog::RNFUNCmodeless("My Dialog")RN
'
' Set HTML content.
xdsMyDialog.cp.html =XBM PPPhtml%
	HMM<style>.hidden { display: none; } </style>
	
	<!-- load bootstrap CSS from CDN -->
	<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css">
	
	<!-- load jquery and bootstrap from CDN -->
	<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
	<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js"></script>
	
	<div class="container-fluid">
		<div id="loader" style="text-align:center" class="mt-5">Fetching data ...</div>
		<table id="datatable" class="table table-sm table-striped table-dark mt-5 hidden">
			<thead>
				<tr>
					<th scope="col">#</th>
					<th scope="col">First Name</th>
					<th scope="col">Last Name</th>
				</tr>
			</thead>
			<tbody>
			</tbody>
		</table>	
	</div>HMM
XBM%html%

' Set ReadyCode.
xdsMyDialog.ReadyCode = PPPcode%
	' Simulate fetching data from database
	xbasic_wait_for_idle(2)	
	dim tbody as C =RN "<tr><th scope=\DQrow\DQ>1</th><td>Anthony</td><td>Miller</td></tr>" +\
					 "<tr><th scope=\DQrow\DQ>2</th><td>James</td><td>Norton</td></tr>" +\
					 "<tr><th scope=\DQrow\DQ>3</th><td>Randy</td><td>Green</td></tr>" +\	
					 "<tr><th scope=\DQrow\DQ>4</th><td>Jacob</td><td>Brown</td></tr>" +\						
					 "<tr><th scope=\DQrow\DQ>5</th><td>Alexander</td><td>White</td></tr>" +\
					 "<tr><th scope=\DQrow\DQ>6</th><td>John</td><td>DOQArtagnan</td></tr>"

	' Put the data on the tableOQs body
	cp.ExecuteJavascript("$(OQ#datatable tbodyOQ).html(OQ" + js_escape(tbody) + "OQ)")
	
	' Hide the loader then show the table.
	cp.ExecuteJavascript("$(OQ#loaderOQ).addClass(OQhiddenOQ)")		
	cp.ExecuteJavascript("$(OQ#datatableOQ).removeClass(OQhiddenOQ)")					
%code%

' Open the xdialog.
xdsMyDialog.Open("5", "5")
XBM

HTML Injection

This technique is used to show dynamic HTML contents. When this is used, make sure that all necessary Javascript codes are executed after the HTML code is injected.

Example

Download Workspace

Xbasic

XBM' autoexec
'
' Instantiate and set xdialog title.
dim xdsMyDialog as P =RN a5wd::xdialog::MFmodeless("HTML Injection")
'
' Set url to navigate.
' This will load Javascript and CSS codes.
xdsMyDialog.cp.url = FUNCa5.Get_Path() + "\html\index.html"
'
' Set ReadyCode
xdsMyDialog.ReadyCode = PPPcode%
	'
	' Set HTML code to inject.
	dim html_to_inject as C =RN PPPhtml%XBM
		HMM<form>
			<div class="row mt-5">
				<div class="col-md-6 offset-md-3" style="padding:50px;background-color:#DAF1FD">
					<div class="alert alert-primary bg-light">
						<div class="row">
							<i class="fa fa-info-circle col-sm-2" style="font-size:50px"></i>
							<div class="col-sm-10">
								<p>This is an injected HTML content.</p>
								<p>Color Picker, Date Picker, and Submit button should all work as expected.</p>
							</div>
						</div>
					</div>
					<div class="form-group row mt-5">
						<label for="color" class="col-sm-3 col-form-label">Color Picker</label>
						<div class="col-sm-9">
							<div class="input-group">
								<input id="color" name="color" type="text" value="#ccc" class="form-control" readonly>
							</div>
						</div>
					</div>
					<div class="form-group row">
						<label for="the_date" class="col-sm-3 col-form-label">Date Picker</label>
						<div class="col-sm-9">
							<input type="text" class="form-control" id="the_date">
						</div>
					</div>
					<button type="button" class="btn btn-primary float-right mt-3" onclick="submit_form()">Submit</button>
				</div>
			</div>
		</form>HMM
	XBM%html%
	
	' Set Javascript code needed by the injected HTML to work properly.
	dim js_to_run as C =RN <<%js%XBM
		JSM/* for colorpicker */
		$("#color").spectrum({
			change: function(color) {
				$('body').css('background-color', color.toHexString());
			}		
		});
		$('#color').show();

		/* for datepicker */
		$('#the_date').datepicker({
			format: "mm/dd/yyyy",
			autoclose: true,
			todayHighlight: true
		}).on('show', function(e) {
			if($(this).val().length > 0) {
				$(this).datepicker('update', new Date($(this).val()));
			}
		});JSM
	XBM%js%
	'
	' Inject HTML code.
	cp.SetInnerHtml("page_content", html_to_inject)
	xbasic_wait_for_idle()
	ui_yield()
	'
	' Execute Javascript code.
	cp.ExecuteJavascript(js_to_run)
%code%
'
' Set EventCode.
xdsMyDialog.EventCode = <<%code%
	' Handle events here.
	if *first(evt, "submit_form|")
		dim color as C =RN word(evt, 2, "|")
		dim the_date as C =RN word(evt, 3, "|")
		ui_msg_box("Xbasic Here", "Color: " + color + GRScrlfQP2CPGRE + "Date: " + the_date)
		
	elseif evt = "a5wd"
		MFsys_open("https://a5wd.com/")
	end if
%code%
'
' Open the xdialog.
xdsMyDialog.Open("70%", "70%")
XBM

Xdialog with Children

Any xdialog called by another xdialog is a child by default.

A child xdialog stays on top of its parent.

A child xdialog minimizes and closes with its parent.

Example

Download Workspace

Xbasic

XBM' autoexec
'
' Instantiate and set xdialog title.
dim xdsMyDialog as P =RN new a5wd::xdialog::RNFUNCmodeless("My Dialog")RN
'
' Set HTML content.
xdsMyDialog.cp.html = <<%html%XBM
	HMM<style>
		body { background-color: #CCE8FF; }
		h1, button { margin: 20px 0 0 350px; }
	</style>
	
	<h1> I am a Parent.</h1>
	
	<button style="width:220px; height:40px" type="button" onclick="xDialogEvent('open_child')">Open a Child Dialog</button>HMM
XBM%html%

' Set EventCode.
xdsMyDialog.EventCode = PPPcode%
	if evt = "open_child"
		dim xdsChild as P =RN new a5wd::xdialog::RNFUNCmodeless("Child")
		
		xdsChild.cp.html = PPPhtml%XBM
			HMM<style>
				body { background-color: #FBF1FD; }
				h1, button { margin: 20px 0 0 220px; }
			</style>
			
			<h1> I am a Child.</h1>
			
			<button style="width:220px; height:40px" type="button" onclick="xDialogEvent('open_grand_child')">Open a Child Dialog</button>HMM
		XBM%html%
							
		xdsChild.EventCode = <<%code2%					
			if evt = "open_grand_child"
				dim xdsGrandChild as P =RN new a5wd::xdialog::RNFUNCmodeless("Grand Child")
				
				xdsGrandChild.cp.html = PPPhtml%XBM
					HMM<style>
						body { background-color: #EFFEF0; }
						h1 { margin: 20px 0 0 90px; }
					</style>
					
					<h1> I am a Grand Child.</h1>HMM
				XBM%html%
				
				xdsGrandChild.Open("5", "3")															
			end if
		%code2%
							
		xdsChild.Open("7.5", "5")									
	end if
%code%

' Open the xdialog.
xdsMyDialog.Open("10", "8")
XBM

Xdialog with No Children

If "NoChildren" is set to true, the xdialog will not have children.

Example

Download Workspace

Xbasic

XBM' autoexec
'
' Instantiate and set xdialog title.
dim xdsMyDialog as P =RN new a5wd::xdialog::RNFUNCmodeless("My Dialog")RN
xdsMyDialog.NoChildren = .t.
'
' Set HTML content.
xdsMyDialog.cp.html = PPPhtml%XBM
	HMM<style>
		body { background-color: #CCE8FF; }
		h1, button { margin: 20px 0 0 350px; }
	</style>
	
	<h1> I am a Parent.</h1>
	
	<button style="width:220px; height:40px" type="button" onclick="xDialogEvent('open_child')">Open a Child Dialog</button>HMM
XBM%html%

' Set EventCode.
xdsMyDialog.EventCode = PPPcode%
	if evt = "open_child"
		dim xdsChild as P =RN new a5wd::xdialog::RNFUNCmodeless("Child")
		xdsChild.NoChildren = .t.
		
		xdsChild.cp.html = PPPhtml%XBM
			HMM<style>
				body { background-color: #FBF1FD; }
				h1, button { margin: 20px 0 0 220px; }
			</style>
			
			<h1> I am not a Child.</h1>
			
			<button style="width:220px; height:40px" type="button" onclick="xDialogEvent('open_grand_child')">Open a Child Dialog</button>HMM
		XBM%html%
							
		xdsChild.EventCode = <<%code2%					
			if evt = "open_grand_child"
				dim xdsGrandChild as P =RN new a5wd::xdialog::RNFUNCmodeless("Grand Child")
				xdsChild.NoChildren = .t.
				
				xdsGrandChild.cp.html = PPPhtml%XBM
					HMM<style>
						body { background-color: #EFFEF0; }
						h1 { margin: 20px 0 0 90px; }
					</style>
					
					<h1> I am not a Child.</h1>HMM
				XBM%html%
				
				xdsGrandChild.Open("5", "3")															
			end if
		%code2%
							
		xdsChild.Open("7.5", "5")									
	end if
%code%
'
' Open the xdialog.
xdsMyDialog.Open("10", "8")
XBM

Subclassing

Subclassing is the heart of object-oriented programming. A subclass or a child class inherits the functionality of the parent class and its ancestors (multiple inheritance). A child class automatically contains all exposed variables and functions from its ancestors. Subclassing allows us to use or extend all inherited functionality.

Example

Create a child class that inherits from the base class a5wd::xdialog::modeless. This child class will become a parent to other child classes so let's name it a5wd_parent::xds.

Download Workspace

Xbasic

XBM' PARENT CLASS
'
define class a5wd_parent::xds inherits a5wd::xdialog::modelessRN
'
' This is the function that is called before the xdialog is created.
function OnInitialize as V ()
	self.XdTitle = "TEST"
	self.Width = "70%"
	self.Height = "70%"
	
	' Add javascripts and CSS.
	FUNCself.AddScripts()
	
	' Add Navigation Bar.
	FUNCself.AddNavBar()
	
	' for children initialization
	FUNCself.Initialize()
end function

' Add a MustOverride function for adding NavBar.	
function AddNavBar as V ()
end function

' Add more MustOverride functions as needed.

function AddScripts as V ()
	cp.html = cp.html + PPPhtml%XBM
		HMM<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css">
		<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
		<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js"></script>HMM
	XBM%html%
end function
end class
XBM

Create a child class that inherits from a5wd_parent::xds (above class).

Xbasic

XBM' CHILD CLASS 1
'
define class xds::products inherits a5wd_parent::xdsRN

' Add HTML code here.
function Initialize as V ()
	self.XdTitle = "Products"
	
	dim html as CRN
	html = PPPhtml%XBM
		HMM<div class="container-fluid">
			<h1 style="text-align:center; color:#ccc; margin-top:150px">Put your HTML content here</h1>	
		</div>HMM
	XBM%html%
	
	cp.html = cp.html + html
end function

' Code to execute when state is "ready".
function Ready as V ()
end function

' Handle events here.
function HandleEvent as V ()
	select
		case evt = "link1"
		
		case evt = "link2"
		
	end select
end function

' Add NavBar by overriding the AddNavBar function
function AddNavBar as V ()
	cp.html = cp.html + PPPhtml%XBM
		HMM<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
		<a class="navbar-brand" href="#">NorthWind</a>
		<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation">
			<span class="navbar-toggler-icon"></span>
		</button>
		<div class="collapse navbar-collapse" id="navbarNavDropdown">
			<ul class="navbar-nav">
				<li class="nav-item active">
					<a class="nav-link" href="javascript:xDialogEvent('link1')">Link1</a>
				</li>
				<li class="nav-item">
					<a class="nav-link" href="javascript:xDialogEvent('link2')">Link2</a>
				</li>
			</ul>
		</div>
		</nav>HMM
	XBM%html%	
end function
end class
XBM

Create another child class that inherits from a5wd_parent::xds.

Xbasic

XBM' CHILD CLASS 2
'
define class xds::employees inherits a5wd_parent::xdsRN

' Add HTML code here.
function Initialize as V ()
	self.XdTitle = "Employees"
	
	dim html as CRN
	html = PPPhtml%XBM
		HMM<div class="container-fluid">
			<h1 style="text-align:center; color:#ccc; margin-top:150px">Put your HTML content here</h1>	
		</div>HMM
	XBM%html%
	
	cp.html = cp.html + html
end function

' Code to execute when state is "ready".
function Ready as V ()
end function

' Handle events here.
function HandleEvent as V ()
	select
		case evt = "link1"
			
		case evt = "link2"
			
		case evt = "link3"
		
		case evt = "link4"

	end select
end function

' Add NavBar by overriding the AddNavBar function
function AddNavBar as V ()
	cp.html = cp.html + PPPhtml%XBM
		HMM<nav class="navbar navbar-expand-lg navbar-light" style="background-color: #e3f2fd;">
		<a class="navbar-brand" href="#">NorthWind</a>
		<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation">
			<span class="navbar-toggler-icon"></span>
		</button>
		<div class="collapse navbar-collapse" id="navbarNavDropdown">
			<ul class="navbar-nav">
				<li class="nav-item active">
					<a class="nav-link" href="javascript:xDialogEvent('link1')">Link1</a>
				</li>
				<li class="nav-item">
					<a class="nav-link" href="javascript:xDialogEvent('link2')">Link2</a>
				</li>
				<li class="nav-item">
					<a class="nav-link" href="javascript:xDialogEvent('link3')">Link3</a>
				</li>
				<li class="nav-item">
					<a class="nav-link" href="javascript:xDialogEvent('link4')">Link4</a>
				</li>
			</ul>
		</div>
		</nav>HMM
	XBM%html%	
end function
end class
XBM
Xbasic

XBM' Instantiate and open xds::products.
dim xdsProducts as xds::productsRN
FUNCxdsProducts.Open()

' Instantiate and open xds::employees.
dim xdsEmployees as xds::employeesRN
FUNCxdsEmployees.Open()
XBM

On the parent class, we added the necessary Javascripts and CSS. We also provided a mechanism for adding a navigation bar.

On the child classes, all we need to do is add our HTML code, handle events, and add a navigation bar if needed.

Adding Window Buttons

Window buttons can be added to an instance of the a5wd::modeless::xdialog but the best way to do this is by subclassing so that all child classes automatically have the window buttons.

Example

Download Workspace

Xbasic

XBM' PARENT CLASS
'
define class a5wd_parent::xds inherits a5wd::xdialog::modelessRN
'
' This is the function that is called before the xdialog is created.
function OnInitialize as V ()
	self.XdTitle = "Parent"
	self.Width = "70%"
	self.Height = "70%"
	
	cp.html = PPPhtml%XBM
		HMM<!-- load bootstrap CSS -->
		<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css"> 
		
		<!-- load font-awesome CSS -->
		<link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
		
		<!-- load bootstrap and jquery -->
		<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
		<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js"></script>
		
		<script>
			function max_restore() {
				if($('#max-restore-button i').hasClass('fa-window-maximize')) {
					xDialogEvent('maximize');
				} else {
					xDialogEvent('restore');
				}
			}
		</script>

		<style>
			.window-buttons {
				position: fixed;
				top: 0;
				right: 0;
				z-index: 999;
			}
			.window-buttons button {
				border: 0;
			}
			
			/* remove button box-shadow */
			.btn:focus {
			  box-shadow: none;
			}
			
			/* customize the close-button */
			#close-button {
				color: #6c757d;
			}
			#close-button:hover {
				color: #fff;
			}
		</style>
		
		<div class="btn-group window-buttons" role="group">
			<button type="button" class="btn btn-outline-secondary btn-sm" onclick="xDialogEvent('minimize')"><i class="fa fa-window-minimize"></i></button>
			<button type="button" class="btn btn-outline-secondary btn-sm" id="max-restore-button" onclick="max_restore()"><i class="fa fa-window-maximize"></i></button>
			<button type="button" class="btn btn-outline-danger btn-sm" id="close-button"><i class="fa fa-window-close" onclick="xDialogEvent('close')"></i></button>
		</div>HMM									
	XBM%html%
				
	' Add Navigation Bar
	FUNCself.AddNavBar()
	
	' Call Initialize().	
	FUNCself.Initialize()
end function

' We separated the NavBar so it can be overriden by a child class.
function AddNavBar as V ()
	cp.html = cp.html + PPPhtml%XBM
		HMM<nav class="navbar navbar-expand-lg navbar-light" style="background-color: #e3f2fd;">
		<a class="navbar-brand" href="#">NorthWind</a>
		<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation">
			<span class="navbar-toggler-icon"></span>
		</button>
		<div class="collapse navbar-collapse" id="navbarNavDropdown">
			<ul class="navbar-nav">
				<li class="nav-item active">
					<a class="nav-link" href="javascript:xDialogEvent('link1')">Link1</a>
				</li>
				<li class="nav-item">
					<a class="nav-link" href="javascript:xDialogEvent('link2')">Link2</a>
				</li>
				<li class="nav-item">
					<a class="nav-link" href="javascript:xDialogEvent('link3')">Link3</a>
				</li>
			</ul>
		</div>
		</nav>HMM
	XBM%html%
end function

' Add more MustOverride functions as needed.
'
' We used here two window event functions of the a5wd::xdialog::modeless class to change the icon of the max-restore-button.
'
function AfterRestore as V ()
	cp.SetInnerHtml("max-restore-button", "<i class=\DQfa fa-window-maximize\DQ></i>")
end function

function AfterMaximize as V ()
	cp.SetInnerHtml("max-restore-button", "<i class=\DQfa fa-window-restore\DQ></i>")
end function

' Handle OnReady here.
function OnReady as V ()
	'
	' Reset max-restore-button icon.
	if FUNCself.IsMaximized()
		FUNCself.AfterMaximize()
	else
		FUNCself.AfterRestore()
	end if
	
	' Call Ready.
	FUNCself.Ready()
end function
end class
XBM

Create a child class that inherits from a5wd_parent::xds.

Xbasic

XBM' CHILD CLASS 1
'
define class xds::products inherits a5wd_parent::xdsRN
'
' Add HTML code here.
function Initialize as V ()
	self.XdTitle = "Products"
	
	dim html as CRN
	html = PPPhtml%XBM
		HMM<div class="container-fluid">
			<h1 style="text-align:center; color:#ccc; margin-top:150px">Put your HTML content here.</h1>
			<p style="text-align:center; color: #888; margin-top:50px">This xdialog inherited the navigation bar and the window buttons from a5wd_parent::xds</p>
		</div>HMM
	XBM%html%
	
	cp.html = cp.html + html
end function

' Code to execute when state is "ready".
function Ready as V ()
end function

' Handle events here.
function HandleEvent as V ()
	select
		case evt = "link1"
		
		case evt = "link2"
		
	end select
end function
end class
XBM

Create another child class that inherits from a5wd_parent::xds.

Xbasic

XBM' CHILD CLASS 2
'
define class xds::employees inherits a5wd_parent::xdsRN
'
' Add HTML code here.
function Initialize as V ()
	self.XdTitle = "Employees"
	
	dim html as CRN
	html = PPPhtml%XBM
		HMM<div class="container-fluid">
			<h1 style="text-align:center; color:#ccc; margin-top:150px">Put your HTML content here.</h1>
			<p style="text-align:center; color: #888; margin-top:50px">This xdialog inherited the window buttons from a5wd_parent::xds but overrode the navigation bar.</p>	
		</div>HMM
	XBM%html%
	
	cp.html = cp.html + html
end function

' Code to execute when state is "ready".
function Ready as V ()
end function

' Handle events here.
function HandleEvent as V ()
	select	
		case evt = "link1"
		
	end select
end function

' Add NavBar by overriding the AddNavBar function.
function AddNavBar as V ()
	cp.html = cp.html + PPPhtml%XBM
		HMM<nav class="navbar navbar-expand-lg navbar-light bg-light">
		<a class="navbar-brand" href="#">NorthWind</a>
		<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation">
			<span class="navbar-toggler-icon"></span>
		</button>
		<div class="collapse navbar-collapse" id="navbarNavDropdown">
			<ul class="navbar-nav">
				<li class="nav-item active">
					<a class="nav-link" href="javascript:xDialogEvent('link1')">Link1</a>
				</li>
			</ul>
		</div>
		</nav>HMM
	XBM%html%	
end function
end class
XBM

Create another child class that inherits from a5wd_parent::xds.

Xbasic

XBM' CHILD CLASS 3
'
define class xds::customers inherits a5wd_parent::xdsRN
'
' Add HTML code here.
function Initialize as V ()
	self.XdTitle = "customers"
	
	dim html as CRN
	html = PPPhtml%XBM
				HMM<div class="container-fluid">
					<h1 style="text-align:center; color:#ccc; margin-top:150px">Put your HTML content here.</h1>
					<p style="text-align:center; color: #888; margin-top:50px">This xdialog inherited the window buttons from a5wd_parent::xds but overrode the navigation bar with nothing to remove it.</p>	
				</div>HMM
			XBM%html%
	cp.html = cp.html + html
end function

' Code to execute when state is "ready".
function Ready as V ()
end function

' Handle events here.
function HandleEvent as V ()
end function

' Override the navigation bar with nothing to exclude it.
function AddNavBar as V ()
end function
end class
XBM
Xbasic

XBM' Instantiate and open xds::products.
' This xdialog inherited the navigation bar and the window buttons.
dim xdsProducts as xds::productsRN
FUNCxdsProducts.Open()

' Instantiate and open xds::employees.
' This xdialog inherited the window buttons but overrode the navigation bar.
dim xdsEmployees as xds::employeesRN
FUNCxdsEmployees.Open()

' Instantiate and open xds::customers.
' This xdialog inherited the window buttons but overrode the navigation bar with nothing to exclude it.
dim xdsCustomers as xds::customersRN
FUNCxdsCustomers.Open()
XBM

On the parent class, we added the necessary Javascripts and CSS. We also added window buttons and a navigation bar.

On the child classes, all we need to do is add our HTML code, handle events, and override the navigation bar if needed. Through inheritance, we saved time writing codes for our child classes. We no longer need to write code for adding Javascripts and CSS, window buttons, and navigation bar because these are already inherited from the parent class.

Passing Data to an Xdialog

Data can be passed to an xdialog instance that is declared as global.

Example 1

Download Workspace

Xbasic

XBM' autoexec (script)
'
' Delete any existing instance.
delete xdsMyDialog 

' Create a global instance and set xdialog title.
dim global xdsMyDialog as P =RN new a5wd::xdialog::MFmodeless("My Dialog")
'
' Set HTML content.
xdsMyDialog.cp.html = <<%html%XBM
	HMM<style> div, button { margin: 20px 0 0 100px; } </style>
	<form>
		<div>
			<label for="first_name_fld">First Name:</label><br>
			<input type="text" id="first_name_fld">
		</div>
		<div>
			<label for="last_name_fld">Last Name:</label><br>
			<input type="text" id="last_name_fld">
		</div>
		<button type="button" onclick="xDialogEvent('submit')">Submit</button>
		<p style="text-align:center">Run the script 'pass_vars' to set field values.</p>
	</form>HMM
XBM%html%

' Set InitializeCode.
xdsMyDialog.InitializeCode = <<%code%
	'
	' Create instance variables.
	dim self.pntr.first_name as C =RN ""
	dim self.pntr.last_name as C =RN ""
%code%

' Set EventCode.
xdsMyDialog.EventCode = <<%code%
	'
	' Set field values using the instance variable values.
	if evt = "set_field_values"
		cp.SetValue("first_name_fld", self.pntr.first_name)
		cp.SetValue("last_name_fld", self.pntr.last_name)
		
	elseif evt = "submit"
		dim new_user as C =RN cp.GetValue("first_name_fld") + " " + cp.GetValue("last_name_fld")
		ui_msg_box("Xbasic", "Welcome " + new_user + ".")	
	end if
%code%
'
' Open the xdialog.
xdsMyDialog.Open("4", "2.6")
XBM
Xbasic

XBM' pass_data (script)
'
' Pass data by setting instance variable values.
xdsMyDialog.pntr.first_name = "Steven"
xdsMyDialog.pntr.last_name = "McDonald"
'
' Fire "set_field_values" event.
xdsMyDialog.FireEvent("set_field_values")
XBM

Example 2

Download Workspace

Xbasic

XBM' xds::my_dialog (class)
'
define class xds::my_dialog inherits a5wd::xdialog::modelessRN
'
' Create instance variables
dim first_name as CRN
dim last_name as CRN

function Initialize as V ()
	self.XdTitle = "My Dialog"
	self.Width = "4"
	self.Height = "2.6"
	
	' Set HTML content.
	self.cp.html = <<%html%XBM
		HMM<style> div, button { margin: 20px 0 0 100px; } </style>
		<form>
			<div>
				<label for="first_name_fld">First Name:</label><br>
				<input type="text" id="first_name_fld">
			</div>
			<div>
				<label for="last_name_fld">Last Name:</label><br>
				<input type="text" id="last_name_fld">
			</div>
			<button type="button" onclick="xDialogEvent('submit')">Submit</button>
			<p style="text-align:center">Run the script 'pass_data' to set field values.</p>
		</form>HMM
	XBM%html%
FUNCend function 

function Ready as V ()
	MFself.set_field_values()
end function

function HandleEvent as V ()
	if evt = "submit"
		dim new_user as C =RN cp.GetValue("first_name_fld") + " " + cp.GetValue("last_name_fld")
		ui_msg_box("Xbasic", "Welcome " + new_user + ".")	
	end if	
end function

function set_field_values as V ()
	'
	cp.SetValue("first_name_fld", self.first_name)
	cp.SetValue("last_name_fld", self.last_name)
end function
end class
XBM
Xbasic

XBM' autoexec
'
' Delete any existing instance
delete xdsMyDialog
'
dim global xdsMyDialog as xds::my_dialogRN
'
xdsMyDialog.first_name = "Richard"
xdsMyDialog.last_name = "Chamberlain"

xdsMyDialog.Open()
XBM
Xbasic

XBM' pass_data (script)
'
xdsMyDialog.first_name = "Mary"
xdsMyDialog.last_name = "Tyler"

MFxdsMyDialog.set_field_values()
XBM

Xdialog Interaction

Xdialogs can interact with each other if they are declared as global.

Example

Download Workspace

Xbasic

XBM' xds::employees
'
define class xds::employees inherits a5wd::xdialog::modelessRN
'
' Create instance variables.
dim id as CRN
dim first_name as CRN
dim last_name as CRN
'
' Add HTML code here.
function Initialize as V ()
	self.XdTitle = "Employees"
	self.Width = "70%"
	self.Height = "70%"
	
	cp.html = PPPhtml%XBM
		HMM<!-- load bootstrap CSS -->
		<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" />

		<style> .hidden { display: none; } </style>

		<!-- load jquery and bootstrap from CDN -->
		<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>

		<div class="container-fluid">
			<h4 class="mt-5">Try editing the records.</h4>
			<table id="datatable" class="table table-sm table-striped table-dark mt-5">
				<thead>
					<tr>
						<th>First Name</th>
						<th>Last Name</th>
						<th> </th>
					</tr>
				</thead>
				<tbody>
				</tbody>
			</table>
		</div>

		<script>
			function edit(id) {
				var first_name = $('#row' + id).find('td:nth-child(1)').html();
				var last_name = $('#row' + id).find('td:nth-child(2)').html();
				xDialogEvent('edit|' + id + '|' + first_name + '|' + last_name);
			}
		</script>HMM
	XBM%html%
end function

' Code to execute when state is "ready".
function Ready as V ()
	' LetOQs simulate fetching data from database.	
	dim tbody as C =RN "<tr id=\DQrow1\DQ><td>Anthony</td><td>Miller</td><td><button type=\DQbutton\DQ class=\DQbtn btn-secondary btn-sm\DQ onclick=\DQedit(OQ1OQ)\DQ>Edit</button></td></tr>" +\
					 "<tr id=\DQrow2\DQ><td>James</td><td>Norton</td><td><button type=\DQbutton\DQ class=\DQbtn btn-secondary btn-sm\DQ onclick=\DQedit(OQ2OQ)\DQ>Edit</button></td></tr>" +\
					 "<tr id=\DQrow3\DQ><td>Randy</td><td>Green</td><td><button type=\DQbutton\DQ class=\DQbtn btn-secondary btn-sm\DQ onclick=\DQedit(OQ3OQ)\DQ>Edit</button></td></tr>" +\
					 "<tr id=\DQrow4\DQ><td>Jacob</td><td>Brown</td><td><button type=\DQbutton\DQ class=\DQbtn btn-secondary btn-sm\DQ onclick=\DQedit(OQ4OQ)\DQ>Edit</button></td></tr>"
			
	' Put the data on the tableOQs body.
	cp.ExecuteJavascript("$(OQ#datatable tbodyOQ).html(OQDQ + js_escape(tbodyCP + DQOQCP")
end function

' Handle events here.
function HandleEvent as V ()
	select
		' edit		
		case *first(evt, "edit|")
			' Open the xdsEditEmployee dialog if not already open. Since we are opening it in this session, this is a child of this dialog.
			if FUNCxdsEditEmployee.Exists() = .f.
				'
				' Extract the passed values. Save them using the instance variables.
				self.id = word(evt, 2, "|")
				self.first_name = word(evt, 3, "|")
				self.last_name = word(evt, 4, "|")
				'
				' Open the child dialog.
				FUNCxdsEditEmployee.Open()
			end if
	end select
end function
end class
XBM
Xbasic

XBM' xds::edit_employee
'
define class xds::edit_employee inherits a5wd::xdialog::modelessRN
'
' Add HTML code here.
function Initialize as V ()
	self.XdTitle = "Edit Employee"
	self.Width = "5"
	self.Height = "3.3"
	
	dim html as CRN = <<%html%XBM
		HMM<!-- load bootstrap CSS -->
		<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" />

		<!-- load jquery and bootstrap from CDN -->
		<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>

		<div class="container-fluid">
			<form>
				<div class="form-group mt-5">
					<label for="first_name_fld">First Name</label>
					<input type="text" class="form-control" id="first_name_fld">
				</div>
				<div class="form-group">
					<label for="last_name_fld">Last Name</label>
					<input type="text" class="form-control" id="last_name_fld">
				</div>
				<button type="button" onclick="submit_form()" class="btn btn-outline-primary float-right">Submit</button>
				<button type="button" onclick="xDialogEvent('close')" class="btn btn-outline-secondary mr-3 float-right">Cancel</button>
			</form>	
		</div>

		<script>
			function submit_form() {
				var first_name = $('#first_name_fld').val();
				var last_name = $('#last_name_fld').val();
				xDialogEvent('submit|' + first_name + '|' + last_name);
			}
		</script>HMM
	XBM%html%
			
	dim app_path as C =RN "a5file://" + FUNCa5.Get_Path()	
	'
	html = strtran(html, "{AppPath}", app_path)	
	cp.html = html			
end function

' Code to execute when state is "ready".
function Ready as V ()
	' Set field values using the variables of the parent dialog.
	cp.SetValue("first_name_fld", xdsEmployees.first_name)
	cp.SetValue("last_name_fld", xdsEmployees.last_name)
end function

' Handle other events here.
function HandleEvent as V ()
	select
		' submit		
		case *first(evt, "submit|")
			' Extract passed values.
			dim first_name as C =RN word(evt, 2, "|")
			dim last_name as C =RN word(evt, 3, "|")
			
			dim id as C =RN xdsEmployees.id
			
			' Save data to database.
			' ...

			' If saved, set table values.
			GRSxdsEmployees.cp.ExecuteJavascript(GRE"$QPOQ#row" + id + "OQCP.findQPOQtd:nth-childQP1CPOQCP.htmlQPOQ" + js_escape(first_name) + "OQCP"GRS)GRE
			GRSxdsEmployees.cp.ExecuteJavascript(GRE"$QPOQ#row" + id + "OQCP.findQPOQtd:nth-childQP2CPOQCP.htmlQPOQ" + js_escape(last_name) + "OQCP"GRS)GRE

			' Close this child dialog.
			FUNCself.Close()
	end select
end function
end class
XBM
Xbasic

XBM' autoexec
'
' Delete any existing instances.
delete xdsEmployees
delete xdsEditEmployee

' Declare xdialog instances as global so they can interact with each other.
dim global xdsEmployees as xds::employeesRN
dim global xdsEditEmployee as xds::edit_employeeRN

' Open the "employees" xdialog.
FUNCxdsEmployees.Open()
XBM

DBF Interaction

Modularity is one of the advantages of object-oriented programming. By using classes, we can organize our code better than ever before. This leads to easier troubleshooting if something goes wrong. For example, if the employee update broke down, the problem must be on the "update_record" function inside the "employees" class. Let's apply this concept to our example below by doing the following.

1. Create a class for each table using the table name as reference.
2. Put all necessary table query functions inside of each table class.
3. Create a class for our xdialog that inherits from a5wd::xdialog::modeless.
4. Instantiate the classes and declare each instance as global.
5. Handle events inside our xdialog class and call necessary functions needed by our application.

Example

Download Workspace

Xbasic

XBM' autoexec
'
' Delete any existing instances.
delete dbfEmployees
delete dbfDepartments
delete setEmpDept
'
' Declare instances as global.
dim global dbfEmployees as dbf::employees
dim global dbfDepartments as dbf::departments
dim global setEmpDept as set::emp_dept
'
' Open the dialog
dim global xdsEmployees as xds::employeesRN
FUNCxdsEmployees.Open()
XBM
Xbasic

XBM' dbf::employees
'
define class dbf::employees
'
dim TableName as C =RN "employees"
'
' select record
function select_record as V (cp as P, id as C)
	dim tbl as P =RN table.open(self.TableName)
	dim qry as P =RN GRStbl.query_create(GRE"NT", "id =" + id)GRE
	
	if qry.records_get() > 0
		cp.SetValue("id_fld", convert_type(tbl.id, "C"GP)
		cp.SetValue("first_name_fld", GRSrtrim(GREtbl.first_nameGP)
		cp.SetValue("last_name_fld", GRSrtrim(GREtbl.last_nameGP)
		cp.SetValue("hire_date_fld", GRSdtoc(GREtbl.hire_dateGP)
		
		cp.ExecuteJavascript("$(OQ#is_active_fldOQ).prop(OQcheckedOQ," + GRSif(GREtbl.is_active, "true", "false"GRS)GRE + "CP")
		cp.ExecuteJavascript("$(\DQinput[name=gender_fld][value=OQ" + GRSrtrimQPGREtbl.genderGP + "OQ]\DQCP.propQPOQcheckedOQ, trueCP")
		
		cp.SetValue("dept_id_fld", GRSrtrim(GREtbl.dept_idGP)
		
		cp.ExecuteJavascript("$QPOQ#dlg_recordOQCP.modalQPOQshowOQCP")
	else
		ui_msg_box("Not Found", "Record not found.", UI_STOP_SYMBOL+UI_OK)
	end if
	
	qry.drop()
	tbl.close()
end function
'
' update record
function update_record as L (cp as P, ptr as P)
	on error goto update_record_eh		
		dim tbl as P =RN table.open(self.TableName)
		dim qry as P =RN tbl.query_create("NT", "id = " + ptr.id)
		dim commit_flag as L =RN .t.

		if qry.records_get() > 0
			tbl.fetch_first()
			tbl.change_begin()
			tbl.first_name = ptr.first_name
			tbl.last_name = ptr.last_name
			tbl.hire_date = ptr.hire_date
			tbl.is_active = ptr.is_active
			tbl.gender = ptr.gender
			tbl.dept_id = ptr.dept_id
			tbl.change_end(commit_flag)
		else
			ui_msg_box("No Record", "Record not found.",UI_STOP_SYMBOL+UI_OK)
		end if
		
		qry.drop()
		tbl.close()
		update_record = commit_flag
	end 
	
	update_record_eh:
		ui_msg_box("Error", GRSerror_text_getQPerror_code_getQPCPCPGRE,UI_STOP_SYMBOL+UI_OK)
		commit_flag = .f.
		resume next
end function
'
' insert record
function insert_record as L (cp as P, ptr as P)
	on error goto insert_record_eh		
		dim tbl as P =RN table.open(self.TableName)
		dim commit_flag as L =RN .t.

		tbl.enter_begin()
		tbl.first_name = ptr.first_name
		tbl.last_name = ptr.last_name
		tbl.hire_date = ptr.hire_date
		tbl.is_active = ptr.is_active
		tbl.gender = ptr.gender
		tbl.dept_id = ptr.dept_id
		tbl.enter_end(commit_flag)

		FUNCtbl.close()		
		insert_record = commit_flag
	end 
	
	insert_record_eh:
		ui_msg_box("Error", GRSerror_text_getQPerror_code_getQPCPCPGRE,UI_STOP_SYMBOL+UI_OK)
		commit_flag = .f.
		resume next
end function
'
' delete record
function delete_record as L (cp as P, id as C)
	on error goto delete_record_eh
		dim tbl as P =RN table.open(self.TableName)
		dim qry as P =RN tbl.query_create("NT", "id = " + id)	
		
		if qry.records_get() > 0
	        tbl.change_begin(.t.)	
			tbl.delete()
			tbl.change_end(.t.)
			delete_record = .t.
		end if	
	end
	
	delete_record_eh:
		ui_msg_box("Error", GRSerror_text_getQPerror_code_getQPCPCPGRE,UI_STOP_SYMBOL+UI_OK)
		delete_record = .f.
end function
end class
XBM
Xbasic

XBM' dbf::departments
'
define class dbf::departmentsRN
'
dim TableName as C = "departments"
'
' set dropdown options
function set_html_options as V (cp as P)
	dim tbl as P =RN table.open(self.TableName)
	dim options as C =RN ""
	
	tbl.fetch_first()
	while .not. tbl.fetch_eof()
		options = options + "<option value=\DQ" + tbl.dept_id + "\DQ>" + tbl.dept_name + "</option>"
		tbl.fetch_next()
	end while
	
	tbl.close()
	
	cp.SetInnerHtml("dept_id_fld", options)
end function
end class
XBM
Xbasic

XBM' set::emp_dept
'
define class set::emp_deptRN
'
dim set_name as C =RN "emp_dept"
dim primary_table_name as C =RN "employees"
'
' populate datatable
function set_datatable as V (cp as P, filter_expression = DQDQ, order_expression = DQDQ)
'
	dim args as sql::Argument
	dim sptr as P =RN GRSset.open_session(GREself.set_nameGP
	
	dim ptbl as P =RN GRSeval(GRE"sptr." + primary_table_nameGP
	
	dim qry as P =RN GRSptbl.query_create(GRE"NT", filter_expression, order_expression, argsGP
	GRSsptr.fetch_first()GRE
	
	dim tbody as C =RN ""
	while .not. GRSsptr.fetch_eof()GRE
		tbody = tbody + "<tr>" +\
							  "<td>" + rtrim(ptbl.first_name) + "</td>" +\
							  "<td>" + rtrim(ptbl.last_name) + "</td>" +\
							  "<td>" + dtoc(ptbl.hire_date) + "</td>" +\
							  "<td>" + GRSif(GREptbl.is_active, "Yes", "No"GP + "</td>" +\
							  "<td>" + GRSif(GREptbl.gender="M", "Male", "Female"GP + "</td>" +\
							  "<td>" + rtrim(sptr.departments.dept_name) + "</td>" +\
							  "<td><button type=\DQbutton\DQ class=\DQbtn btn-secondary btn-sm\DQ onclick=\DQedit_recordQPOQ" + convert_type(ptbl.id, "C") + "OQCP\DQ>Edit</button></td>" +\
						  "</tr>"
	    GRSsptr.fetch_next()GRE
	end while

	GRSptbl.query_detach()GRE
	GRSsptr.close()GRE
	
	cp.ExecuteJavascript("$(OQ#datatable tbodyOQCP.htmlQPOQ" + js_escape(tbody) + "OQCP"GP
end function
end class
XBM
Xbasic

XBM' xds::employees
'
define class xds::employees inherits a5wd::xdialog::modeless
'
' Create instance variables.
dim id as CRN
dim first_name as CRN
dim last_name as CRN
'
' Add HTML code here.
function Initialize as V ()
	self.XdTitle = "Employees"
	self.Width = "70%"
	self.Height = "70%"
	cp.url = FUNCa5.Get_Path() + "\html\my_dialog.html"
end function

' Code to execute when state is "ready".
function Ready as V ()
	MFsetEmpDept.set_datatable(cp)
	MFdbfDepartments.set_html_options(cp)	
end function

' Handle events here.
function HandleEvent as V ()
	select
		' edit_record		
		case *first(evt, "edit_record|")
			dim id as C =RN word(evt, 2, "|")
			MFdbfEmployees.select_record(cp, id)
			
		' update_record		
		case *first(evt, "update_record|")
			dim ptr as PRN
			dim ptr.first_name as C =RN word(evt, 2, "|")
			dim ptr.last_name as C =RN word(evt, 3, "|")
			dim ptr.hire_date as D =RN ctod(word(evt, 4, "|")GP
			dim ptr.is_active as L =RN GRSif(GREword(evt, 5, "|") = "1", .t., .f.GP
			dim ptr.gender as C =RN word(evt, 6, "|")
			dim ptr.dept_id as C =RN word(evt, 7, "|")
			dim ptr.id as C =RN word(evt, 8, "|")
			
			if MFdbfEmployees.update_record(cp, ptr)
				MFsetEmpDept.set_datatable(cp)
				cp.ExecuteJavascript("$QPOQ#dlg_recordOQCP.modalQPOQhideOQCP")
			end if
			
		' insert_record		
		case *first(evt, "insert_record|")
			dim ptr as PRN
			dim ptr.first_name as C =RN word(evt, 2, "|")
			dim ptr.last_name as C =RN word(evt, 3, "|")
			dim ptr.hire_date as D =RN ctod(word(evt, 4, "|")GP
			dim ptr.is_active as L =RN GRSif(GREword(evt, 5, "|") = "1", .t., .f.GP
			dim ptr.gender as C =RN word(evt, 6, "|")
			dim ptr.dept_id as C =RN word(evt, 7, "|")
			
			if MFdbfEmployees.insert_record(cp, ptr)
				MFsetEmpDept.set_datatable(cp)
				cp.ExecuteJavascript("$QPOQ#dlg_recordOQCP.modalQPOQhideOQCP")
			end if
			
		' delete_record		
		case *first(evt, "delete_record|")
			dim id as C =RN word(evt, 2, "|")
			if MFdbfEmployees.delete_record(cp, id)
				MFsetEmpDept.set_datatable(cp)
				cp.ExecuteJavascript("$QPOQ#dlg_recordOQCP.modalQPOQhideOQCP")				
			end if
	end select
end function
end class
XBM

AlphaDAO Interaction

One cool thing I love with AlphaDAO is its portability. Once our code is done, it will work across all supported databases. If we want to move to another database, all we need to do is change the connection string.

AlphaDAO supports Microsoft Access, DB2, Excel, GoogleSheet, MariaDB, MongoDB, MySQL, ODBC, Oracle, OracleLite, Paradox, PostgreSQL, SQL Server, SQLite, StaticJSON, OData, Quickbooks, and more.

Example

Download Workspace

Xbasic

XBM' autoexec
'
' In this example, we used a Microsoft Access database file that is located inside our workspace.
' We used a5.Get_Path() in our connection string so that it always points to our workspace.

' Delete any existing instances.
delete tblEmployees
delete tblDepartments
delete xdsEmployees

dim global gConn as C =RN "{A5API=Access,FileName=OQ" + FUNCa5.Get_Path() + "\test_database.accdbOQ}"
'
' If a named connection is used, our connection string will be something like;
' dim global gConn as C = "::Name::MyConnectionName"

' Instantiate our classes.
dim global tblEmployees as tbl::employeesRN
dim global tblDepartments as tbl::departmentsRN

dim global xdsEmployees as xds::employeesRN
FUNCxdsEmployees.Open()
XBM
Xbasic

XBM' tbl::employees
'
define class tbl::employeesRN
'
dim TableName as C =RN "employees"
dim ConnectionString as C =RN gConn
'
function set_datatable as V (cp as P)
	on error goto set_datatable_eh	
		dim error_message as C =RN ""
		dim args as sql::Arguments
		
		' Here, we joined the 2 tables using SELECT statement. 
		' Another way is to create a view and then query that view.
		'
		dim sql_command as C =RN "SELECT *, d.dept_name as dept " +\
							   "FROM " + self.TableName + " e " +\
							   "LEFT JOIN departments d ON e.dept_id = d.dept_id"
		    
	 	' connect to database
	 	dim cn as sql::ConnectionRN
		if .not. MFcn.open(self.ConnectionString)
			if cn.CallResult.text <> ""
				error_message = cn.CallResult.text
			else
				error_message = "Connection failed."
			end if
			goto set_datatable_eh
		end if
		
		' execute query
		if .not. MFcn.execute(sql_command, args)
			error_message = cn.CallResult.text
			if error_message = ""
				error_message = "Execution failed."
				goto set_datatable_eh
			end if
		else
			dim rs as sql::ResultSet =RN cn.ResultSet
			dim tbody as C =RN ""
			while FUNCrs.NextRow()
				tbody = tbody + "<tr>" +\
									  "<td>" + rtrim(GRSrs.Data(GRE"first_name")GP + "</td>" +\
									  "<td>" + rtrim(GRSrs.Data(GRE"last_name")GP + "</td>" +\
									  "<td>" + dtoc(GRSrs.Data(GRE"hire_date")GP + "</td>" +\
									  "<td>" + GRSif(rs.Data(GRE"is_active"GP, "Yes", "No"GP + "</td>" +\
									  "<td>" + GRSif(rs.Data(GRE"gender"GP = "M", "Male", "Female"GP + "</td>" +\
									  "<td>" + rtrim(GRSrs.Data(GRE"dept")GP + "</td>" +\
									  "<td><button type=\DQbutton\DQ class=\DQbtn btn-secondary btn-sm\DQ onclick=\DQedit_record(OQ" + convert_type(GRSrs.Data(GRE"id"), "C"GP + "OQ)\DQ>Edit</button></td>" +\
								  "</tr>"			
			end while	
			cp.ExecuteJavascript("$QPOQ#datatable tbodyOQCP.htmlQPOQ" + js_escape(tbody) + "OQCP"GP
		end if	
		
		if cn.IsOpen
			FUNCcn.Close()
		end if	
	end
	
	' handle error
	set_datatable_eh:
		if cn.IsOpen
			FUNCcn.Close()
		end if
		if error_message = ""
			error_message = GRSerror_text_get(error_code_get())GRE
		end if
		ui_msg_box("Error", error_message, UI_STOP_SYMBOL+UI_OK)
end function
'
' select record
function select_record as L (cp as P, args as sql::Arguments)
	on error goto select_record_eh
		dim retval as L =RN .f.
		dim error_message as C =RN ""
		
		dim sql_command as C =RN "SELECT * FROM " + self.TableName + " WHERE id = :id"
		    
	 	' connect to database
	 	dim cn as sql::ConnectionRN
		if .not. MFcn.open(self.ConnectionString)
			if cn.CallResult.text <> ""
				error_message = cn.CallResult.text
			else
				error_message = "Connection failed."
			end if
			goto select_record_eh
		end if
		
		' execute query
		if .not. MFcn.execute(sql_command, args)
			error_message = cn.CallResult.text
			if error_message = ""
				error_message = "Execution failed."
				goto select_record_eh
			end if
		else
			dim rs as sql::ResultSet =RN cn.Resultset
			cp.SetValue("id_fld", convert_type(GRSrs.Data(GRE"id"), "C"GRS))GRE
			cp.SetValue("first_name_fld", rtrim(GRSrs.Data(GRE"first_name")GRS))GRE
			cp.SetValue("last_name_fld", rtrim(GRSrs.Data(GRE"last_name")GRS))GRE
			cp.SetValue("hire_date_fld", dtoc(GRSrs.Data(GRE"hire_date")GRS))GRE
			
			cp.ExecuteJavascript("$QPOQ#is_active_fldOQCP.propQPOQcheckedOQ," + GRSif(rs.Data(GRE"is_active"GP, "true", "false"GP + "CP")
			cp.ExecuteJavascript("$QP\DQinput[name=gender_fld][value=OQ" + rtrim(GRSrs.Data(GRE"gender")GP + "OQ]\DQCP.propQPOQcheckedOQ, trueCP"GP
			
			cp.SetValue("dept_id_fld", rtrim(GRSrs.Data(GRE"dept_id")GRS))GRE
			
			cp.ExecuteJavascript("$QPOQ#dlg_recordOQCP.modalQPOQshowOQCP")
			retval = .t.
		end if
		if cn.IsOpen
			FUNCcn.Close()
		end if
		select_record = retval	
	end
	
	' handle error
	select_record_eh:
		if cn.IsOpen
			FUNCcn.Close()
		end if
		if error_message = ""
			error_message = GRSerror_text_get(error_code_get())GRE
		end if
		ui_msg_box("Error", error_message, UI_STOP_SYMBOL+UI_OK)
		select_record = .f.			
end function
'
' update record
function update_record as L (cp as P, args as sql::Arguments)
	on error goto update_record_eh	
		dim retval as L =RN .f.
		dim error_message as C =RN ""
		
		dim sql_command as C =RN "UPDATE " + self.TableName + " " +\
							   "SET " +\
							    	"first_name = :first_name, " +\
							    	"last_name = :last_name, " +\
							    	"hire_date = :hire_date, " +\
							    	"is_active = :is_active, " +\
							    	"gender = :gender, " +\
							    	"dept_id = :dept_id " +\
							    "WHERE id = :id"
  
	 	' connect to database
	 	dim cn as sql::ConnectionRN
		if .not. MFcn.open(self.ConnectionString)
			if cn.CallResult.text <> ""
				error_message = cn.CallResult.text
			else
				error_message = "Connection failed."
			end if
			goto update_record_eh
		end if
		
		' execute query
		if .not. MFcn.execute(sql_command, args)
			error_message = cn.CallResult.text
			if error_message = ""
				error_message = "Execution failed."
				goto update_record_eh
			end if
		elseif cn.CallResult.RowsAffected = 1
			retval = .t.
		end if
		if cn.IsOpen
			FUNCcn.Close()
		end if
		update_record = retval	
	end
	
	' handle error
	update_record_eh:
		if cn.IsOpen
			FUNCcn.Close()
		end if
		if error_message = ""
			error_message = GRSerror_text_get(error_code_get())GRE
		end if
		ui_msg_box("Error", error_message, UI_STOP_SYMBOL+UI_OK)
		update_record = .f.
end function
'
' insert record
function insert_record as L (cp as P, args as sql::Arguments)
	on error goto insert_record_eh	
		dim retval as L =RN .f.
		dim error_message as C =RN ""
		
		dim sql_command as C =RN "INSERT INTO " + self.TableName + " " +\
							   "(first_name, last_name, hire_date, is_active, gender, dept_id) " +\
							   "VALUES (:first_name, :last_name, :hire_date, :is_active, :gender, :dept_id)"
  
	 	' connect to database
	 	dim cn as sql::ConnectionRN
		if .not. GRScn.open(GREself.ConnectionStringGP
			if cn.CallResult.text <> ""
				error_message = cn.CallResult.text
			else
				error_message = "Connection failed."
			end if
			goto insert_record_eh
		end if
		
		' execute query
		if .not. MFcn.execute(sql_command, args)
			error_message = cn.CallResult.text
			if error_message = ""
				error_message = "Execution failed."
				goto insert_record_eh
			end if
		elseif cn.CallResult.RowsAffected = 1
			retval = .t.
		end if
		if cn.IsOpen
			FUNCcn.Close()
		end if
		insert_record = retval	
	end
	
	' handle error
	insert_record_eh:
		if cn.IsOpen
			FUNCcn.Close()
		end if
		if error_message = ""
			error_message = GRSerror_text_get(error_code_get())GRE
		end if
		ui_msg_box("Error", error_message, UI_STOP_SYMBOL+UI_OK)
		insert_record = .f.
end function
'
' delete record
function delete_record as L (cp as P, args as sql::Arguments)
	on error goto delete_record_eh	
		dim retval as L =RN .f.
		dim error_message as C =RN ""
		
		dim sql_command as C =RN "DELETE FROM " + self.TableName + " WHERE id = :id"
  
	 	' connect to database
	 	dim cn as sql::ConnectionRN
		if .not. MFcn.open(self.ConnectionString)
			if cn.CallResult.text <> ""
				error_message = cn.CallResult.text
			else
				error_message = "Connection failed."
			end if
			goto delete_record_eh
		end if
		
		' execute query
		if .not. MFcn.execute(sql_command, args)
			error_message = cn.CallResult.text
			if error_message = ""
				error_message = "Execution failed."
				goto delete_record_eh
			end if
		elseif cn.CallResult.RowsAffected = 1
			retval = .t.
		end if
		if cn.IsOpen
			FUNCcn.Close()
		end if
		delete_record = retval	
	end
	
	' handle error
	delete_record_eh:
		if cn.IsOpen
			FUNCcn.Close()
		end if
		if error_message = ""
			error_message = GRSerror_text_get(error_code_get())GRE
		end if
		ui_msg_box("Error", error_message, UI_STOP_SYMBOL+UI_OK)
		delete_record = .f.
end function
end class
XBM
Xbasic

XBM' tbl::departments
'
define class tbl::departments
'
dim TableName as C =RN "departments"
dim ConnectionString as C =RN gConn
'
' set dropdown options
function set_html_options as V (cp as P)
	on error goto set_html_options_eh	
		dim error_message as C =RN ""
		dim args as sql::ArgumentsRN
		dim sql_command as C =RN "SELECT * FROM " + self.TableName
		    
	 	' connect to database
	 	dim cn as sql::ConnectionRN
		if .not. MFcn.open(self.ConnectionString)
			if cn.CallResult.text <> ""
				error_message = cn.CallResult.text
			else
				error_message = "Connection failed."
			end if
			goto set_html_options_eh
		end if
		
		' execute query
		if .not. MFcn.execute(sql_command, args)
			error_message = cn.CallResult.text
			if error_message = ""
				error_message = "Execution failed."
				goto set_html_options_eh
			end if
		else
			dim rs as sql::ResultSet =RN cn.ResultSet
			dim options as C =RN ""
			while FUNCrs.NextRow()
				options = options + "<option value=\DQ" + rtrim(GRSrs.Data(GRE"dept_id")GP + "\DQ>" + rtrim(GRSrs.Data(GRE"dept_name")GP + "</option>"
			end while
			
			cp.SetInnerHtml("dept_id_fld", options)	
		end if	
		
		if cn.IsOpen
			FUNCcn.Close()
		end if	
	end
	
	' handle error
	set_html_options_eh:
		if cn.IsOpen
			FUNCcn.Close()
		end if
		if error_message = ""
			error_message = GRSerror_text_get(error_code_get())GRE
		end if
		ui_msg_box("Error", error_message, UI_STOP_SYMBOL+UI_OK)
end function
end class
XBM
Xbasic

XBM' xds::employees
'
define class xds::employees inherits a5wd::xdialog::modelessRN
'
' Create instance variables.
dim id as CRN
dim first_name as CRN
dim last_name as CRN
'
' Add HTML code here.
function Initialize as V ()
	self.XdTitle = "Employees"
	self.Width = "70%"
	self.Height = "70%"
	cp.url = FUNCa5.Get_Path() + "\html\my_dialog.html"
end function

' Code to execute when state is "ready".
function Ready as V ()
	MFtblEmployees.set_datatable(cp)
	MFtblDepartments.set_html_options(cp)	
end function

' Handle events here.
function HandleEvent as V ()
	select
		' edit_record		
		case *first(evt, "edit_record|")
			dim args as sql::ArgumentsRN
			args.Add("id", convert_type(word(evt, 2, "|"), "N"GRS))GRE
			MFtblEmployees.select_record(cp, args)
			
		' update_record		
		case *first(evt, "update_record|")
			dim args as sql::ArgumentsRN
			args.Add("first_name", word(evt, 2, "|")GP
			args.Add("last_name", word(evt, 3, "|")GP
			args.Add("hire_date", ctod(word(evt, 4, "|")GRS))GRE
			args.Add("is_active", convert_type(word(evt, 5, "|"), "N"GRS))GRE
			args.Add("gender", word(evt, 6, "|")GP
			args.Add("dept_id", word(evt, 7, "|")GP
			args.Add("id", convert_type(word(evt, 8, "|"), "N"GRS))GRE
			
			if MFtblEmployees.update_record(cp, args)
				MFtblEmployees.set_datatable(cp)
				cp.ExecuteJavascript("$QPOQ#dlg_recordOQCP.modalQPOQhideOQCP")
			end if
			
		' insert_record		
		case *first(evt, "insert_record|")
			dim args as sql::ArgumentsRN
			args.Add("first_name", word(evt, 2, "|")GP
			args.Add("last_name", word(evt, 3, "|")GP
			args.Add("hire_date", ctod(word(evt, 4, "|")GRS))GRE
			args.Add("is_active", convert_type(word(evt, 5, "|"), "N"GRS))GRE
			args.Add("gender", word(evt, 6, "|")GP
			args.Add("dept_id", word(evt, 7, "|")GP
			
			if MFtblEmployees.insert_record(cp, args)
				MFtblEmployees.set_datatable(cp)
				cp.ExecuteJavascript("$QPOQ#dlg_recordOQCP.modalQPOQhideOQCP")
			end if
			
		' delete_record		
		case *first(evt, "delete_record|")
			dim args as sql::ArgumentsRN
			args.Add("id", convert_type(word(evt, 2, "|"), "N"GRS))GRE
			if MFtblEmployees.delete_record(cp, args)
				MFtblEmployees.set_datatable(cp)
				cp.ExecuteJavascript("$QPOQ#dlg_recordOQCP.modalQPOQhideOQCP")				
			end if
	end select
end function
end class
XBM

Showing Reports

The following examples demonstrate some ways on how to display reports in Chrome Control.

Example 1

Download Workspace

Xbasic

XBM' Save the report as PDF and then use the path as url.
'
' Instantiate and set xdialog title.
dim xdsMyDialog as P =RN new a5wd::xdialog::MFmodeless("PDF Report")
xdsMyDialog.cp.url = a5.Get_Path() + "\html\pdf_report.html"

xdsMyDialog.ReadyCode = PPPcode%
	'
	' Create the report.
	dim filename as C =RN "file" + GRSremspecial(time())GRE
	dim fn as C =RN GRSreport.SaveAs(GRE"employees", "PDF", "", "last_name", a5.Get_Path() + "\temp\\" + filename, .f., .f.GP
	xbasic_wait_for_idle()
	ui_yield()
	
	' Set the url of the resource to be used by the object.
	cp.ExecuteJavascript("$QPOQ#pdfOQCP.attrQPOQdataOQ, OQ" + GRSjs_escapeQPGREfnGP + "#toolbar=1&navpanes=0&scrollbar=1OQCP")
%code%
'
' Open the xdialog.
xdsMyDialog.Open("70%", "70%")
XBM

Example 2

Download Workspace

Xbasic

XBM' Export the report as Excel file and then use "sheetJS" to convert it to raw HTML.
'
' Instantiate and set xdialog title.
dim xdsMyDialog as P =RN new a5wd::xdialog::MFmodeless("Report")
xdsMyDialog.cp.url = a5.Get_Path() + "\html\html_report.html"

xdsMyDialog.ReadyCode = PPPcode%
	'
	' Create the report.
	dim filename as C =RN "file" + GRSremspecial(time())GRE
	dim fn as C =RN GRSreport.SaveAs(GRE"employees", "Excel", "", "last_name", a5.Get_Path() + "\temp\\" + filename, .f., .f.GP
	xbasic_wait_for_idle(1)
	ui_yield()
	
	fn = "file:///" + MFstritran(fn, "\\", "\\\")
	
	' Pass it to the Javascript function.
	cp.ExecuteJavascript("create_html_reportQPOQ" + fn + "OQCP")
%code%
'
' Open the xdialog.
xdsMyDialog.Open("70%", "70%")
XBM

Example 3

Download Workspace

Xbasic

XBM' Export the report as Excel file and then use "sheetJS" to convert it to csv.
' The csv data can be manipulated to create a stunning report.
'
' Instantiate and set xdialog title.
dim xdsMyDialog as P =RN new a5wd::xdialog::MFmodeless("Report")
xdsMyDialog.cp.url = a5.Get_Path() + "\html\csv_report.html"

xdsMyDialog.ReadyCode = PPPcode%
	'
	' Create the report.
	dim filename as C =RN "file" + GRSremspecial(time())GRE
	dim fn as C =RN GRSreport.SaveAs(GRE"employees", "Excel", "", "last_name", a5.Get_Path() + "\temp\\" + filename, .f., .f.GP
	xbasic_wait_for_idle(1)
	ui_yield()
	
	fn = "file:///" + MFstritran(fn, "\\", "\\\")
	
	' Pass it to the Javascript function.
	cp.ExecuteJavascript("create_csv_reportQPOQ" + fn + "OQCP")
%code%
'
' Open the xdialog.
xdsMyDialog.Open("70%", "70%")
XBM

Creating SDI Application

A modeless xdialog can be used to create a Single Document Interface (SDI) application.

The trick is to hide Alpha Five before or after the xdialog is shown and then close when the xdialog is closed.

Example

Download Workspace

Xbasic

XBM' autoexec
'
' Delete any existing instances.
delete xdsMyApp

dim global xdsMyApp as xds::my_appRN

' Uncomment to remove window caption.
'xdsMyApp.NoCaption = .t.

' Hide Alpha Five.
FUNCa5.Hide()

' Open the xdialog.
FUNCxdsMyApp.Open()
XBM
Xbasic

XBM' xds::my_app
'
define class xds::my_app inherits a5wd::xdialog::modelessRN
'
' This is the function that is called before the xdialog is created.
function Initialize as V ()
	self.XdTitle = "MyApp"

	' Maximize the window.
	self.Maximized = .t.
	
	cp.url = FUNCa5.Get_Path() + "\html\my_app.html"
end function
'
' We used here two window event functions of the a5wd::xdialog::modeless class to change the icon of the max-restore-button.
'
function AfterRestore as V ()
	cp.SetInnerHtml("max-restore-button", "<i class=\DQfa fa-window-maximize\DQ></i>")
end function

function AfterMaximize as V ()
	cp.SetInnerHtml("max-restore-button", "<i class=\DQfa fa-window-restore\DQ></i>")
end function

function OnReady as V ()
	'
	' Reset max-restore-button icon.
	if self.IsMaximized()
		self.AfterMaximize()
	else
		self.AfterRestore()
	end if
	
	' Call Ready.
	FUNCself.Ready()
end function

' Code to execute when state is "ready".
function Ready as V ()
end function

' Handle other events here.
function HandleEvent()
	select
		case evt = "exit-to-cpanel"
			GRSself.Close()
			a5.Show()GRE
			
		case evt = "close"
			FUNCa5.Close()
			
		case evt = "a5wd"
			MFsys_open("https://a5wd.com/")
	end select
end function
end class
XBM

Creating a User Login System

An SDI application can be protected with a user login system. The user account may also be used in logging activities inside the app.

At startup, we navigate to the login page. After successful login, we navigate to the main page. This is done by using the function "SetNewUrl".

Example

Download Workspace

Xbasic

XBM' autoexec
'
' Delete any existing instances.
delete dbfUsers
delete xdsMyApp

' Declare instances as global.
dim global dbfUsers as dbf::usersRN
dim global xdsMyApp as xds::my_appRN

' Uncomment this to remove the window caption.
'xdsMyApp.NoCaption = .t.

' Hide Alpha Five.
FUNCa5.Hide()

' Open the xdialog.
FUNCxdsMyApp.Open()
XBM
Xbasic

XBM' dbf::users
'
define class dbf::usersRN
'
dim TableName as C =RN "users"
function get_password_hash as C (username as C)RN
	dim password_hash as C =RN ""
	dim tbl as P =RN table.open(self.TableName)
	dim qry as P =RN tbl.query_create("NT", "username =OQ" + username + "OQ")
	
	if qry.records_get() > 0
		password_hash = tbl.password_hash
	end if
	
	qry.drop()
	tbl.close()
	
	get_password_hash = password_hash
end function	
end class
XBM
Xbasic

XBM' xds::my_app
'
define class xds::my_app inherits a5wd::xdialog::modelessRN
'
function Initialize as V ()
	self.XdTitle = "MyApp"

	' Maximize the window.
	self.Maximized = .t.
	
	cp.url = a5.Get_Path() + "\html\login.html"
end function
'
function AfterRestore as V ()
	cp.SetInnerHtml("max-restore-button", "<i class=\DQfa fa-window-maximize\DQ></i>")
end function

function AfterMaximize as V ()
	cp.SetInnerHtml("max-restore-button", "<i class=\DQfa fa-window-restore\DQ></i>")
end function
'
' Code to execute when state is "ready".
function Ready as V ()
	' Reset max-restore-button icon.
	if self.IsMaximized()
		FUNCself.AfterMaximize()
	else
		FUNCself.AfterRestore()
	end if
end function
'
' Handle events here.
function HandleEvent()
	select
		' login (our html here is login.html)
		case *first(evt, "login|")
			dim username as C =RN word(evt, 2, "|")
			dim password as C =RN word(evt, 3, "|")

			dim logged_in as L =RN .f.
			if password <> ""
				if MFGet_Hash(password) = MFdbfUsers.get_password_hash(username)
					logged_in = .t.
				end if
			end if
			
			if logged_in
				' Navigate to app main page using the function "SetNewUrl".
				'
				GRSself.SetNewUrl(a5.Get_Path()GRE + "\html\my_app.html"GP
			else
				cp.ExecuteJavascript("$QPOQ#error-messageOQCP.removeClassQPOQhiddenOQCP")
			end if		
		
		' exit to control panel (our html here is my_app.html)
		case evt = "exit-to-cpanel"
			dim password as C =RN cp.GetValue("password_cpanel")
			if MFGet_Hash(password) = "bb91c12e50d8c87f970354f68e4cfcf9"
				GRSa5_windowbar_close()
				self.Close()
				a5.Show()
				a5_windowbar_show()GRE
			else
				cp.ExecuteJavascript("$QPOQ#error-messageOQCP.removeClassQPOQhiddenOQCP")
			end if
			
		case evt = "close"
			FUNCa5.Close()
			
		case evt = "a5wd"
			MFsys_open("https://a5wd.com/")
	end select
end function
end class
XBM
Xbasic

XBM' Get_Hash
'
function Get_Hash AS C (str as C)
	Get_Hash = FUNCmd5(str + "my_app02")
end function
XBM

A5WD Classes

Classes

ClassName   Availability
a5wd::xdialog::modeless   version 1.0.0 and later
a5wd::xdialog::modal   Coming soon ...
More will be added soon.

a5wd::xdialog::modeless

Built-in Events

Name Availability
init version 1.0.0 and later
hide version 1.0.0 and later
show version 1.0.0 and later
restore version 1.0.0 and later
minimize version 1.0.0 and later
maximize version 1.0.0 and later
close version 1.0.0 and later
prevent_close version 1.0.0 and later
on_activate version 1.0.0 and later
on_deactivate version 1.0.0 and later

Public Variables

Name Availability
cp as helper::Chrome version 1.0.0 and later
evt as C version 1.0.0 and later
tag as C version 1.0.0 and later
pntr as P version 1.0.0 and later
Setup Variables
XdTitle as C version 1.0.0 and later
DeclareXdialogEvent as L = .T. version 1.0.0 and later
XdialogEventFunction as C = <<%js%
function xDialogEvent(eventName) {
   var client = new XMLHttpRequest();
   client.open('GET', 'a5xdialog:' + eventName,false);
   client.setRequestHeader('My-Custom-Header', 'Some Value');
   client.send();
}
%js%
version 1.0.0 and later
DisableContextMenu as L = .T. version 1.0.0 and later
ContextMenuJsCode as C version 1.0.0 and later
BodyCodeAdditional as C version 1.0.0 and later
BodyCodeOverride as C version 1.0.0 and later
RememberSize as L = .F. version 1.0.0 and later
RememberPosition as L = .F. version 1.0.0 and later
PreventClose as L = .F. version 1.0.0 and later
CloseOnLeave as L = .F. version 1.0.0 and later
NoChildren as L = .F. version 1.0.0 and later
NoCaption as L = .F. version 1.0.0 and later
Position as C = "m"

Values: tl = top-left, tm = top-middle, tr = top-right, lm = left-middle, m = middle, rm = right-middle, bl = bottom-left, bm = bottom-middle, br = bottom-right

version 1.0.0 and later
LeftOffset as C = "0"

Values: percentage and numeric string

version 1.0.0 and later
TopOffset as C = "0"

Values: percentage and numeric string

version 1.0.0 and later
Width as C = "50%"

Values: percentage and numeric string

version 1.0.0 and later
Height as C = "50%"

Values: percentage and numeric string

version 1.0.0 and later
Left as C = "auto"

Values: "auto", percentage, and numeric string

version 1.0.0 and later
Top as C = "auto"

Values: "auto", percentage, and numeric string

version 1.0.0 and later
MarginTop as C = "0" version 1.0.0 and later
MarginBottom as C = "-0.5" version 1.0.0 and later
MarginLeft as C = "0" version 1.0.0 and later
MarginRight as C = "-0.4" version 1.0.0 and later
Maximized as L = .F. version 1.0.0 and later
SetupCode as C version 1.0.0 and later
InitializeCode as C version 1.0.0 and later
Xdialog Event Flow Variables
EventFiredCode as C Set EventFired = "end" to end event flow. version 1.0.0 and later
InitEventCode as C version 1.0.0 and later
EventCode as C version 1.0.0 and later
ReadyCode as C version 1.0.0 and later
Window Event Variables
OnActivateCode as C version 1.0.0 and later
OnDeactivateCode as C version 1.0.0 and later
OnPreventCloseCode as C version 1.0.0 and later
BeforeCloseCode as C Set BeforeClose = "cancel" to cancel Close(). version 1.0.0 and later
AfterCloseCode as C version 1.0.0 and later
BeforeShowCode as C Set BeforeShow = "cancel" to cancel Show(). version 1.0.0 and later
AfterShowCode as C version 1.0.0 and later
BeforeHideCode as C Set BeforeHide = "cancel" to cancel Hide(). version 1.0.0 and later
AfterHideCode as C version 1.0.0 and later
BeforeRestoreCode as C Set BeforeRestore = "cancel" to cancel Restore(). version 1.0.0 and later
AfterRestoreCode as C version 1.0.0 and later
BeforeMinimizeCode as C Set BeforeMinimize = "cancel" to cancel Minimize(). version 1.0.0 and later
AfterMinimizeCode as C version 1.0.0 and later
BeforeMaximizeCode as C Set BeforeMaximize = "cancel" to cancel Maximize(). version 1.0.0 and later
AfterMaximizeCode as C version 1.0.0 and later

Public Functions

Name Availability
New as V version 1.0.0 and later
Open as V version 1.0.0 and later
Open2 as V version 1.0.0 and later
Refresh as V version 1.0.0 and later
Activate as V version 1.0.0 and later
Close as V version 1.0.0 and later
Show as V version 1.0.0 and later
Hide as V version 1.0.0 and later
Minimize as V version 1.0.0 and later
Restore as V version 1.0.0 and later
Maximize as V version 1.0.0 and later
Resize as V version 1.0.0 and later
Move as V version 1.0.0 and later
FireEvent as V version 1.0.0 and later
SetNewUrl as V version 1.0.0 and later
RunScripts as V Internal use only. version 1.0.0 and later
ParentGet as C version 1.0.0 and later
Exists as L version 1.0.0 and later
IsActive as L version 1.0.0 and later
IsMinimized as L version 1.0.0 and later
IsMaximized as L version 1.0.0 and later
RememberedGet as C version 1.0.0 and later
RememberedClear as C version 1.0.0 and later

MustOverride Functions

Name Availability
OnInitialize as V Calls Initialize(). version 1.0.0 and later
Initialize as V version 1.0.0 and later
Xdialog Event Flow Functions
OnEventFired as C Calls EventFired(). version 1.0.0 and later
EventFired as C Return "end" to end event flow. version 1.0.0 and later
OnInitEvent as V Calls InitEvent(). version 1.0.0 and later
InitEvent as V version 1.0.0 and later
OnEvent as V Calls HandleEvent(). version 1.0.0 and later
HandleEvent as V version 1.0.0 and later
OnReady as V Calls Ready(). version 1.0.0 and later
Ready as V version 1.0.0 and later
Window Event Functions
OnActivate as V version 1.0.0 and later
OnDeactivate as V version 1.0.0 and later
OnPreventClose as V version 1.0.0 and later
BeforeClose as C Return "cancel" to cancel Close(). version 1.0.0 and later
AfterClose as V version 1.0.0 and later
BeforeShow as C Return "cancel" to cancel Show(). version 1.0.0 and later
AfterShow as V version 1.0.0 and later
BeforeHide as C Return "cancel" to cancel Hide(). version 1.0.0 and later
AfterHide as V version 1.0.0 and later
BeforeMinimize as C Return "cancel" to cancel Minimize(). version 1.0.0 and later
AfterMinimize as V version 1.0.0 and later
BeforeRestore as C Return "cancel" to cancel Restore(). version 1.0.0 and later
AfterRestore as V version 1.0.0 and later
BeforeMaximize as C Return "cancel" to cancel Maximize(). version 1.0.0 and later
AfterMaximize as V version 1.0.0 and later

Note:

Window event functions supersede window event codes.

The following examples demonstrate various ways on how to use the base class a5wd:xdialog:modeless. The sample applications are made simple just to show proof of concept.

Example 1: Direct Usage

Download Workspace

Xbasic

XBM' autoexec
'
'Instantiate and set xdialog title.
dim xdsMyDialog as P =RN new a5wd::xdialog::MFmodeless("My Dialog")
'
' Set HTML content.
xdsMyDialog.cp.html = PPPhtml%XBM
	HMM<form style="margin-top:20px">
		<label for="name_fld">Enter your name. </label><br>
		<input type="text" id="name_fld" style="width:230px">
		<button type="button" onclick="xDialogEvent(OQsubmitOQ)" style="display:inline">Submit</button>
	</form>
	<button type="button" style="position:fixed;bottom:10px;margin-left:125px" onclick="xDialogEvent(OQcloseOQ)">Close</button>HMM
XBM%html%

' Set InitializeCode.
xdsMyDialog.InitializeCode = <<%code%
	self.PreventClose = .t.
%code%

' Set OnPreventCloseCode.
xdsMyDialog.OnPreventCloseCode = <<%code%
	ui_msg_box("Not Allowed", "Please use the OQCloseOQ button.")
%code%

' Set BeforeCloseCode.
xdsMyDialog.BeforeCloseCode = <<%code%
	ui_msg_box("", "Bye!")
%code%

' Set ReadyCode.
xdsMyDialog.ReadyCode = <<%code%
	cp.ExecuteJavascript("document.getElementById(OQname_fldOQCP.focusQPCP")
%code%

' Set EventCode.
xdsMyDialog.EventCode = <<%code%
	if evt = "submit"
		dim name as C =RN cp.GetValue("name_fld")
		if name = ""
			ui_msg_box("Xbasic", "Please type your name.")
		else
			ui_msg_box("Xbasic", "Welcome " + name + ".")
		end if
	end if
%code%

' Open the xdialog.
xdsMyDialog.Open("3.4", "2.4")
XBM

Example 2: Subclassing (Nonparent)

Download Workspace

Xbasic

XBM' xds::my_dialog
'
define class xds::my_dialog inherits a5wd::xdialog::modelessRN

' Initialize
function Initialize as V ()
	self.XdTitle = "My Dialog"
	self.Width = "3.4"
	self.Height = "2.4"
	
	' Set HTML content.
	self.cp.html = <<%html%XBM
		HMM<form style="margin-top:20px">
			<label for="name_fld">Enter your name. </label><br>
			<input type="text" id="name_fld" style="width:230px">
			<button type="button" onclick="xDialogEvent(OQsubmitOQ)" style="display:inline">Submit</button>
		</form>
		<button type="button" style="position:fixed;bottom:10px;margin-left:125px" onclick="xDialogEvent(OQcloseOQ)">Close</button>HMM
	XBM%html%
	
	self.PreventClose = .t.
end function

' OnPreventClose
function OnPreventClose as V ()
	ui_msg_box("Not Allowed", "Please use the OQCloseOQ button.")
end function

' BeforeClose
function BeforeClose as V ()
	ui_msg_box("", "Bye!")
end function

' Ready
function Ready as V ()
	cp.ExecuteJavascript("document.getElementById(OQname_fldOQCP.focusQPCP")
end function

' HandleEvent
function HandleEvent as V ()
	if evt = "submit"
		dim name as C =RN cp.GetValue("name_fld")
		if name = ""
			ui_msg_box("Invalid", "Please type your name.")
		else
			ui_msg_box("Xbasic", "Welcome " + name + ".")
		end if
	end if
end function
end class
XBM
Xbasic

XBM' autoexec
'
' Instantiate
dim xdsMyDialog as xds::my_dialogRN
'
' Open the xdialog
xdsMyDialog.Open()
XBM

On Example 1, we instantiated the base class and then used the exposed variables to define our application.

On Example 2, we created a subclass and used the exposed functions and variables to define our application. All behavior and properties are defined inside the subclass. All we need to do to run our app is instantiate and then open. The resulting application is the same as with Example 1.

We did not intend to make the subclass as parent that is why we overrode the functions "Initialize(), Ready(), and HandleEvent() instead of overriding OnInitialize(), OnReady(), and OnEvent(). There is no issue overriding the latter but it is a good practice no to if the subclass is not to be used as a parent.

Example 3: Subclassing (Parent)

Xbasic

XBM' a5wd_parent::xds
'
define class a5wd_parent::xds inherits a5wd::xdialog::modelessRN

' OnInitialize
function OnInitialize as V ()
	self.XdTitle = "My Dialog"
	self.Width = "3.4"
	self.Height = "2.4"
	
	' Set HTML content.
	self.cp.html = <<%html%XBM
		HMM<form style="margin-top:20px">
			<label for="name_fld">Enter your name. </label><br>
			<input type="text" id="name_fld" style="width:230px">
			<button type="button" onclick="xDialogEvent(OQsubmitOQ)" style="display:inline">Submit</button>
		</form>
		<button type="button" style="position:fixed;bottom:10px;margin-left:125px" onclick="xDialogEvent(OQcloseOQ)">Close</button>HMM
	XBM%html%
	
	self.PreventClose = .t.
	
	' Call Initialize() function for children to use.
	FUNCself.Initialize()
end function

' OnPreventClose
function OnPreventClose as V ()
	ui_msg_box("Not Allowed", "Please use the OQCloseOQ button.")
end function

' BeforeClose
function BeforeClose as V ()
	ui_msg_box("", "Bye!")
end function

' OnReady
function OnReady as V ()
	cp.ExecuteJavascript("document.getElementById(OQname_fldOQCP.focusQPCP")
	'
	' Call Ready() function for children to use.
	FUNCself.Ready()
end function

' OnEvent
function OnEvent as V ()
	if evt = "submit"
		dim name as C =RN cp.GetValue("name_fld")
		if name = ""
			ui_msg_box("Invalid", "Please type your name.")
		else
			ui_msg_box("Xbasic", "Welcome " + name + ".")
		end if
	end if
	'
	' Call HandleEvent() function for children to use.
	FUNCself.HandleEvent()
end function
end class
XBM

The above class will be used as parent. Note that we overrode the functions OnInitialize(), OnReady(), and OnEvent() and called the functions Initialize(), Ready(), and HandleEvent() respectively.

Let's now create child classes that inherit from this parent class.

Example 3A: Subclassing (Child1)

Download Workspace

Xbasic

XBM' xds::child1

define class xds::child1 inherits a5wd_parent::xdsRN
'
function Initialize as V ()
	'
	' Extend functionality by adding another field and button.
	cp.html = cp.html + <<%html%XBM
		HMM<label for="password_fld">Enter your password. </label><br>
		<input type="password" id="password_fld" style="width:230px">
		<button type="button" onclick="xDialogEvent('submit2')" style="display:inline">Submit</button>HMM
	XBM%html%
	'
	' Allow closing the dialog using the window button.
	self.PreventClose = .f.
end function

' Handle the new event.
function HandleEvent as V ()
	if evt = "submit2"
		ui_msg_box("Xbasic", "Your password is " + GRScp.GetValueQPGRE"password_fld"GP + ".")
	end if
end function

' Override BeforeClose to remove the message.
function BeforeClose as V ()
end function
end class
XBM
Xbasic

XBM' autoexec
'
' Instantiate
dim xdsChild1 as xds::child1RN
'
' Open the xdialog
FUNCxdsChild1.Open()
XBM

Example 3B: Subclassing (Child2)

Download Workspace

Xbasic

XBM' xds::child2
'
define class xds::child2 inherits a5wd_parent::xdsRN
'
function Initialize as V ()
	'
	' Modify functionality by adding validation.
	cp.html = cp.html + <<%html%XBM
		HMM<label for="password_fld">Are you human? </label><br>
		<input type="text" id="number1_fld" style="width:62px" disabled> + 
		<input type="text" id="number2_fld" style="width:62px" disabled> = 
		<input type="text" id="sum_fld" style="width:62px">HMM
	XBM%html%
	
	self.PreventClose = .f.
end function

' Ready
function Ready as V ()
	dim number1 as N =RN  GRSround(rand()GRE * 10, 0GP
	dim number2 as N =RN GRSround(rand()GRE * 10, 0GP
	cp.SetValue("number1_fld", GRSconvert_typeQPGREnumber1, "C"GP)
	cp.SetValue("number2_fld", GRSconvert_typeQPGREnumber2, "C"GP)
end function

' LetOQs override OnEvent since we added a validation.
function OnEvent as V ()
	if evt = "submit"
		dim number1 as N =RN GRSconvert_type(cp.GetValue(GRE"number1_fld"GP, "N"GP
		dim number2 as N =RN GRSconvert_type(cp.GetValue(GRE"number2_fld"GP, "N"GP
		dim sum as N =RN GRSconvert_type(cp.GetValue(GRE"sum_fld"GP, "N"GP
		
		if number1 + number2 = sum
			dim name as C =RN cp.GetValue("name_fld")
			if name = ""
				ui_msg_box("Invalid", "Please type your name.")
			else
				ui_msg_box("Xbasic", "Welcome " + name + ".")
			end if
		else
			ui_msg_box("Xbasic", "Sorry, it seems you are not human.")
		end if
	end if
end function

' LetOQs override BeforeClose to confirm closing.
function BeforeClose as C ()
	dim resp as N =RN ui_msg_box("Confimation", "Are you sure you want to close?", UI_YES_NO)
	if resp = 7
		' Return OQcancelOQ to cancel Close().
		BeforeClose = "cancel"
	end if
end function
end class
XBM
Xbasic

XBM' autoexec
'
' Instantiate
dim xdsChild2 as xds::child2RN
'
' Open the xdialog
FUNCxdsChild2.Open()
XBM

On the above examples (3A and 3B), we've seen how we modified and extended the functionality of the parent class. A child class can use, extend, and modify the functionality of its parent. This is possible because of inheritance.

A child class can become a parent of a grandchild class and a grandchild class can become a parent of a grand grandchild class and it can continue indefinitely. This leads to Multiple Inheritance where a child class inherits all functionality of its parent and ancestors.

If we make the class in Example 3A as parent, the code becomes ...

Xbasic

XBM' xds::child1 (now a parent)

define class xds::child1 inherits a5wd_parent::xdsRN
'
' InitEvent
function InitEvent as V ()
	' Call a MustOverride function.
	FUNCself.InitEvent2()
end function
'
function Initialize as V ()
	'
	' Extend functionality by adding another field and button.
	cp.html = cp.html + <<%html%XBM
		HMM<label for="password_fld">Enter your password. </label><br>
		<input type="password" id="password_fld" style="width:230px">
		<button type="button" onclick="xDialogEvent('submit2')" style="display:inline">Submit</button>HMM
	XBM%html%
	'
	' Allow closing the dialog using the window button.
	self.PreventClose = .f.
	'
	' Call a MustOverride function.
	FUNCself.Initialize2()
end function

' Ready
function Ready as V ()
	' Call a MustOverride function.
	FUNCself.Ready2()
end function

' Handle the new event.
function HandleEvent as V ()
	if evt = "submit2"
		ui_msg_box("Xbasic", "Your password is " + GRScp.GetValueQPGRE"password_fld"GP + ".")
	end if
	'
	' Call a MustOverride function.
	FUNCself.HandleEvent2()
end function

' Override BeforeClose to remove the message.
function BeforeClose as V ()
end function

' Create MustOverride functions for children to override.
'
function InitEvent2 as V ()
end function
'
function Initialize2 as V ()
end function
'
function Onready2 as V ()
end function
'
function HandleEvent2 as V ()
end function
end class
XBM

Open Function

Description

Opens the xdialog.

Syntax

Open as V (width = "50%", height = "50%", left = "auto", top = "auto")

Arguments

widthCHARACTEROPTIONAL
The width of the xdialog.
Value can be percentage of the screen width or numeric string specifying the width in inches.
heightCHARACTEROPTIONAL
The height of the xdialog.
Value can be percentage of the screen height or numeric string specifying the height in inches.
leftCHARACTEROPTIONAL
The position of the xdialog from the left of the screen.
Value can be "auto", percentage of the screen width, or numeric string specifying the length in inches.
When "auto" is selected, left position is computed so that the xdialog is centered horizontally.
topCHARACTEROPTIONAL
The position of the xdialog from the top of the screen.
Value can be "auto", percentage of the screen height, or numeric string specifying the length in inches.
When "auto" is selected, top position is computed so that the xdialog is centered vertically.

Example 1

Xbasic

XBM' Instantiate and set the title and webpage to navigate.
dim xdsMyDialog as P =RN new a5wd::xdialog::RNFUNCmodeless("Bootstrap", "https://getbootstrap.com/")
'
' Open the xdialog using the defined size and position.
xdsMyDialog.Open("8", "6", "0.5", "0.5")
XBM

Example 2

Xbasic

XBM' Instantiate and set title.
dim xdsMyDialog as P =RN new a5wd::xdialog::FUNCmodeless("JS Tutorial")
'
' Set url.
xdsMyDialog.cp.url = "https://www.w3schools.com/js/"
'
' Open the xdialog using the default size and position.
xdsMyDialog.Open()
XBM

Example 3

Open at full screen (maximized).

Xbasic

XBM' Instantiate.
dim xdsMyDialog as a5wd::xdialog::modelessRN
'
' Set title and url.
xdsMyDialog.XdTitle = "Handymancabin"
xdsMyDialog.cp.url = "https://handymancabin.com/"
'
' Open the xdialog.
xdsMyDialog.Maximized = .t.
xdsMyDialog.Open()
XBM

Open2 Function

Description

Opens the xdialog.

Syntax

Open2 as V (position = "m", width = "50%", height = "50%", left_offset = "0", top_offset = "0")

Arguments

positionCHARACTEROPTIONAL
The position of the xdialog.
Value can be "tl" (top-left), "tm" (top-middle), "tr" (top-right), "lm" (left-middle), "m" (middle), "rm" (right-middle), "bl" (bottom-left), "bm" (bottom-middle), and "br" (bottom-right).
widthCHARACTEROPTIONAL
The width of the xdialog.
Value can be percentage of the screen width or numeric string specifying the width in inches.
heightCHARACTEROPTIONAL
The height of the xdialog.
Value can be percentage of the screen height or numeric string specifying the height in inches.
left_offsetCHARACTEROPTIONAL
The offset from the left position.
Value can be percentage of the screen width or numeric string specifying the length in inches.
top_offsetCHARACTEROPTIONAL
The offset from the top position.
Value can be percentage of the screen height or numeric string specifying the length in inches.

Example

Xbasic

XBM' Instantiate and set the title.
dim xdsMyDialog as P =RN new a5wd::xdialog::RNFUNCmodeless("CSS Tutorial")
'
' Set the url. 
xdsMyDialog.cp.url = "https://www.w3schools.com/css/"
'
' Open the xdialog using the defined position and size.
xdsMyDialog.Open2("tr", "10", "6")
XBM

New Function

Description

Sets properties for the xdialog.

Syntax

New as V (xd_title = "", url = "", html = "", no_caption = .f., remember_size = .f., remember_position = .f., prevent_close = .f., close_on_leave = .f., no_children = .f.)

Arguments

xd_titleCHARACTEROPTIONAL
The title of the xdialog.
urlCHARACTEROPTIONAL
The url of the Chrome Control.
htmlCHARACTEROPTIONAL
The html of the Chrome Control.
no_captionLOGICALOPTIONAL
A flag to show or not to show the caption of the xdialog.
remember_sizeLOGICALOPTIONAL
A flag to remember or not to remeber the size of the xdialog.
remember_positionLOGICALOPTIONAL
A flag to remember or not to remeber the position of the xdialog.
prevent_closeLOGICALOPTIONAL
A flag to prevent or not to prevent the xdialog from closing when the "X" button is pressed.
close_on_leaveLOGICALOPTIONAL
A flag to close or not to close the xdialog when it loses focus.
no_childrenLOGICALOPTIONAL
A flag to prevent or not to prevent the xdialog from having children.
When this flag is set to false, all xdialogs that are opened from the parent xdialog will also close when the parent xdialog is closed otherwise, they will remain open.

Examples

Xbasic

XBM' Without using New()
dim xdsMyDialog as P =RN new a5wd::xdialog::RNFUNCmodeless("Free Items Database", "https://freeitemsdatabase.com/", "", .f., .f., .f., .f. , .f. , .f.)	
xdsMyDialog.Open()
'
' Using New()
dim xdsMyDialog as P =RN new a5wd::xdialog::RNFUNCmodeless()
xdsMyDialog.New("FID File Host", "http://fidfilehost.com", "", .f., .f., .f., .f. , .f. , .f.)
xdsMyDialog.Open()
'
' Without Using New()
dim xdsMyDialog as a5wd::xdialog::modelessRN
xdsMyDialog.XdTitle = "Handyman Cabin"
xdsMyDialog.cp.url = "https://handymancabin.com/"
xdsMyDialog.Open()
'
' Using New()
dim xdsMyDialog as a5wd::xdialog::modelessRN
xdsMyDialog.New("MRR Download", "https://mrrdownload.com/")
xdsMyDialog.Open()
XBM

Refresh Function

Description

Refreshes the contents of the xdialog.

This is a wrapper to the ui_modeless_dlg_refresh function.

Syntax

Refresh as V (asynchronous = .t.)

Argument

asynchronousLOGICALOPTIONAL

Example

Xbasic

XBM' Delete any existing instances.
delete xdsMyDialog
'
' Instantiate and set the title of the xdialog.
' Declare it as global so it can be accessed anywhere.
dim global xdsMyDialog as P =RN a5wd::xdialog::FUNCmodeless("My Dialog")
'
' Prevent the dialog from closing using the X button.
xdsMyDialog.PreventClose = .t.
'
' Write code to execute when the X button is clicked.
xdsMyDialog.OnPreventCloseCode = PPPcode%
	ui_msg_box("Not Allowed", "Sorry, this xdialog is prevented to close.",UI_STOP_SYMBOL+UI_OK)
%code%
'
' Write setup code.
xdsMyDialog.SetupCode = <<%code%
	dim global gName as C =RN ""
	ok_button_label = "&OK"
	cancel_button_label = "&Cancel"
%code%
'
' Override body code.
xdsMyDialog.BodyCodeOverride = <<%dlg%
DLG{ymargin=1,0}
{xmargin=3,3}
{region}
Type your name:| {stretch=width}[.40gName];
{endregion};
{stickto=bottom}
{stretch=width}{line=1,0};
{region}
{stretch=}
{stickto=bottom}
<*15=ok_button_label!OK> <15=cancel_button_label!CANCEL>
{endregion};DLG
%dlg%
'
' Write event code.
xdsMyDialog.EventCode = <<%code%
	if gName = ""
		if evt = "OK" .or. evt = "CANCEL"
			ui_msg_box("Not Allowed", "Please type your name first.", UI_ATTENTION_SYMBOL+UI_OK)
			end
		end if
	end if
	
	if evt = "OK"
		ui_msg_box(evt, "You pressed OK." + crlf(2) + "Bye " + gName + "!", UI_INFORMATION_SYMBOL+UI_OK)
		self.Close()
		
	elseif evt = "CANCEL"
		ui_msg_box(evt, "You pressed CANCEL."+ crlf(2) + "Bye " + gName + "!", UI_INFORMATION_SYMBOL+UI_OK)
		self.Close()
	end if
%code%
'
' Open the xdialog using the defined size and default position.
xdsMyDialog.Open("4", "2")
XBM
Xbasic

XBM' Modify the value of the global variable at the interactive window.
gName = "Jonathan"

' Refresh the value of the textbox using Refresh().
xdsMyDialog.Refresh()
XBM

Activate Function

Description

Activates the xdialog.

This is a wrapper to the ui_modeless_dlg_setfocus function.

Syntax

Activate as V ()

Example

Xbasic

XBM' Delete any existing instances.
delete xdsMyDialog
'
' Instantiate the xdialog object.
' Declare as global so it can be accessed anywhere.
dim global xdsMyDialog as a5wd::xdialog::modelessRN
'
' Set title and url.
xdsMyDialog.New("HTML5 Tutorial", "https://www.tutorialspoint.com/html5/index.htm")
'
' Open the xdialog using the defined position, size, and offset.
xdsMyDialog.Open2("br", "50%", "50%", "0", "-1")
XBM
Xbasic

XBM' Activate the xdialog using Activate().
xdsMyDialog.Activate()
XBM

Close Function

Description

Closes the xdialog.

This is a wrapper to the ui_modeless_dlg_close function.

Syntax

Close as V ()

Example

Xbasic

XBM' Delete any existing instances.
delete xdsMyDialog
'
' Instantiate the xdialog object.
' Declare as global so it can be accessed anywhere.
dim global xdsMyDialog as a5wd::xdialog::modelessRN
'
' Set title and url.
xdsMyDialog.New("JS Tutorials", "https://davidwalsh.name/tutorials/javascript")
'
' Open the xdialog using the defined position, size, and offset.
xdsMyDialog.Open2("br", "50%", "50%", "0", "-1")
XBM
Xbasic

XBM' Close the xdialog at the interactive window.
xdsMyDialog.Close()
XBM

Show Function

Description

Shows the xdialog after it is hidden.

This is a wrapper to the ui_dlg_show function.

Syntax

Show as V ()

Example

Xbasic

XBM' Delete any existing instances.
delete xdsMyDialog
'
' Instantiate the xdialog object.
' Declare as global so it can be accessed anywhere.
dim global xdsMyDialog as a5wd::xdialog::modelessRN
'
' Set title and url.
xdsMyDialog.New("FID Filehost", "https://fidfilehost.com/")
'
'  LetOQs inject a "CLICK ME TO HIDE THIS DIALOG" button on the webpage.
xdsMyDialog.ReadyCode = PPPcode%
	dim js as C =RN PPPjs%XBM
						JSM/* Let's use jQuery since it is loaded on this webpage. */
						var btn = '<button type="button" style="margin:20px" class="btn btn-info btn-lg smooth" onclick="xDialogEvent(\OQhide\OQ)">CLICK ME TO HIDE THIS DIALOG</button>';
						$('#wrap').prepend(btn);JSM
					XBM%js%
	cp.ExecuteJavascript(js)
%code%
'
' Open the xdialog using the defined position, size, and offset.
xdsMyDialog.Open2("br", "50%", "50%", "0", "-1")
XBM
Xbasic

XBM' Click the "CLICK ME TO HIDE THIS DIALOG" button in the dialog created using the above code.
'
' Show the dialog again by running this code at the interactive window.
xdsMyDialog.Show()
XBM

Hide Function

Description

Hides the xdialog.

This is a wrapper to the ui_dlg_hide function.

Syntax

Hide as V ()

Example

Xbasic

XBM' Delete any existing instances.
delete xdsMyDialog
'
' Instantiate the xdialog object.
' Declare as global so it can be accessed anywhere.
dim global xdsMyDialog as a5wd::xdialog::modelessRN
'
' Set title and url.
xdsMyDialog.New("Handymancabin", "https://handymancabin.com/")
'
' Open the xdialog using the defined position, size, and offset.
xdsMyDialog.Open2("br", "50%", "50%", "0", "-1")
XBM
Xbasic

XBM' Hide the xdialog using Hide() at the interactive window.
xdsMyDialog.Hide()

' Show the dialog again using Show().
xdsMyDialog.Show()
XBM

Minimize Function

Description

Minimizes the xdialog.

This is a wrapper to the ui_dlg_minimize function.

Syntax

Minimize as V ()

Example

Xbasic

XBM' Delete any existing instances.
delete xdsMyDialog
'
' Instantiate the xdialog object.
' Declare as global so it can be accessed anywhere.
dim global xdsMyDialog as a5wd::xdialog::modelessRN
'
' Set title and url.
xdsMyDialog.New("Alphasoftware", "https://www.alphasoftware.com/")
'
' Open the xdialog using the defined position, size, and offset.
xdsMyDialog.Open2("br", "50%", "50%", "0", "-1")
XBM
Xbasic

XBM' Minimize the xdialog using Minimize() at the interactive window.
xdsMyDialog.Minimize()

' Restore the dialog to its original size and location using Restore().
xdsMyDialog.Restore()
XBM

Restore Function

Description

Restores the xdialog.

Syntax

Restore as V ()

Example

Xbasic
		
XBM' Delete any existing instances.
delete xdsMyDialog
'
' Instantiate the xdialog object.
' Declare as global so it can be accessed anywhere.
dim global xdsMyDialog as a5wd::xdialog::modelessRN
'
' Set title and url.
xdsMyDialog.New("Bootstrap", "https://getbootstrap.com/")
'
' Uncomment this to prevent the child dialog from behaving as child.
'xdsMyDialog.NoChildren = .t.
'
' LetOQs create a child dialog.
xdsMyDialog.ReadyCode = PPPcode%
	dim xdsChildDialog as a5wd::xdialog::modelessRN
	xdsChildDialog.XdTitle = "My Menu"

	xdsChildDialog.cp.html = PPPhtml%XBM
								HMM<!-- load Bootstrap CSS from CDN -->
								<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" rel="stylesheet" />
								
								<div class="container-fluid">
									<div class="row mt-5">
										<div class="col-sm">
											<button type="button" onclick="xDialogEvent('maximize_parent')" class="btn btn-primary btn-lg btn-block">Maximize Parent</button>
											<button type="button" onclick="xDialogEvent('minimize_parent')" class="btn btn-danger btn-lg btn-block">Minimize Parent</button>
											<button type="button" onclick="xDialogEvent('restore_parent')" class="btn btn-success btn-lg btn-block">Restore Parent</button>
											<button type="button" onclick="xDialogEvent('close_parent')" class="btn btn-secondary btn-lg btn-block">Close Parent</button>
										</div>
									</div>
								</div>HMM
							XBM%html%

	xdsChildDialog.EventCode = <<%code2%
									select
										case evt = "maximize_parent"
											xdsMyDialog.Maximize()
											
										case evt = "minimize_parent"
											xdsMyDialog.Minimize()
											
										case evt = "restore_parent"
											xdsMyDialog.Restore()
											
										case evt = "close_parent"
											xdsMyDialog.Close()
									end select
								%code2%	
								
	' Open the child xdialog						
	FUNCxdsChildDialog.Open2("rm", "3", "3.5")
%code%
'
' Open the parent xdialog.
xdsMyDialog.Open2("lm", "60%", "60%")XBM

Maximize Function

Description

Maximizes the xdialog.

This is a wrapper to the ui_dlg_maximize function.

Syntax

Maximize as V ()

Example

Xbasic

XBM' Delete any existing instances.
delete xdsMyDialog
'
' Instantiate the xdialog object.
' Declare as global so it can be accessed anywhere.
dim global xdsMyDialog as a5wd::xdialog::modelessRN
'
' Set title and url.
xdsMyDialog.New("W3 Schools", "https://www.w3schools.com")
'
' w3schools.com does not use jQuery so letOQs load it at initialization.
' The trick is to download jQuery code and then execute it.
xdsMyDialog.InitEventCode = <<%code% 
	dim response as P =RN FUNChttp_get("https://code.jquery.com/jquery-3.5.1.min.js")
	if eval_valid("response.parsed_headers.status_code") = .f.
		ui_msg_box("Error", "Unable to download jQuery.", UI_ATTENTION_SYMBOL+UI_OK)
	elseif response.parsed_headers.status_code = 200
		cp.ExecuteJavascript(response.body)
	else
		ui_msg_box("Error", "The request returned with the following status code: " + response.parsed_headers.status_code, UI_ATTENTION_SYMBOL+UI_OK)
	end if	
%code%

' Now, we can use jQuery to add buttons at the top-right corner.
xdsMyDialog.ReadyCode = PPPcode%
	dim js as C =RN PPPjs%XBM
		JSMvar btn = '<div style="position:fixed; z-index:999; top:0; right:0">' +
						'<button type="button" class="w3-button w3-blue" onclick="xDialogEvent(\OQminimize\OQ)">Minimize</button>' +
						'<button type="button" class="w3-button w3-blue" onclick="xDialogEvent(\OQrestore\OQ)">Restore</button>' +
						'<button type="button" class="w3-button w3-blue" onclick="xDialogEvent(\OQmaximize\OQ)">Maximize</button>' +
					'</div>';
		$('body').prepend(btn);JSM
	XBM%js%
	
	cp.ExecuteJavascript(js)
%code%

' Open the xdialog.
xdsMyDialog.Open()
XBM
Xbasic

XBM' Note that on the above code, we fire the events "minimize", "restore", and "maximize".

' Calling these functions externally accomplishes the same.
'
xdsMyDialog.Maximize()

xdsMyDialog.Restore()

xdsMyDialog.Minimize()

' We may also fire the events at will.
'
FUNCxdsMyDialog.FireEvent("minimize")

FUNCxdsMyDialog.FireEvent("restore")

FUNCxdsMyDialog.FireEvent("maximize")
XBM

Resize Function

Description

Resizes the xdialog.

This is a wrapper to the ui_dlg_resize function.

Syntax

Resize as V (width as C, height as C)

Arguments

widthCHARACTER
The width of the xdialog.
Value can be percentage of the screen width or numeric string specifying the width in inches.
heightCHARACTER
The height of the xdialog.
Value can be percentage of the screen height or numeric string specifying the height in inches.

Example

Xbasic

XBM' Delete any existing instances.
delete xdsMyDialog
' Instantiate.
dim global xdsMyDialog as a5wd::xdialog::modelessRN
'
' Set title and url.
xdsMyDialog.XdTitle = "JS Tutorial"
xdsMyDialog.cp.url = "https://www.tutorialrepublic.com/html-tutorial/"
'
' Open the xdialog using the default size and position.
xdsMyDialog.Open()
XBM
Xbasic

XBM' Run this code at the interactive window..
FUNCxdsMyDialog.Resize("6", "4")
XBM

Move Function

Description

Resizes the xdialog.

This is a wrapper to the ui_dlg_move function.

Syntax

Move as V (left as C, top as C)

Arguments

leftCHARACTER
The position of the xdialog from the left of the screen.
Value can be percentage of the screen width or numeric string specifying the length in inches.
topCHARACTER
The position of the xdialog from the top of the screen.
Value can be percentage of the screen height, or numeric string specifying the length in inches.

Example

Xbasic

XBM' Delete any existing instances.
delete xdsMyDialog
' Instantiate.
dim global xdsMyDialog as a5wd::xdialog::modeless =RN new a5wd::xdialog::RNFUNCmodeless("Programming", "https://www.khanacademy.org/computing/computer-programming")
'
' Open the xdialog using the default size and position.
xdsMyDialog.Open2("br")
XBM
Xbasic

XBM' Run this code at the interactive window.
FUNCxdsMyDialog.Move("0", "0")
XBM

FireEvent Function

Description

Fires an xdialog event.

This is a wrapper to the ui_dlg_event function.

Syntax

FireEvent as V (evt as C, flags = "W")

Arguments

eventCHARACTER
The name of the event to fire.
flagsCHARACTEROPTIONAL

I - Immediate. Causes the script to stop executing until the event has completed executing.

W - Wait for idle. I.e. wait until the next idle cycle to execute the event. The script can continue executing before the event has completed executing.

Example

Xbasic

XBM' Delete any existing instances.
delete xdsMyDialog
' Instantiate.
dim global xdsMyDialog as a5wd::xdialog::modeless =RN new a5wd::xdialog::RNFUNCmodeless("JS Guide")
xdsMyDialog.cp.url = "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide"
'
' Open the xdialog using the default size and position.
xdsMyDialog.Open2("br")
XBM
Xbasic

XBM' Run this code at the interactive window.
FUNCxdsMyDialog.FireEvent("close")
XBM

SetNewUrl Function

Description

Changes the url of the Chrome Control.

Syntax

SetNewUrl as V (new_url as C)

Arguments

new_urlCHARACTER
The new url of the Chrome Control.

Example

Xbasic

XBM' Instantiate
dim xdsMyDialog as P =RN new a5wd::xdialog::MFmodeless("Get Site Content")
'
' Set url.
xdsMyDialog.cp.url = "https://mrrdownload.com/product-category/free-products/"
'
xdsMyDialog.ReadyCode = PPPcode%
	' Extract some raw data
	dim data as C =RN cp.ExecuteJavascriptResult("document.querySelectorQPOQ.productsOQCP.innerHTML")
	
	' Add a close button to demonstrate that xDialogEvent is still working.
	dim close_button as C =RN "<button type=\DQbutton\DQ onclick=\DQxDialogEvent(OQcloseOQ)\DQ style=\DQwidth:300px;height:70px\DQ>CLICK ME TO CLOSE THIS DIALOG</button>"
	
	' Write the data to an html file
	GRSfile.from_string(a5.Get_Path()GRE + "\temp.html", close_button + dataGP
	xbasic_wait_for_idle()
	
	' Set the html file as new url.
	GRSself.SetNewUrl(a5.Get_Path()GRE + "\temp.html"GP
%code%

' Open the xdialog using the default size and position.
FUNCxdsMyDialog.Open()
XBM

ParentGet Function

Description

Gets the name of the parent xdialog.

This is a wrapper to the ui_dlg_parent_get function.

Syntax

ParentGet as C ()

Example

Xbasic

XBM' Instantiate
dim xdsMyDialog as P =RN new a5wd::xdialog::MFmodeless("Caller")
'
xdsMyDialog.cp.html = PPPhtml%XBM
	HMM<style> body { background-color:#DFF3FE } button { margin-left:50px;margin-top:50px } </style>
	<button type="button" onclick="xDialogEvent('open_child')">Open Child Dialog</button>HMM
XBM%html%
'
xdsMyDialog.EventCode = PPPcode%
	if evt = "open_child"
		' Open a child xdialog.
		' The caller xdialog is the parent of a called xdialog by default.
		dim xdsChild as P =RN new a5wd::MFxdialog::modeless("Called")
		
		xdsChild.cp.html = PPPhtml%XBM
			HMM<style> body { background-color:#F5DFFE } button { margin-left:50px;margin-top:50px }</style>
			<button type="button" onclick="xDialogEvent('get_parent')">Get Parent</button>
			<button type="button" onclick="xDialogEvent('close_parent')">Close Parent</button>HMM
		XBM%html%
		
		xdsChild.EventCode = PPPcode2%
			' get_parent
			if evt = "get_parent"
				ui_msg_box("Info", "The name of the parent xdialog is \DQ" + FUNCself.ParentGet() + "\DQ.")
			
			' close_parent
			elseif evt = "close_parent"
				GRSui_modeless_dlg_close(self.ParentGet())GRE
			end if
		%code2%
		
		MFxdsChild.Open("30%", "30%")
	end if
%code%

' Open the xdialog using the default size and position.
MFxdsMyDialog.Open("50%", "50%")
XBM

Exists Function

Description

Indicates whether the modeless dialog box exists.

This is a wrapper to the ui_modeless_dlg_exist function.

Syntax

Exists as L ()

Example

Xbasic

XBM'Instantiate.
dim xdsMyDialog as a5wd::xdialog::modelessRN
xdsMyDialog.New("CSS3 Tutorial", "https://www.tutorialrepublic.com/css-tutorial/")
'
' Open the xdialog.
xdsMyDialog.Open()
XBM
Xbasic

XBM' At the interactive window, run this code to determine if the dialog named "CSS3 Tutorial" exists.
' Close the xdialog then try again.
?FUNCxdsMyDialog.Exists()
XBM

IsActive Function

Description

Indicates whether the xdialog is active or any control on the dialog has focus.

This is a wrapper to the ui_is_active function.

Syntax

IsActive as L ()

Example

Xbasic

XBM'Instantiate.
dim xdsMyDialog as P =RN new a5wd::xdialog::MFmodeless("Test")
'
xdsMyDialog.cp.html = PPPhtml%XBM
	HMM<style> body { background-color:#DFF3FE } button, h1 { margin-left:50px;margin-top:50px } </style>
	<button type="button" onclick="xDialogEvent('is_active')">Is this xdialog active?</button>
	<button type="button" onclick="xDialogEvent('activate_control_panel')">Is this xdialog still active?</button>
	<h1 id="result"></h1>HMM
XBM%html%

xdsMyDialog.EventCode = PPPcode%
	if evt = "is_active"
		cp.SetInnerHtml("result", GRSifQPself.IsActiveQPCPGRE, "True", "False"GP)
		
	elseif evt = "activate_control_panel"
		FUNCControlPanel.Activate()
		cp.SetInnerHtml("result", GRSifQPself.IsActiveQPCPGRE, "True", "False"GP)
	end if
%code%
'
' Open
xdsMyDialog.Open("50%", "50%")
XBM

IsMaximized Function

Description

Indicates whether the xdialog is maximized or not.

This is a wrapper to the ui_dlg_is_maximized function.

Syntax

IsMaximized as L ()

Example

Xbasic

XBM'Instantiate.
dim xdsMyDialog as P =RN new a5wd::MFxdialog::modeless("Test")
'
xdsMyDialog.cp.html = PPPhtml%XBM
	HMM<style> body { background-color:#DFF3FE } button { margin-left:50px;margin-top:50px } </style>
	<button type="button" onclick="xDialogEvent('maximize')">Maximize</button>
	<button type="button" onclick="xDialogEvent('restore')">Restore</button>
	<button type="button" onclick="xDialogEvent('is_maximized')">Is this dialog maximized?</button>HMM
XBM%html%

xdsMyDialog.EventCode = PPPcode%
	if evt = "is_maximized"
		ui_msg_box("Result", GRSself.IsMaximizedQPCPGRE)
	end if
%code%
'
' Open
xdsMyDialog.Open("50%", "50%")
XBM

IsMinimized Function

Description

Indicates whether the xdialog is minimized or not.

This is a wrapper to the ui_dlg_is_minimized function.

Syntax

IsMinimized as L ()

Example

Xbasic

XBM' Delete any existing instances.
delete xdsMyDialog
'
' Instantiate the xdialog object.
' Declare as global so it can be accessed anywhere.
dim global xdsMyDialog as a5wd::xdialog::modelessRN
'
' Set title and url.
xdsMyDialog.New("MySQL Tutorial", "https://www.mysqltutorial.org/")
'
' Open the xdialog using the defined position, size, and offset.
xdsMyDialog.Open2("br", "50%", "50%", "0", "-1")
XBM
Xbasic

XBM' Run these codes at the interactive window. 
'
?FUNCxdsMyDialog.Minimize()
'
?FUNCxdsMyDialog.IsMinimized()
XBM

RememberedGet Function

Description

Retrieves any remembered alignment, size, and position data from the registry.

This is a wrapper to the ui_dlg_remembered_get function.

Syntax

RememberedGet as C ()

Example

Xbasic

XBM' Delete any existing instances.
delete xdsMyDialog
' Instantiate.
dim global xdsMyDialog as a5wd::xdialog::modelessRN
xdsMyDialog.New("JS 4 Cats", "http://jsforcats.com/")
'
' Set these to true so that the xdialog will open using its previous size and position.
xdsMyDialog.RememberSize = .t.
xdsMyDialog.RememberPosition = .t.
'
' Open the xdialog.
xdsMyDialog.Open()
XBM
Xbasic

XBM' Move/resize the xdialog then close. 
'
'Open the xdialog again then run this code at the interactive window.
?FUNCxdsMyDialog.RememberedGet()
XBM

RememberedClear Function

Description

Clears any remembered alignment, size, and position data from the registry.

This is a wrapper to the ui_dlg_remembered_clear function.

Syntax

RememberedClear as C ()

Example

Xbasic

XBM' Delete any existing instances.
delete xdsMyDialog
'
' Instantiate the xdialog object.
' Declare as global so it can be accessed anywhere.
dim global xdsMyDialog as a5wd::xdialog::modelessRN
'
' Set title and url.
xdsMyDialog.New("MySQL Guru", "https://www.guru99.com/mysql-tutorial.html")
'
' Open the xdialog using the saved size and position.
xdsMyDialog.RememberSize = .t.
xdsMyDialog.RememberPosition = .t.
xdsMyDialog.Open()
XBM
Xbasic

XBM' Open the above xdialog, move, resize then close. When you open it again, it should return to previous position and size. 
'
' Now, close the xdialog then run this code. Open the xdialog again.
?FUNCxdsMyDialog.RememberedClear()
'
XBM

a5wd::xdialog::modal

Coming soon ...