WebView custom Gadget [examples]

<%@ Language=VFP %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
</head>
<%
timeofday()
if len(database())=0
	open database southwind
endif
 
// get the column descriptions
use example in 0 current
astore(afieldList, fldlist(), ',')
declare afieldDesc[ fldcount() ]
adesc(afieldDesc)
use
 
// perform the query
tmpfile = sys(2015)	
select * from example order by state save as [&tmpfile]
use [&tmpfile] in 0 current
declare afieldList[ fldcount() ]
 
// declare some special symbols (html uses ampersand so do we)	
amp = chr(38) 
nbsp = amp + "nbsp;"  
 
// generate the html output
? ('<table width="100%" height="100%" cellpadding="5" cellspacing="0" bgcolor="white" border=0px>') 
? ('<tr bgcolor="gray">')
? ('<td align="center" colspan="&(fldcount())">')
? ('</td>')
? ('</tr>')  
 
// display column headings
? ('<tr bgcolor="#eaeaea">')
	for j=1 to fldcount()
		? ('<td halign=center valign=top>')
		? ('<b><font color="gray">' + afieldDesc[j] + '</font></b>')
		? ('</td>')
    next
? ('</tr>') 
? ('<tr bgcolor="darkgray" height="1px">' + replicate('<td></td>', fldcount()) + '</tr>')
 
// group subtotals by the STATE field 
last_state = state 
declare subtotals[3]
subtotals[1] = 0.0  	// limit
subtotals[2] = 0.0	// balance
subtotals[3] = 0.0	// available
m_limit = 0.0
m_balance = 0.0
m_available = 0.0 
 
// scan through the records generating the table rows and columns
goto top
 
// for all records...	   
for i=1 to reccount()+2
	if mod(i,2) = 0
    	rowcolor = "#f9f9f9"
    	altcolor = "#FFFFFF"
	else
		rowcolor = "#FFFFFF"        	
		altcolor = "#f9f9f9"
    endif
 
	// check for subtotal break
	if (state != last_state and i > 1) or (i > reccount())
		? ('<tr bgcolor="lightgray" height="1px">' + replicate('<td></td>', fldcount()) + '</tr>')
 
		// display subtotals
		? ('<tr bgcolor="#f5f5f5" color="gray">')
 
		if i <= reccount()+1
			? ('<td colspan="3" halign=left><b><font color="gray">Sub-total for state: ' + last_state + '</font></b>')
			? (replicate('<td>&(nbsp)</td>', 5))
		elseif i = reccount()+2
			? ('<td color="gray" halign=left><b>Totals:</b>')
			? (replicate('<td>&(nbsp)</td>', 7))
        endif
 
		? ('<td align=right>')
        tmpfld = currency(subtotals[1])
        fld = 'tmpfld'
		? ('<b><font color="gray">' + etos(&fld)+'&(nbsp)&(nbsp)' + '</font><b>')
		? ('</td>')
 
		? ('<td align=right>')
        tmpfld = currency(subtotals[2])
        fld = 'tmpfld'
		? ('<b><font color="gray">' + etos(&fld)+'&(nbsp)&(nbsp)' + '</font><b>')
		? ('</td>')
 
		? ('<td align=right>')
        tmpfld = currency(subtotals[3])
        fld = 'tmpfld'
		? ('<b><font color="gray">' + etos(&fld)+'&(nbsp)&(nbsp)' + '</font><b>')
		? ('</td>') 
		? (replicate('<td>&(nbsp)</td>', 1))
 
		? ('</tr>')
 
		? ('<tr bgcolor="white" height="1px">' + replicate('<td></td>', fldcount()) + '</tr>')
		if i > reccount()+1
			? ('<tr bgcolor="white" height="1px">' + replicate('<td></td>', fldcount()) + '</tr>')
			? ('<tr bgcolor="black" height="1px">' + replicate('<td></td>', fldcount()) + '</tr>')
        endif
 
		? ('<tr colspan="&(fldcount())" bgcolor="&altcolor">')
		? (replicate('<td>&(nbsp)</td>', fldcount()))
		? ('</tr>') 
 
		if i = reccount()+1			
		    subtotals[1] = m_limit  		// limit
		    subtotals[2] = m_balance		// balance
		    subtotals[3] = m_available		// available
        	loop
        endif
 
	    subtotals[1] = 0.0  	// limit
	    subtotals[2] = 0.0		// balance
	    subtotals[3] = 0.0		// available
 
		if i > reccount()+1
        	exit
        endif
    endif
 
	// save subtotal values       	
   	last_state = state 
   	subtotals[1] = subtotals[1] + limit
   	subtotals[2] = subtotals[2] + balance
   	subtotals[3] = subtotals[3] + available 
   	m_limit  = m_limit + limit
   	m_balance = m_balance + balance
   	m_available = m_available + available
 
	// for all columns...
	? ('<tr bgcolor="&rowcolor">')
	for j=1 to fldcount()
		fld = afieldlist(j)
		if (upper(fld) = 'LIMIT' or upper(fld) = 'BALANCE' or upper(fld) = 'AVAILABLE')
        	tmpfld = currency(&fld)
        	fld = 'tmpfld'
			? ('<td valign=top align=right>')
		else            	
			? ('<td valign=top align=left>')
        endif
		? (etos(&fld)+"&(nbsp)&(nbsp)")
		? ('</td>')
    next   
 
	? ('</tr>')
	skip
next  
 
? ('</table>')
? ('** End of report elapsed time '+timeofday(4)+' seconds **')
erase '&tmpfile..dbf'
erase '&tmpfile..dbt'  
%>
</body>
</html>

https://www.lianja.com/doc/index.php/Example_webview_gadget_rsp_script


PHP:

// Lianja PHP WebView
//
echo '<html>';
echo '<head>';
echo '<style>';
echo '.tablecaption { background: gray; font-weight: bold; color: white; height:26px; }';
echo '.smallfont { font-size:small; }';
echo 'body { padding: 0px; margin: 0px; border: 1px solid lightgray; border-top: 1px solid white;}';
echo '</style>';
echo '</head>';
echo '<body>'; 
 
