Library [examples]

Open the Script Editor in the Library workspace to edit program or other text files
MODIFY_LIBRARY
// Open the Script Editor in the Library workspace to edit program or other text files 

modify file myprg
modify file myjs.js

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


Load a library file built with the Lianja C Extensions API
SET_LIBRARY
// Open Samples.so API procedure library
set library to samples.so
// Open pdf.so procedure library without closing active libraries
set library to pdf.so additive
// Close pdf.so API procedure library
release library pdf.so
// Close all active API procedure library files
set library to

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


Close an active API library file
RELEASE_LIBRARY
// Open Samples.so API procedure library
set library to samples.so
// Open pdf.so procedure library without closing active libraries
set library to pdf.so additive
// Close pdf.so API procedure library
release library pdf.so
// Close all active API procedure library files
set library to

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


Load an API library file
LOADLIBRARY
// Open example API extension library
loadlibrary("example.dll") 
 
// Open pdf.so procedure library without closing active libraries
set library to pdf.so additive
 
// Close pdf.so API procedure library
release library pdf.so
 
// Close all active API extension libraries
set library to

https://www.lianja.com/doc/index.php/LOADLIBRARY()


Load a library file built with the Lianja C Extensions API, a Lianja procedure library or a JavaScript (.js), PHP (.php) or Python (.py) file
REQUIRE
// Open Samples.so API procedure library
require("Samples")
// Close pdf.so API procedure library
release library pdf.so
// Close all active API procedure library files
set library to

https://www.lianja.com/doc/index.php/REQUIRE()


Load a Lianja C Extensions API, a Lianja procedure library or a JavaScript (.js), PHP (.php) or Python (.py) file
REQUIRE_ONCE
// Open Samples.so C extension API procedure library
require_once("Samples")
// Close pdf.so C extension API procedure library
release library pdf.so
// Close all active C extension API procedure library files
set library to

https://www.lianja.com/doc/index.php/REQUIRE_ONCE()


Close one or more class library files
CLOSE_CLASSLIB
set classlib to myclasses
set classlib to sharedclasses additive
close classlib sharedclasses
close classlib

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


Close one or more class library files
RELEASE_CLASSLIB
set classlib to myclasses
set classlib to sharedclasses additive
release classlib sharedclasses
release classlib

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


Current library directory
LIBDIR
? libdir()
C:\Lianja\library\
? Lianja.libdir
C:\Lianja\library\

https://www.lianja.com/doc/index.php/LIBDIR()


Return the string “../../library/”
LIBPATH
<%@ Language=VFP %>

<% /////////////////////////////////////////////////////////////////////////////////////////////////////////// set macros on set fixed on private m_libpath = libPath() ? ” ? ‘http://&m_libpath/jquery-1.10.2/jquery-1.10.2.min.js‘ ? ‘http://&m_libpath/bootstrap-3.3.4/js/bootstrap.min.js‘ %>

<% // ...

https://www.lianja.com/doc/index.php/LIBPATH()


Registers a function in an external shared 32-bit dynamic link library (.dll) file (Windows only)

DECLARE_-_DLL
DECLARE INTEGER CreateProcess IN kernel32.dll as CreateProcess; 
STRING lpApplicationName,;
STRING lpCommandLine,;
INTEGER lpProcessAttributes,;
INTEGER lpThreadAttributes,;
INTEGER bInheritHandles,;
INTEGER dwCreationFlags,;
INTEGER lpEnvironment,;
STRING lpCurrentDirectory,;
STRING lpStartupInfo,;
STRING @ lpProcessInformation

https://www.lianja.com/doc/index.php/DECLARE_-_DLL


Procedure library setting
PROCLIBS
set procedure to lib1
set procedure to lib2 additive
? proclibs()
/home/apps/test/lib1.dbo,/home/apps/test/lib2.dbo

https://www.lianja.com/doc/index.php/PROCLIBS()


Load a procedure or C Extensions library
INCLUDE_ONCE
// Open pdf.so C extensions library located in current directory
include("pdf.so")
// Close pdf.so C extensions library
release library pdf.so
// Close all active C extensions library files
set library to

https://www.lianja.com/doc/index.php/INCLUDE_ONCE()


Load a procedure or C Extensions library
INCLUDE
// Open pdf.so C extensions library located in current directory
include("pdf.so")
// Close pdf.so C extensions library
release library pdf.so
// Close all active C extensions library files
set library to

https://www.lianja.com/doc/index.php/INCLUDE()


 

Library

Q:

I have a file in the library called convert2.dbo
I am trying to call the file like so:

Code:
c:\lianja\bin\lianjaruntime.exe lib:/convert2dbo.dbo  --args "'TEST5_1_000001.jpg','TEST5_1_025001.jpg',50,'R:\test5\test5_ROLL2',2,'test5'"

I have also tried

Code:
lib:\

But not luck.

When I change it back to a file in the application it runs fine.

A:

Lianjaruntime.exe has no idea, on its own, where lib: is. Even if you are calling it with a run or spawn from inside Lianja. It’s in its own process.

You can specify –runtimedir to tell it where these files dirs are: this would (perhaps: I have a memory of it not doing so) make the LIB files automatically available.

You can specify –dir to set the default directory (the equivalent of having selected an app).

I have code that predates these switches where I use left(sys(16),3) in the .dbo I’m calling to get the current drive and then figure everything out from there. Only works in Windows.  I should change it to set(“dire”) which is also in Lianja now. That would make it OS independent. That particular SET(“directory”) command never got documented in VFP, although it was brought to their attention. It was very handy in VFP and is even handier here.


 

Library

Custom libraries are loaded internally and are not affected by SET PROCEDURE TO in any way at all.
This is another reason why I recommend their use.


No I’m referring to the custom library for the App itself.
Go into App settings.
Scroll down the attributes to the delegates.
There is a custom library that gets automatically created if you create an init, load, ready, unload, inactive delegate.
Editing that custom library lets you add your own functions.
There is a custom library for each App, Page and Section. That’s where the delegates live.
Custom libraries are automatically opened when the App is loaded. They are monitored for changes for you and recompiled and reloaded. This is a fundamental part of the Lianja App Builder development cycle. There is no explicit compile or build required.
This is the same principle for all of the supported scripting languages; Lianja/VFP, JavaScript, PHP or Python.


My recommendation would be to place these functions in the App custom library rather than an external library loaded with SET PROCEDURE TO.
Why? Because lianja knows when any of these files have been edited and automatically recompiles and reloads them. That is not the case with SET PROCEDURE TO. This is exactly what happens when you edit your delegates, custom section code or ,rsp files that generate dynamic WebView content too. There is no compile and build steps required. It is done for you as the whole App is live. The UI knows when files have changed.
Also an advantage to this approach is that it is scripting language independent.
Note also that if you must use SET PROCEDURE TO you can check to see whether the library is already loaded by looking for a “well known function” in the library e.g.

Code:
if not function_exists("__mylib__")
    Set procedure to mylib additive
    // inside mylib.prg declare an empty function called __mylib__
Endif

// alternatively use require_once() which does all the hard work for you

Code:
require_once("mylib")

Q:
I realise that sometimes, my changes will not take effect if I run the app immediately after making the changes
I need to load another app and reload back my original app.
May I know if there is a better way to force a refresh so that when I run the app, it will take the latest source files?
A:
If you are using custom libraries these will automatically be recompiled and reloaded if they are edited.
If you have libraries that you are using that Lianja knows nothing about then you will need to save and reload your application for these to take effect.


In Lianja “Procedure libraries” can contain:
– classes
– procedures
– functions
Procedures and Functions are essentially the same thing. It’s good practice to use “Function” if it returns a result and “Procedure” if it does not. It’s all down to personal taste.
Script files (.prg) are opened and closed every time you call them. Not a good idea for your own functions. The file should just contain the code.

Code:
//myfunc.prg
return "Hello world"
//mylib.prg
function myfunc()
return "Hello world"