// open the southwind database
$db = Lianja::openDatabase("southwind");
 
// Open a recordset
$rs = $db->openRecordSet("select * from example"); 
 
// main table
echo '<table cellpadding="5">'; 
echo '<caption class="tablecaption">Example PHP Report</caption>';
 
// print table headings 
$rs->movefirst(); 
 
echo '<tr bgcolor="lightgray" class="smallfont">';
for ($j=0; $j<$rs->fcount(); ++$j) 
{
	echo '<th><font color="white">' . $rs->fields($j)->name . '</font></th>';
}
echo "</tr>";
 
 
// Traverse the recordset and write the output into the Webview section.
for ($i=0; $i<$rs->reccount(); ++$i)
{
	if (($i%2) == 0)
	{
    	$rowcolor = "#f1f6fe";
    	$altcolor = "#FFFFFF";
	}
	else
	{
		$rowcolor = "#FFFFFF";        	
		$altcolor = "#f1f6fe";
	}
 	echo '<tr bgcolor="' . $rowcolor . '" color="darkgray" class="smallfont" valign="top">';
	for ($j=0; $j<$rs->fcount(); ++$j)
	{
		$name = $rs->fields($j)->name;
		$value = $rs->fields($j)->value;
		if (in_array($name, array('LIMIT', 'AVAILABLE', 'BALANCE')))
		{
			echo '<td align="right">$' . sprintf("%-8.2f", $value) . '</td>';
		}
		else
		{
			echo '<td>' . $value . '</td>';
		}
	}
	echo '</tr>';
	$rs->movenext(); 
}
 
// end of table
echo '</table>';
 
 
// Close the recordset	
$rs->close(); 
 
// end of report
echo '<hr />Report complete at <b>' . date("r", time()) . '</b>'; 
 
// Close off HTML tags
echo '</body>';
echo '</html>';

Python:

#
# Lianja Custom Python WebView
#
#
import Lianja
import time
 
# The output of the "print" command will be redirected into the WebView.
print "<html>"
print "<head>"
print "<style>"
print ".tablecaption { background: gray; font-weight: bold; color: white; \
  height:26px; }"
print ".smallfont { font-size:small; }"
print "body { padding: 0px; margin: 0px; border: 1px solid lightgray; \
  border-top: 1px solid white;}"
print "</style>"
print "</head>"
print "<body>"
 
# open a database
db = Lianja.openDatabase("southwind") 
 
# open a recordset
rs = db.openRecordSet("select * from example")
 
# main table
print "<table cellpadding=\"5\">"
print "<caption class=\"tablecaption\">Example Python Report</caption>"
 
# column headings
rs.movefirst()
print "<tr bgcolor=\"lightgray\" class=\"smallfont\">"
for j in range( rs.fcount() ):
	print "<th><font color=\"white\">" + rs.fields(j).name + "</font></th>"
print "</tr>"
 
# Traverse the recordset and write the output into the Webview section.
for i in range( rs.reccount() ):
	if ((i%2) == 0):
		rowcolor = "#f1f6fe"
		altcolor = "#FFFFFF"
	else:
		rowcolor = "#FFFFFF"       	
		altcolor = "#f1f6fe"
 	print "<tr bgcolor=\"" + rowcolor + "\" color=\"darkgray\" class=\"smallfont\" valign=top>"
	for j in range( rs.fcount() ):
		if rs.fields(j).name in [ "LIMIT", "BALANCE", "AVAILABLE" ]:
			print "<td align=right>$%.2f</td>" % rs.fields(j).value
		else:
			print "<td>%s</td>" % rs.fields(j).value
	print "</tr>"
	rs.movenext()
 
# end of table
print "</table>"
 
# Close the RecordSet	
rs.close() 
 
# End of report
print "<hr>Report complete at <b>" + time.asctime() + "</b>" 
 
# Close off HTML tags
print "</body>"
print "</html>"

https://www.lianja.com/doc/index.php/Example_webview_gadget_Python_script


JS:

<%@ Language=JavaScript %>
<html>
<head>
<style>
.tablecaption { background: gray; font-weight: bold; color: white; height:26px; }
.smallfont { font-size:small; }
body { padding: 0px; margin: 0px; border: 1px solid lightgray; border-top: 1px solid white;}
</style>
</head>
<body>
<%
db = Lianja.openDatabase("southwind");
 
// Open a recordset
rs = db.openRecordSet("select * from example");
 
// main table
print("<table cellpadding=\"5\">"); 
print("<caption class=\"tablecaption\">Example JavaScript Report</caption>");
 
// print table headings 
rs.moveFirst(); 
print("<tr bgcolor=\"lightgray\" class=\"smallfont\">");
for (j=0; j < rs.fieldcount; ++j)
{
	print("<th><font color=\"white\">" + rs.fields(j).name + "</font></th>");
}
print("</tr>");
 
// Traverse the recordset and write the output into the Webview section.
for (i=0; i < rs.reccount; ++i)
{
	if ((i%2) == 0)
	{
    	rowcolor = "#f1f6fe";
    	altcolor = "#FFFFFF";
	}
	else
	{
		rowcolor = "#FFFFFF";        	
		altcolor = "#f1f6fe";
	}
 	print("<tr bgcolor=\"" + rowcolor + "\" color=\"darkgray\" class=\"smallfont\" valign=top>");
	for (j=0; j < rs.fieldcount; ++j)
	{
		name = rs.fields(j).name;
		value = rs.fields(j).value;
		if (['LIMIT', 'AVAILABLE', 'BALANCE'].indexOf(name) >= 0)
		{
			print("<td align=right>$" + value.toFixed(2) + "</td>");
		}
		else
		{
			print("<td>" + value + "</td>");
		}
	}
	print("</tr>");
	rs.moveNext(); 
}
 
// end of table
print("</table>");
 
// Close the recordset	
rs.close(); 
 