Q:
I have no problem defining multiple functions in libraries but I cannot see how to call these directly from attributes (without having an intermediate prg file as per my first post)
A:
Just edit a custom library, add your function and specify it in an expression:

Code:
myfunc()

and in a custom library:

Code:
function myfunc()
// your code
endfunc

Custom libraries are always opened when your app is opened.
When you edit a custom library Lianja detects that it has changed and will reload it automatically and compile it.



Library

Q:
If I have a .prg in my app and I right-click & select ‘Add to Library‘ then the prg gets copied into the library section and I can use it as a library file, all ok.
The original file stays behind with the ‘app files’ though and it appears that there is no link between the newly created ‘library file’ and the original one because changes are not persisted between them – is this just done for safety? I guess after adding a file to the library I would probably want to delete the original one from the app right?
A:
In an App, when you ‘Add to library’ (prg script file), the prg is copied to the library and can be used by other Apps. There is no link between the original App prg and the library copy. Changes to the library copy should be made in the Library workspace. If you want to use the library copy from your originating App, then yes, delete the App prg.
If you have files called ‘myprg.prg’ in both your App and the Library and issue ‘do myprg’, the one in the App will be run. If you issue ‘do myotherprg’ and no myotherprg.prg exists in the current App, then the Library will be checked and the file run if it exists.


with the library page in the library, the code called by the library page has to be in the library, and the delegates referenced in the page attributes have to have the lib:/ prefix on them


Q:
from a page, I open a saved page in the “Page Library” with the command: Lianja.showDialog (….), or showDialogPanel, is the same.
If I try to debug, I do not see the code executed ..
will it be possible to debug pages viewed with lianja.showDialog ()?
A:
what I’ve found is that if the debugger misses where I put the breakpoint, I start in the program that calls the one I’m interested in, and then step into it.
A2:
In the past when I have had to debug a page that gets called from showdialog, I debugged it from the original project.
Meaning – lets say I had a project called leftpage. I then used that in another project called mainpage.
When I opened mainpage, I could not debug leftpage.
So I opened the project called lefpage and debugged the code in the original project where the code was created.



 

Library

Q:
when I set an external library loaded with SET PROCEDURE TO, I lose access to the custom library functions or both are available?
A:
You will still have access to your App’s custom library/libraries.
You can use SET PROCEDURE TO <lib> ADDITIVE for multiple extra procedure/function libraries.
The ADDITIVE means that it is opened in addition to any existing libraries.
The LIST PROCEDURE command will list the procedures and functions that are currently defined.


Q:
I have a page, “Leave_balance” in my app
I opened my app and goto “Console” workspace
When I issue the command, “Lianja.ShowDialog(“Some title”,”Leave_Balance”), the system display only a blank popup window instead of my page in the popup window.
A:
Lianja.showDialog() displays pages from the UI page library not the current app.
Save the page in the UI a Page library to be able to use it like that.



Library

If you only need the file to be available to a particular app then open that app and add the file via the Apps Workspace. If you want it available to multiple apps then put it in the Lianja Library (via the Library Workspace).


You will still have access to your App’s custom library/libraries.
You can use SET PROCEDURE TO <lib> ADDITIVE for multiple extra procedure/function libraries. The ADDITIVE means that it is opened in addition to any existing libraries.
The LIST PROCEDURE command will list the procedures and functions that are currently defined.


If it is a standalone prg, just click the + button at the bottom of the ‘Files’ in the Sidebar in the Apps Workspace and it will prompt you for the filename. The default file extension is ‘.prg’. Yes, it will be available for the whole App. When you Deploy, it will be deployed as a .dbo (pseudo-compiled) file.
If you have lots of functions you want to use, you can put them in a function/procedure library (create this using the + button as before):
Then use set procedure to <lib> additive in a delegate called before the function is required, for example in the app.load() or the app.ready() (or a delegate for the relevant Page or Section).
you can add functions (‘anotherfuncstill’ here) in with the event delegates. The custom libraries for event delegates (created when you create your first delegate) are opened for you automatically; there is no need to use set procedure in this case.
Pages and Sections can also have a ‘Valid When’ event delegate called after the field validation.