// end of report
print("<hr>Report complete at <b>" + new Date() + "</b>"); 
%>
</body>
</html>

Advertisements

Custom sections [examples]

Custom Sections are built using the Lianja UI Framework. When building a Custom Section you should subclass the Section class.

E.g. Custom Section which consists of a tabbed PageFrame containing a Grid with a simple address book style navigation ListBox that populates the Grid with data when the ListBox is clicked.

custom_vfp4

//
// Lianja custom section for page "page1" section "section1"
//
//------------------------------------------------------------------------------
// declare a namespace - this is added by default when you use the template code
namespace custom_vfp
 
//------------------------------------------------------------------------------
// when a namespace is active public variables are added to the namespace
public ui_grid
 
//------------------------------------------------------------------------------
// Step 1: Define the classes we need
// Note that all Lianja UI Framework classes can be subclassed in Visual FoxPro
//
// Subclass a Section 
// Note how the event procedures are defined. These correspond to the navigation
// buttons in the section header.
define class page1_section1 as section
	proc init()
		// place your section "init" code here
	endproc
	proc add()
		// place your section "add" code here
	endproc
	proc delete()
		// place your "delete" code here
	endproc
	proc first()
		// place your "first" code here
	endproc
	proc previous()
		// place your move "previous" code here
	endproc
	proc next()
		// place your move "next" code here
	endproc
	proc last()
		// place your "last" code here
	endproc
	proc watch()
		// place your "watch" code here
	endproc
	proc refresh()
		// place your "refresh" code here
	endproc
	proc edit()
		// place your "edit" code here
	endproc
	proc search()
		// place your "search" code here
	endproc
	proc save()
		// place your "save" code here
	endproc
	proc cancel()
		// place your "cancel" code here
	endproc
enddefine
//--------------------------------------------------------------------------
// Subclass a Listbox so that we can define the Click event procedure
define class cls_listbox as ListBox
	proc click()
		ui_grid.clear
		// Note how the AddItems method of Grid, ListBox and Combobox can take 
		// a SQL SELECT statement as an argument
		if trim(this.text) = "All"
			ui_grid.additems('select * from example where last_name != " "') 
		else
			ui_grid.additems('select * from example where;
			upper(left(last_name,1)) = "' + trim(this.text) + '"') 
		endif
		ui_grid.refresh()
	endproc
enddefine
//-------------------------------------------------------------------------------
// Define the main procedure in the section file that will create the section and
// return it to Lianja.
// Note that this must be the same name as the file in which it is contained in.
proc page1_section1 
 
//--------------------------------------------------------------------------
// Make sure the database is open
if database() != "southwind"
	open database southwind
endif
//--------------------------------------------------------------------------
// Step 2: Create the Custom Section object
page1_section1 = createobject("page1_section1")
//--------------------------------------------------------------------------
// Step 3: Create a PageFrame class and add it to the Section
page1_section1.addobject("tabs", "pageframe")
//--------------------------------------------------------------------------
// Step 4: Add a Page to the PageFrame class and set some of its properties
tabs.addobject("ui_tab_customers", "page")
ui_tab_customers.caption = "Customers"
ui_tab_customers.show
//--------------------------------------------------------------------------
// Step 5: Add a Container to the Page and set some of its properties
ui_tab_customers.addobject("ui_cont", "container")
ui_cont.autosize = .t.
ui_cont.backcolor = "lightblue"
ui_cont.layout = "horizontal"
ui_cont.margin = 5 
ui_cont.spacing = 5
ui_cont.show
//--------------------------------------------------------------------------
// Step 6: Add a subclassed ListBox to the Container and set some of its properties
ui_cont.addobject("ui_listbox", "cls_listbox")
ui_listbox.fixedwidth = 200
//--------------------------------------------------------------------------
// Step 7: Invoke the AddItems method with a comma-separated list of items
// to add to the ListBox
ui_listbox.additems("All,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z")
ui_listbox.show
//--------------------------------------------------------------------------
// Step 8: Add a Grid to the Container 
// Note that ui_grid is a namespace variable
ui_cont.addobject("ui_grid", "grid")
ui_grid.show
ui_grid.rowheight = 20 
ui_grid.readonly = .t.
ui_grid.recordmark = .f.
ui_grid.closable = .f.
ui_grid.caption = "Sample data"
ui_grid.additems('select * from example where last_name != " "') 
ui_grid.refresh
ui_grid.autofit
//--------------------------------------------------------------------------
// Step 9: Add a couple more Page classes to the PageFrame
tabs.addobject("ui_tab_orders", "page")
ui_tab_orders.caption = "Orders"
tabs.addobject("ui_tab_shippers", "page")
ui_tab_shippers.caption = "Shippers"
//--------------------------------------------------------------------------
// Step 10: now we must return the Section back to Lianja
return page1_section1

https://www.lianja.com/doc/index.php/Developing_Lianja_Custom_Sections_in_Visual_FoxPro


Container classes are UI classes that can have other UI classes (Containers or Components) added to them to construct a hierarchical tree of visual elements. You add objects to existing objects using the AddObject( ) method of a container.  e.g.

// create a new object variable called "mygrid" which is a "Grid" 
myobj.addobject("mygrid", "grid")

Container classes are UI classes that can have other UI classes added to them and include the following.

  • Commandgroup
  • Container
  • Control
  • Gadget
  • Grid
  • Page
  • Pageframe
  • Section
  • Splitter
  • Tree

https://www.lianja.com/doc/index.php/Developing_Lianja_Custom_Sections_in_Visual_FoxPro


All classes in the Lianja UI Framework have Methods and Properties. Methods are procedures that control the behavior of the object and Properties are attributes that control the appearance and functionality of the object. All classes in the framework have a common set of Properties and Methods and others that are specific to the class. e.g.

Some common properties:

  • Left
  • Top
  • Width
  • Height
  • BackColor
  • ForeColor

Some common methods:

  • show
  • hide

Events are actions that are triggered when an object is affected by some external action e.g. clicking a CommandButton or editing a TextBox.

By subclassing the Lianja UI Framework classes you can define your own Event procedures that will be called when an event is triggered. e.g. let’s declare a class that subclasses a CommandButton and responds to the click event.

define class mybutton as commandbutton
 proc click( )
   MessageBox("You clicked the button!")
 endproc
enddefine

https://www.lianja.com/doc/index.php/Developing_Lianja_Custom_Sections_in_Visual_FoxPro


PHP:

All classes in the Lianja UI Framework have Methods and Properties. Methods are procedures that control the behavior of the object and Properties are attributes that control the appearance and functionality of the object. All classes in the framework have a common set of Properties and Methods and others that are specific to the class.

Custom Section which consists of a tabbed PageFrame containing a Grid with a simple address book style navigation ListBox that populates the Grid with data when the ListBox is clicked.

custom_php4

//--------------------------------------------------------------------------
//
// Lianja custom PHP section
//
//--------------------------------------------------------------------------
// Important note. In PHP to access outer variables from within class 
// methods you must declare them global and then specify global again
// within the class method
global $ui_grid;
global $ui_listbox;
// You can write to the console log from PHP like this 
Lianja::writeLog("Hello from PHP");
//--------------------------------------------------------------------------
// Step 1: Define the classes we need
// Note how the Lianja UI Framework classes are subclassed in PHP 
// using the __construct() magic method.
class mySection extends Lianja     
{
    function __construct()
    {
        parent::__construct("Section");
    }
 
    function add()
    {
        Lianja::showMessage("add() was called");
    }
 
    function delete()
    {
        Lianja::showMessage("delete() was called again");
    }
 
    function first()
    {
        Lianja::showMessage("first() was called");
    }
 
    function previous()
    {
        Lianja::showMessage("previous() was called");
    }
 
    function next()
    {
        Lianja::showMessage("next() was called");
    }
 
    function last()
    {
        Lianja::showMessage("last() was called");
    }
 
    function watch()
    {
        Lianja::showMessage("watch() was called");
    }
 
    function edit()
    {
        Lianja::showMessage("edit() was called");
    }
 
    function save()
    {
        Lianja::showMessage("save() was called");
    }
 
    function cancel()
    {
        Lianja::showMessage("cancel() was called");
    }
 
    function refresh()
    {
    	;
    }
}
//--------------------------------------------------------------------------
// Note how the click() event handler for the Listbox is defined in PHP 
// just as a normal class method.
class myListbox extends Lianja
{
    function __construct()
    {
        parent::__construct("Listbox");
    }
 
    function click()
    {
        // Important note. In PHP to access outer variables from within class 
        // methods you must declare them global and then specify global again
        // within the class method
        global $ui_grid;
        global $ui_listbox;
        $ui_grid->clear();  
        // Note how the AddItems" method of Grid, ListBox and ComboBox can take 
        // a SQL SELECT statement as an argument
        if ($ui_listbox->text == "All")
        {
            $ui_grid->additems('select * from southwind!example where 
                last_name != " "');
        }
        else
        { 
            $ui_grid->additems('select * from southwind!example where
                upper(left(last_name,1)) = "' . $ui_listbox->text . '"');
        }
        $ui_grid->refresh();
        Lianja::writeLog("clicked again");
    }
}
//--------------------------------------------------------------------------
// Step 2: Create the Section object
$page1_section1_section = Lianja::createObject("Section"); 
//--------------------------------------------------------------------------
// Step 3: Create a PageFrame object and add it to the Section
$page1_section1_section->addObject("ui_tabs", "Pageframe");
 
//--------------------------------------------------------------------------
// Step 4: Add a Page to the PageFrame object and set some of its properties
$ui_tabs->addobject("ui_tab_customers", "Page");
$ui_tab_customers->caption = "Customers";
 
//--------------------------------------------------------------------------
// Step 5: Add a Container to the Page and set some of its properties
// The AddObject() method takes the objectname as the first arg then 
// the classname as the second.
$ui_tab_customers->addobject("ui_cont", "Container"); 	
$ui_cont->autosize = 1;
$ui_cont->backcolor = "lightgray";
$ui_cont->layout = "horizontal";
$ui_cont->margin = 5;
$ui_cont->spacing = 5;
 
//--------------------------------------------------------------------------
// Step 6: Add a ListBox to the Container and set some of its properties
$ui_cont->addobject("ui_listbox", "myListbox");
$ui_listbox->fixedwidth = 200; 
//--------------------------------------------------------------------------
// Step 7: Invoke the AddItems method with a comma-separated list of items 
// to add to the ListBox
$ui_listbox->additems("All,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z");
 
//--------------------------------------------------------------------------
// Step 8: Add a Grid to the Container
$ui_cont->addobject("ui_grid", "Grid");
$ui_grid->rowheight = 20;
$ui_grid->readonly = 1;
$ui_grid->recordmark = 0;
$ui_grid->closable = 0;
$ui_grid->caption = "Sample data";
$ui_grid->additems('select * from southwind!example where last_name != " "');
$ui_grid->autofit( );
$ui_grid->show();
//--------------------------------------------------------------------------
// Step 9: Add a couple more Page objects to the PageFrame
$ui_tabs->addobject("ui_tab_orders", "Page");
$ui_tab_orders->caption = "Orders";
$ui_tabs->addobject("ui_tab_shippers", "Page");
$ui_tab_shippers->caption = "Shippers";
//--------------------------------------------------------------------------
// Step 10: Return the section back to the Lianja. We accomplish this by assigning
// it to the global returnvalue variable.
$returnvalue = $page1_section1_section;

When you develop a Custom Section or Gadget in PHP, the Lianja UI Framework makes available several built-in global PHP functions to enable you to interact with Lianja and the embedded Lianja database. This provides you with a embedded PHP database with full SQL and noSQL data access.

  • Lianja::createObject(objectname, classname)
  • Lianja::openDatabase(dbname)
  • Lianja::showMessage(messagetext)
  • Lianja::execute(lianjacommandstring)
  • Lianja::evaluate(lianjaexpression)

Container classes are UI classes that can have other UI classes (Containers or Components) added to them to construct a hierarchical tree of visual elements. You add objects to existing objects using the AddObject( ) method of a container. The first argument is the name of the object you want to create and the second is the name of the class that you want to instantiate e.g.

// create a new object called "myobj" which is a "Container"
$myobj = Lianja::createObject("Container");
 
// add a new object variable called "mygrid" which is a "Grid" 
$myobj->addObject("mygrid", "Grid");

Events are actions that are triggered when an object is affected by some external action e.g. clicking a CommandButton or editing a TextBox.

By subclassing the Lianja UI Framework classes you can define your own Event procedures that will be called when an event is triggered. e.g. let’s declare a class that subclasses a CommandButton and responds to the click event.

class myButton extends Lianja
{
    function __construct()
    {
        parent::__construct("CommandButton");
    }
    
    function click()
    {
        Lianja::showmessage("You clicked the button!");
    }
}

https://www.lianja.com/doc/index.php/Developing_Lianja_Custom_Sections_in_PHP


Python:

Custom Section which consists of a tabbed PageFrame containing a Grid with a simple address book style navigation ListBox that populates the Grid with data when the ListBox is clicked.

custom_py4

#
# Lianja custom Python section "page1_section1"
#
import Lianja
#--------------------------------------------------------------------------
# Step 1: Define the classes we need
# Note that all Lianja UI Framework classes can be subclassed in Python
class mySection(Lianja.Section):
    def add(self):
        Lianja.showMessage("add() was called")
 
    def delete(self):
        Lianja.showMessage("delete() was called")
 
    def first(self):
        Lianja.showMessage("first() was called")
 
    def previous(self):
        Lianja.showMessage("previous() was called")
 
    def next(self):
        Lianja.showMessage("next() was called")
 
    def last(self):
        Lianja.showMessage("last() was called")
 
    def refresh(self):
        pass
 
    def search(self):
        pass
 
    def watch(self):
        Lianja.showMessage("watch() was called")
 
    def edit(self):
        Lianja.showMessage("edit() was called")
 
    def save(self):
        Lianja.showMessage("save() was called")
 
    def cancel(self):
        Lianja.showMessage("cancel() was called")
 
#--------------------------------------------------------------------------
# Note how the click() event handler for the ListBox is defined in Python
class myListbox(Lianja.Listbox):
    def click(self):
        ui_grid.clear( )
        # Note how the AddItems method of Grid, ListBox and ComboBox can take 
        # a SQL SELECT statement as an argument
        if ui_listbox.text == "All":
            ui_grid.additems('select * from southwind!example where last_name != " "')
        else: 
            ui_grid.additems('select * from southwind!example where upper(left(last_name,1)) \
            = "' + ui_listbox.text + '"')
        ui_grid.refresh( )
 
#--------------------------------------------------------------------------
# Step 2: Create the Section object
# Note that the CreateObject() method needs two args: objectname, classname
oSection = Lianja.createObject("oSection", "mySection")
oSection.backcolor = "lightgreen"
oSection.caption = "This is a custom Python section"
 
#--------------------------------------------------------------------------
# Step 3: create a PageFrame object and add it to the Section
oSection.addObject("ui_tabs", "Pageframe")
 
#--------------------------------------------------------------------------
# Step 4: Add a Page to the Pageframe object and set some of its properties
ui_tabs.addobject("ui_tab_customers", "Page")
ui_tab_customers.caption = "Customers"
 
#--------------------------------------------------------------------------
# Step 5: Add a Container to the Page and set some of its properties
# The AddObject() method takes the objectname as the first arg then the classname as the second.
ui_tab_customers.addobject("ui_cont", "Container") 	
ui_cont.autosize = 1
ui_cont.backcolor = "lightblue"
ui_cont.layout = "horizontal"
ui_cont.margin = 5
ui_cont.spacing = 5
 
#--------------------------------------------------------------------------
# Step 6: Add a ListBox to the Container and set some of its properties
ui_cont.addobject("ui_listbox", "myListbox")
ui_listbox.fixedwidth = 200
 
#--------------------------------------------------------------------------
# Step 7: Invoke the AddItems method with a comma separated list of items to add to the ListBox
ui_listbox.additems("All,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z")
 
#--------------------------------------------------------------------------
# Step 8: Add a Grid to the Container
ui_cont.addobject("ui_grid", "Grid")
ui_grid.rowheight = 20
ui_grid.readonly = 1
ui_grid.recordmark = 0
ui_grid.closable = 0
ui_grid.caption = "Sample data"
ui_grid.additems('select * from southwind!example where last_name != " "')
ui_grid.autofit( )
ui_grid.refresh( )
 
#--------------------------------------------------------------------------
# Step 9: Add a couple more Page objects to the PageFrame
ui_tabs.addobject("ui_tab_orders", "Page")
ui_tab_orders.caption = "Orders"
ui_tabs.addobject("ui_tab_shippers", "Page")
ui_tab_shippers.caption = "Shippers"
 
#--------------------------------------------------------------------------
# Step 10: Return the section back to the Lianja. We accomplish this by assigning
# it to the global returnvalue variable.
returnvalue = oSection

When you develop a Custom Section or Gadget in Python, the Lianja UI Framework makes available several built-in global Python functions to enable you to interact with Lianja and the embedded Lianja database. This provides you with a embedded Python database with full SQL and noSQL data access.

# include the lianja module
import Lianja
  • Lianja.createObject(objectname, classname)
  • Lianja.openDatabase(dbname)
  • Lianja.showMessage(messagetext)
  • Lianja.execute(lianjacommandstring)
  • Lianja.evaluate(lianjaexpression)

Container classes are UI classes that can have other UI classes (Containers or Components) added to them to construct a hierarchical tree of visual elements. You add objects to existing objects using the AddObject( ) method of a container. The first argument is the name of the object you want to create and the second is the name of the class that you want to instantiate e.g.

# include the lianja module
import Lianja
 
# create a new object called "myobj" which is a "Container"
myobj = Lianja.createObject("myobj", "Container")
 
# add a new object variable called "mygrid" which is a "Grid" 
myobj.addObject("mygrid", "Grid")

Container classes are UI classes that can have other UI classes added to them and include the following.

  • Commandgroup
  • Container
  • Control
  • Gadget
  • Grid
  • Page
  • Pageframe
  • Section
  • Splitter
  • Tree

All classes in the Lianja UI Framework have Methods and Properties. Methods are procedures that control the behavior of the object and Properties are attributes that control the appearance and functionality of the object. All classes in the framework have a common set of Properties and Methods and others that are specific to the class. e.g.

Some common properties:

  • Left
  • Top
  • Width
  • Height
  • BackColor
  • ForeColor

Some common methods:

  • show
  • hide

Events are actions that are triggered when an object is affected by some external action e.g. clicking a CommandButton or editing a TextBox.

By subclassing the Lianja UI Framework classes you can define your own Event procedures that will be called when an event is triggered. e.g. let’s declare a class that subclasses a CommandButton and responds to the click event.

import Lianja
 
class mybutton(Lianja.Commandbutton):
    def click(self):
        Lianja.showMessage("You clicked the button!")

ty classes available in the Lianja UI Framework

https://www.lianja.com/doc/index.php/Developing_Lianja_Custom_Sections_in_Python


JS:

Custom Section which consists of a tabbed PageFrame containing a Grid with a simple address book style navigation ListBox that populates the Grid with data when the ListBox is clicked.

custom_js4

//
// Lianja custom JavaScript section "page1_section1"
//
//--------------------------------------------------------------------------
// Step 1: Create the custom section object
// Note that the CreateObject() function needs two args: objectname, classname
oSection = createobject("oSection", "section");
 
//--------------------------------------------------------------------------
// Step 2: Create a PageFrame class and add it to the Section
oSection.addobject("ui_tabs", "pageframe");
 
//--------------------------------------------------------------------------
// Step 3: Add a Page to the PageFrame class and set some of its properties
ui_tabs.addobject("ui_tab_customers", "page");
ui_tab_customers.caption = "Customers";
 
//--------------------------------------------------------------------------
// Step 4: Add a Container to the Page and set some of its properties
// the AddObject() method takes the object name as the first arg then the 
// class name as the second.
ui_tab_customers.addobject("ui_cont", "container") ;	
ui_cont.autosize = 1;
ui_cont.backcolor = "lightblue";
ui_cont.layout = "horizontal";
ui_cont.margin = 5;
ui_cont.spacing = 5;
 
//--------------------------------------------------------------------------
// Step 5: Add a ListBox to the Container and set some of its properties
ui_cont.addobject("ui_listbox", "Listbox");
ui_listbox.fixedwidth = 200;
 
//--------------------------------------------------------------------------
// Step 6: Declare event callbacks for objects using JavaScript closures
// like this:
ui_listbox.click = function( )
{
    ui_grid.clear( );
    // Note how the AddItems method of Grid, LisBbox and ComboBox can take 
    // a SQL SELECT statement as an argument
    if (ui_listbox.text.trim( ) == "All")
    {
        ui_grid.additems('select * from southwind!example where last_name != " "'); 
    } 
    else 
    {
        ui_grid.additems('select * from southwind!example where ' +
                    'upper(left(last_name,1)) = "' + ui_listbox.text.trim( ) + '"');
    }
    ui_grid.refresh( );
};
 
//--------------------------------------------------------------------------
// Step 7: Invoke the AddItems method with a comma-separated list of items
// to add to the Listbox
ui_listbox.additems("All,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z");
 
//--------------------------------------------------------------------------
// Step 8: Add a Grid to the Container
ui_cont.addobject("ui_grid", "grid");
ui_grid.show( );
ui_grid.rowheight = 20;
ui_grid.readonly = 1;
ui_grid.recordmark = 0;
ui_grid.closable = 0;
ui_grid.caption = "Sample data";
ui_grid.additems('select * from southwind!example where last_name != " "');
ui_grid.autofit( );
ui_grid.refresh( );
 
//--------------------------------------------------------------------------
// Step 9: Add a few more Page classes to the PageFrame
ui_tabs.addobject("ui_tab_orders", "page");
ui_tab_orders.caption = "Orders";
ui_tabs.addobject("ui_tab_shippers", "page");
ui_tab_shippers.caption = "Shippers";
 
//--------------------------------------------------------------------------
// Step 10: Now return the section back to the Lianja. We accomplish
// this by assigning it to the returnvalue variable.
returnvalue = oSection;

When you develop a Custom Section or Gadget in JavaScript, the Lianja UI Framework makes available several built-in global JavaScript functions to enable you to interact with Lianja and the embedded Lianja database. This provides you with a embedded JavaScript database with full SQL and noSQL data access.

  • createObject(objectname, classname)
  • openDatabase(dbname)
  • showMessage(messagetext)
  • execute(lianjacommandstring)
  • evaluate(lianjaexpression)
  • require(filename)
  • require_once(filename)
  • include(filename)
  • include_once(filename)

Container classes are UI classes that can have other UI classes (Containers or Components) added to them to construct a hierarchical tree of visual elements. You add objects to existing objects using the AddObject( ) method of a container. The first argument is the name of the object you want to create and the second is the name of the class that you want to instantiate e.g.

// create a new object called "myobj" which is a "Container"
myobj = createObject("myobj", "Container");
 
// add a new object variable called "mygrid" which is a "Grid" 
myobj.addObject("mygrid", "grid");

Container classes are UI classes that can have other UI classes added to them and include the following.

  • Commandgroup
  • Container
  • Control
  • Gadget
  • Grid
  • Page
  • Pageframe
  • Section
  • Splitter
  • Tree

All classes in the Lianja UI Framework have Methods and Properties. Methods are procedures that control the behavior of the object and Properties are attributes that control the appearance and functionality of the object. All classes in the framework have a common set of Properties and Methods and others that are specific to the class. e.g.

Some common properties:

  • Left
  • Top
  • Width
  • Height
  • BackColor
  • ForeColor

Some common methods:

  • show
  • hide

Events are actions that are triggered when an object is affected by some external action e.g. clicking a CommandButton or editing a TextBox.

By subclassing the Lianja UI Framework classes you can define your own Event procedures that will be called when an event is triggered. e.g. let’s declare a class that subclasses a CommandButton and responds to the click event.

myobj = createobject("myobj", "Commandbutton");
 
// You declare event callbacks for objects using javascript closures like this:
myobj.click = function( )
{
    // place your event handler here
};

https://www.lianja.com/doc/index.php/Developing_Lianja_Custom_Sections_in_JavaScript


 

Custom search [examples]

The Section header has a “search” icon calling “Custom search delegate”

450px-customqueryvfp

The code in the custom search delegate. It could be a modal “form” built out of the Lianja UI Framework components.

////////////////////////////////////////////////////////////////
// Event delegate for 'customsearch' event
proc Customers_section1_customsearch()
	m_recno = recno()
	m_select = select()
	select customers
	browse caption "Customers" noedit ;
		fields companyname:h="Company Name" size 400,400 title "Select a Customer"
        select m_select
	if _result != 0
		Lianja.getElementByID("Customers.section1").goto(_result)
 		return
	endif
	goto m_recno
endproc

https://www.lianja.com/doc/index.php/Developing_Custom_Query_Builders_in_Visual_FoxPro


 

 

 

Custom gadget [examples]

Custom Gadgets are built using the Lianja UI Framework. When building a Custom Gadget you should subclass the Gadget class.

gadgets_vfp2

//
// Lianja custom gadget for page "page1" section "section1" gadget "gadget1"
//
//---------------------------------------------------------------------------
// Declare a namespace
namespace customgadget
 
//---------------------------------------------------------------------------
// When a namespace is active, public variables are added to the namespace
public improper, proper
 
//---------------------------------------------------------------------------
// Subclass a commandbutton so that we can define the Click event procedure
define class ProperButton as CommandButton
    proc click()
        proper.text = proper(improper.text)
    endproc
enddefine
//---------------------------------------------------------------------------
// Define the main procedure to create the gadget and return it to Lianja
// Note that this MUST be the same name as the file in which it is contained
proc gadget1
    gadget1 = createobject("Gadget") 
    gadget1.addobject("dowhat", "Label")
    gadget1.addobject("improper", "Textbox")
    gadget1.addobject("proper", "Label")
    gadget1.addobject("proper_button", "ProperButton")
    dowhat.text = "Text to convert to proper case:"
    proper_button.caption = "Convert to proper case"
return gadget1

 

gadgets3

Modifying the properties of the objects we have added to the Gadget allows us to alter their appearance. This includes the stylesheet property, which can be assigned a text string containing CSS settings or the name of a CSS file

proc gadget1
    gadget1 = createobject("Gadget") 
    gadget1.addobject("dowhat", "Label")
    gadget1.addobject("improper", "Textbox")
    gadget1.addobject("proper", "Label")
    gadget1.addobject("proper_button", "ProperButton")
    dowhat.text = "Text to convert to proper case:"
    proper_button.caption = "Convert to proper case"
    dowhat.stylesheet = "color: white; background-color: orange; border: ";
	  + "2px groove black; border-radius: 10px; opacity: 1; padding: 2px 4px"
    dowhat.alignment = 2
    dowhat.borderstyle = 1
    improper.fixedheight = 50
    improper.stylesheet = "app:/textbox.css"
    proper.fixedheight = 50
    proper.stylesheet = "color: black; background-color: white; border: ";
	  + "2px groove gray; border-radius: 10px; opacity: 1; padding: 2px 4px"
    proper_button.fixedheight = 50
    proper_button.fontsize = 14
    proper_button.stylesheet = "app:/button.css"
return gadget1

https://www.lianja.com/doc/index.php/Developing_Lianja_Custom_Gadgets_in_Visual_FoxPro


PHP:

Custom Gadget which consists of a Textbox for data entry, Labels for textual display and a CommandButton which causes the case of the data entered to be changed when it is clicked.

gadgets_php2

//
// Lianja custom gadget for page "page1" section "section1" gadget "gadget4"
//
//--------------------------------------------------------------------------
// To access outer variables from within class methods you must declare them
// global and then specify global again within the class method
global $uppertext;
global $lowertext;
//--------------------------------------------------------------------------
// Define the class we need to handle the CommandButton Click() event
class LowButton extends Lianja
{
    function __construct()
    {
        parent::__construct("CommandButton");
    }
 
    function click()
    {
        global $uppertext;
        global $lowertext;
        $upstring = $uppertext->text;
        $lowertext->text = strtolower($upstring);
    }
}
//--------------------------------------------------------------------------
// Create the gadget and add controls
$gadget4 = Lianja::createObject("Gadget");
$gadget4->addobject("how", "Label");
$gadget4->addobject("uppertext", "Textbox");
$gadget4->addobject("lowertext", "Label");
$gadget4->addobject("lowbutton", "LowButton");
$how->text="Text to convert to lower case:";
$lowbutton->caption="Convert to lower case";
//--------------------------------------------------------------------------
// Return the gadget back to Lianja
$returnvalue = $gadget4;

gadgets4

Modifying the properties of the objects we have added to the Gadget allows us to alter their appearance. This includes the stylesheet property, which can be assigned a text string containing CSS settings or the name of a CSS file. For example:

$how->stylesheet = "color: white; background-color: orange; border: 
	2px groove black; border-radius: 10px; opacity: 1; padding: 2px 4px";
$how->alignment = 2;
$how->borderstyle = 1;
$uppertext->fixedheight = 50;
$uppertext->stylesheet = "app:/textbox.css";
$lowertext->fixedheight = 50;
$lowertext->stylesheet = "color: black; background-color: white; border: 
	2px groove gray; border-radius: 10px; opacity: 1; padding: 2px 4px";
$lowbutton->fixedheight = 50;
$lowbutton->fontsize = 14;
$lowbutton->stylesheet = "app:/button.css";

Python:

Custom Gadget which consists of a Textbox for data entry, Labels for textual display and a CommandButton which causes the case of the data entered to be changed when it is clicked.

gadgets_py2

#
# Lianja custom gadget for page "page1" section "section1" gadget "gadget3"
#
#---------------------------------------------------------------------------
import Lianja
#---------------------------------------------------------------------------
# Define the class we need to handle the button click event
class SwapButton(Lianja.Commandbutton):      
    def click(self):
    	str = starttext.text
    	swapped.text = str.swapcase()
#---------------------------------------------------------------------------
# Create the gadget and add in the controls
gadget3 = Lianja.createObject("gadget3", "Gadget")
gadget3.addobject("instructions", "Label")
gadget3.addobject("starttext", "Textbox")
gadget3.addobject("swapped", "Label")
gadget3.addobject("swapbutton", "SwapButton")
instructions.text = "Text to swap case:"
swapbutton.caption = "Swap case"
#---------------------------------------------------------------------------
# Return the gadget to Lianja
returnvalue = gadget3

Modifying the properties of the objects we have added to the Gadget allows us to alter their appearance. This includes the stylesheet property, which can be assigned a text string containing CSS settings or the name of a CSS file. For example:

gadgets31

instructions.stylesheet = "color: white; background-color: orange; \
border: 2px groove black; border-radius: 10px; opacity: 1; padding: 2px 4px"
instructions.alignment = 2
instructions.borderstyle = 1
swapbutton.fixedheight = 50
swapbutton.fontsize = 14
swapbutton.stylesheet = "app:/button.css"
starttext.fixedheight = 50
starttext.stylesheet = "app:/textbox.css"
swapped.fixedheight = 50
swapped.stylesheet = "color: black; background-color: white; \
border: 2px groove gray; border-radius: 10px; opacity: 1; padding: 2px 4px"

https://www.lianja.com/doc/index.php/Developing_Lianja_Custom_Gadgets_in_Python


JS:

Custom Gadget which consists of a Textbox for data entry, Labels for textual display and a CommandButton which causes the case of the data entered to be changed when it is clicked.

gadgets_js2

//
// Lianja custom gadget for page "page1" section "section1" gadget "gadget2"
// 
//-------------------------------------------------------------------------- 
// Create the gadget object and add controls
gadget2 = createobject("gadget2","gadget"); 
gadget2.addobject("howto", "label");
gadget2.addobject("lowertext", "textbox");
gadget2.addobject("converted", "label");
gadget2.addobject("upbutton", "commandbutton");
howto.text = "Text to convert to upper case:";
upbutton.caption = "Convert to upper case";
 
//-------------------------------------------------------------------------- 
// Handle the button click() event
upbutton.click = function()
{
    lowstring = lowertext.text;
    converted.text = lowstring.toUpperCase();
};
 
//-------------------------------------------------------------------------- 
// Return the gadget back to Lianja
returnvalue = gadget2;

Modifying the properties of the objects we have added to the Gadget allows us to alter their appearance. This includes the stylesheet property, which can be assigned a text string containing CSS settings or the name of a CSS file. For example:

gadgets41

howto.stylesheet = "color: white; background-color: orange; border: " +
	"2px groove black; border-radius: 10px; opacity: 1; padding: 2px 4px";
howto.alignment = 2;
howto.borderstyle = 1;
lowertext.fixedheight = 50;
lowertext.stylesheet = "app:/textbox.css";
converted.fixedheight = 50;
converted.stylesheet = "color: black; background-color: white; border: " +
	"2px groove gray; border-radius: 10px; opacity: 1; padding: 2px 4px";
upbutton.fixedheight = 50;
upbutton.fontsize = 14;
upbutton.stylesheet = "app:/button.css";

https://www.lianja.com/doc/index.php/Developing_Lianja_Custom_Gadgets_in_JavaScript


 

Custom components

  • Add support for visually designing pages and sections that are not included in the desktop/web/mobile generated runtime code. These are known as “Custom Component” pages (a new attribute in the page attributes). Their primary purpose is to provide the ability to build custom components visually. (See below).

 

  • Add the ability to save a form/canvas/webview section as a custom component which can be embedded in a cell of a grid or embedded in a cell of a formgrid section. Custom components are saved into the lib:/components/component directory as code in the scripting language specified for the section. If you want the component to be able to be used in desktop/web and mobile apps then you should specify javascript or typescript as the scripting language. When you save a section as a custom component the code for it will be automatically generated. The name of the component is taken from the custom component library name (in the page attributes) and the section name and should be globally unique. For example, a page with the custom component library name of “com_lianja” and a section id of “orderform” would generate a lib:/components/com_lianja/com_lianja_orderform directory containing (in the case of javascript) a single file named com_lianja_orderform.js which contains a single javascript function com_lianja_orderform() which dynamically creates the component when invoked. You should not edit this code as it will be generated automatically every time you save changes to a “Custom Component page”. Note also that whenever a custom component is saved during development and it’s code generated there is a Lianja package automatically generated called (in this case) com_lianja.lpk which contains all of its custom components. This is placed in the packages directory. You can then redistribute this package file as a third party component library which can be used by programmers and NoCode developers.

This will provide professional developers the opportunity to offer custom components that can be used by Lianja NoCode developers to further accelerate Rapid App Development.


having the component available in the lib:/ makes them easily available throughout the multiple functional apps that comprise a full-featured application.


I can see a benefit to being able to supply a “component library” name at the Application and Project levels, with App defaulting to Project, page defaulting to App. Right now there isn’t the ability to specify default attributes at the project level. There are a number of attributes that should default across a project given that a project could well have 15 or 20 applications.