It’s handling the SET PROCEDURE correctly if the procedure library is in the App itself – it correctly loads the dbo. If the procedure library is in the Library, it is still expecting to find the prg.
If you copy the prg files into the deployed library, or the dbo files into the deployed App, this will work around it until it gets fixed.


Q:
procedure in a seperate prg file. And perhaps that needs something like ‘SET PROCEDURE TO’ to work? My main page and most other stuff uses javascript / python as the scripting language. And I also wonder if the ‘scope’ of the procedure was something I missed, or didn’t declare correctly “,)
A:
Yes, if it’s a procedure in a procedure library you need a

Code:
set procedure to <prgfile> additive

unless it is defined as the ‘Custom Library’ for the App, a Page or a Section, in which case that will be issued for you automatically.


Q:
How can I use a variable within several procedures in the same prg file?
A:
Remember that the section or page custom library where you define your event delegate procedures is a library, not a program that you are running from start to finish. The library declares your procedures, it doesn’t call them, so it’s not the same as one program/procedure calling another with the called procedure having access to the calling procedure’s private variables, e.g. a private variable set in Gamesheet_GSHeader_field82_click would be accessible to set_value as it is called by Gamesheet_GSHeader_field82_click.
To make a variable accessible to the procedures within your library, you do need to make it public. As Dave says, you could use a namespace to avoid conflicts. As I mentioned in a previous post, you can access public variables declared in a namespace with namespace.variable. You can also access them with just the variable name if your procedure is in the same namespace. For example:

Code:
// lib_Gamesheet_gsheader.prg
namespace gsheaderpublic testmsg = "Blank"

proc set_value()
        namespace gsheader
        testmsg = "testing"
        messagebox("Set Value message " + testmsg)
        messagebox(priv1) // private variable in calling procedure
endproc

////////////////////////////////////////////////////////////////
// Event delegate for 'click' event
proc Gamesheet_GSHeader_field82_click()
        namespace gsheader  // not currently required as does not use namespace public vars
        private priv1 = "Hello" // accessible to set_value
        set_value()
endproc


////////////////////////////////////////////////////////////////
// Event delegate for 'click' event
proc Gamesheet_GSHeader_field83_click()
        namespace gsheader
        messagebox(testmsg) 
endproc

I could then have the same variable name in another page in another namespace, e.g.

Code:
//lib_page1_section1.prg
namespace section1public testmsg = "This is section 1"

////////////////////////////////////////////////////////////////
// Event delegate for 'click' event
proc page1_section1_field78_click()
        namespace section1
        messagebox(testmsg)
endproc

 


I just meant design or at least complete the design with the UI Page in another App, so that you don’t have 2 copies of the same Page and controls in the main App as (from experience[IMG]file:///C:/DOCUME~1/Kruno/LOCALS~1/Temp/enhtmlclip/Image(2).png[/IMG]) that can be confusing. Once the Page is saved to the Page Library (yes, click the icon as Herb says to save it manually) it will be called from the Page Library, it just needs to be in an App too if you want to modify it. Herb’s other instructions are for code called by the UI Page. The code can either reside in the main App or in the Library. If you want it in the Library, add the ‘lib:/’ prefix as Herb says and add the relevant prg scripts to the Library.


Q:
How to call one the same page from two different applications? Calling completely including a left bar, right bar. Of course I can copy the page, but this is not correct because of maintenance at 2 locations.
A:
You can include the Left and Right Sidebars in a Page saved to the Page Library, they just need to be set to be shown in the Page Attributes


Q:
how I can have multiple functions in one file.
A:
Put your app specific functions in the custom library file for the app. Put your page specific functions in the custom library for the page. Same goes for section specific functions.


While you are developing and testing that is the case. The class libraries will not be automatically reloaded if the source file is edited.
In the App Builder itself, it listens for any custom libraries or other relevant files being edited and automatically recompiles and reloads them.
This in fact is how a lot of the “live” development is accomplished.


Try using SET CLASSLIB rather than SET PROCEDURE and omit the file extension.
Although set procedure will handle class definitions it is better to use set classlib.

Code:
set classlib to formclasses
list classlib
list classes

will show you what classes are in scope.

Code:
set procedure to mylibrary
list procedure

will show you what procedures and functions are in scope.
useful functions to be aware of:

Code:
? function_exists("myprocname")
? class_exists("myclassname")

So in your code:

Code:
proc openLibs()
    if not function_exists("myfunc")
        set procedure to myfunclib additive
    endif
    if not class_exists("basebutton1")
       set classlib to formclasslib additive
    endif
    // etc...
endproc
Code:
require_once("formclasslib.vcp")

Which takes care of a lot of messing about with determining if a class library has been loaded or not. The classes are however declared at the current scope level and will be released when the proc returns.
If you are using these classes in a modal form then they will remain in scope until the form is closed. e.g.

Code:
// myform.prg
require_once("alan.scp")
loForm = createobject("myform")
loForm.show(1)    // blocks execution until the form is closed.

Once you have satisfied yourself that your UI forms and classes are working, you can embed them in a “Custom” section. See below.Screen Shot 2015-01-29 at 10.43.15 AM.jpg

Custom libraries are loaded internally and are not affected by SET PROCEDURE TO in any way at all.
This is another reason why I recommend their use.


No I’m referring to the custom library for the App itself.
Go into App settings.
Scroll down the attributes to the delegates.
There is a custom library that gets automatically created if you create an init, load, ready, unload, inactive delegate.
Editing that custom library lets you add your own functions.
There is a custom library for each App, Page and Section. That’s where the delegates live.
Custom libraries are automatically opened when the App is loaded. They are monitored for changes for you and recompiled and reloaded. This is a fundamental part of the Lianja App Builder development cycle. There is no explicit compile or build required.
This is the same principle for all of the supported scripting languages; Lianja/VFP, JavaScript, PHP or Python.


My recommendation would be to place these functions in the App custom library rather than an external library loaded with SET PROCEDURE TO.
Why? Because lianja knows when any of these files have been edited and automatically recompiles and reloads them. That is not the case with SET PROCEDURE TO. This is exactly what happens when you edit your delegates, custom section code or ,rsp files that generate dynamic WebView content too. There is no compile and build steps required. It is done for you as the whole App is live. The UI knows when files have changed.
Also an advantage to this approach is that it is scripting language independent.
Note also that if you must use SET PROCEDURE TO you can check to see whether the library is already loaded by looking for a “well known function” in the library e.g.

Code:
if not function_exists("__mylib__")
    Set procedure to mylib additive
    // inside mylib.prg declare an empty function called __mylib__
Endif

// alternatively use require_once() which does all the hard work for you

Code:
require_once("mylib")

Q:
I realise that sometimes, my changes will not take effect if I run the app immediately after making the changes
I need to load another app and reload back my original app.
May I know if there is a better way to force a refresh so that when I run the app, it will take the latest source files?
A:
If you are using custom libraries these will automatically be recompiled and reloaded if they are edited.
If you have libraries that you are using that Lianja knows nothing about then you will need to save and reload your application for these to take effect.


In Lianja “Procedure libraries” can contain:
– classes
– procedures
– functions
Procedures and Functions are essentially the same thing. It’s good practice to use “Function” if it returns a result and “Procedure” if it does not. It’s all down to personal taste.
Script files (.prg) are opened and closed every time you call them. Not a good idea for your own functions. The file should just contain the code.

Code:
//myfunc.prg
return "Hello world"
//mylib.prg
function myfunc()
return "Hello world"

 


Q:
I have no problem defining multiple functions in libraries but I cannot see how to call these directly from attributes (without having an intermediate prg file as per my first post)
A:
Just edit a custom library, add your function and specify it in an expression:

Code:
myfunc()

and in a custom library:

Code:
function myfunc()
// your code
endfunc

Custom libraries are always opened when your app is opened.
When you edit a custom library Lianja detects that it has changed and will reload it automatically and compile it.