The development of web applications in PicoLisp
Readers of the previous article a Radical approach to application development could rightly notice that the article is too theoretical. So I need to restore the balancegood and eviltheory and practice.
This article reveals only the tip of the iceberg called picoLisp. Behind interesting points about the innards of database, organization of a distributed database, debugging, functional I/O object model with multiple inheritance, PicoLisp Prolog...
I still hope that our programmers will look to this powerful tool.
Carefully, under the cut a lot of text and the brackets!
abu@software-lab.de
the
Developing web applications in PicoLisp
© Software Lab. Alexander Burger
This document provides an introduction to writing web applications in PicoLisp.
It concentrates on the XHTML/CSS framework (unlike the previous Java-AWT, Java-Swing and plain-HTML frameworks), which is easier to use, more flexible in design and does not depend on plug-ins, JavaScript, cookies and CSS.
Simple GUI, HTTP/HTML has several advantages: it works in any browser and can be completely controlled by the script ("@lib/scrape.l").
More precisely, the CSS can to be used to improve the layout. And the browsers JavaScript will react faster and more smoothly. But this framework works perfectly and in browsers that don't know anything about CSS or JavaScript. All examples were also tested in the text-browser w3m.
Basic information about the system PicoLisp: PicoLisp Reference and PicoLisp Tutorial. Assumes knowledge of HTML and a little CSS and HTTP.
The examples assume that PicoLisp was started from a global installation (see Installation).
the
-
the
- Static page
the-
the
- Hello World
the-
the
- application server the
- How it works?
the - URL Syntax the
- Security
the-
the
- the File ".pw"
the - the
html
the - CSS Attributes the
- tags
the-
the
- Simple tags the
- Lists the
- Tables the
- Menu and tabs
the - Hello World
- online forms
the-
the
- Session the
- Forms
the-
the
- the
gui
the - control Flow the
- Switching the URL the
- dialogs and Alerts the
- calculator Example
the - the
- Tables (Charts)
the-
the
- Scrolling the
- Functions Get and Put
the - GUI-classes
the-
the
- input Fields
the-
the
- Numeric input fields the
- Time and date the
- Phone number the
- Checkboxes
the - the Prefix of fields classes
the-
the
- Initialization the
- Enabling and disabling the
- Formatting the
- Side effects the
- data Validation the
- Link database
the - Buttons
the-
the
- Buttons dialog Windows the
- JavaScript
the - input Fields
- a Minimal complete app
the-
the
- getting started
the-
the
- Localization the
- Navigation the
- Selecting objects the
- Editing the
- Buttons vs links
the - data Model the
- Usage
the-
the
- Customer/vendor the
- Item the
- Order the
- Reports
the - Bugs
- getting started
the
Static page
You can use PicoLisp to generate static HTML pages. In itself, this does not make much sense, since with the same success it is possible to directly write HTML code, but it forms the base for interactive applications and allows us to get acquainted with the application server and other fundamental concepts.
the
Hello World
To begin with a minimal application, create a file "project.l" in the PicoLisp installation directory and enter the following two lines.
the
########################################################################
(html 0 "Hello" "@lib.css" NIL
"Hello World!" )
########################################################################
(We will use and modify this file in all following examples. Whenever you see this code fragment between lines ('#####'), just copy and paste it into the file "project.l" and click on the "Refresh" button of your browser to see the result)
application server
Open a terminal window and start a PicoLisp application server
the
$ pil @lib/http.l @lib/xhtml.l @lib/form.l --server 8080 project.l +
The prompt will not appear. The server is running and waiting for connections. You can stop it later by pressing
Ctrl-C
in this terminal or by running 'killall pil
' in a terminal window.(In subsequent examples, we assume that this HTTP server continues to work)
Now open URL 'http://localhost:8080' in the browser. You should see a blank page with a single line of text.
How it works?
The above line loads the debugger ( " + " ), code HTTP server ("@lib/http.l"), function XHTML ("@lib/xhtml.l") and a GUI-framework ("@lib/form.l" you will need it later to online forms).
It then calls the function
server
with the port number and URL by default. She will listen to this port for incoming HTTP requests in an endless loop. Every time it receives a GET request on port 8080, the file "project.l" is loaded and executed using the (load)During the execution of this file all data written to the current output channel (STDOUT) is sent directly to the browser. The code in "project.l" is responsible for generating the HTML (or other format acceptable to the browser).
the
URL Syntax
The application server uses a slightly specialized syntax when exchanging URLS with the client. The part of the URL is the "path" that remains after cropping
the
-
the
- Protocol specification, host, and port the
- the final question mark and arguments
is interpreted according to some rules. The most important of them are:
the
-
the
- If the path starts with an exclamation mark ('!'), the remaining part (without '!') as the name Lisp functions. All the arguments after the question mark is passed to this function. the
- If the path ends ".l" (a dot and "L" in lowercase), it is taken as the name of a Lisp file that is uploaded using (load). This is the most common case, and we use it in our example "project.l". the
- If the file name extension matches an entry in the global table of mime types
*Mimes
, the file is sent to the client with mime-type and max-age value taken from this table.
the - otherwise, the file is sent to the client with mime type "application/octet-stream" and max-age of 1 second.
The application is no restriction to extend or modify the table
*Mimes
function mime
. For example,the
(mime "doc" "application/msword" 60)
defines a new mime type with a max-age of one minute.
Argument values in the URL, after the path and the question mark, are encoded in such a way as to preserve the data types Lisp:
the
-
the
- an Ordinary character (internal symbol) starts with a dollar sign ("$") the
- the Number starts with a plus sign (+) the
- External symbol (object DB) starts with a dash ('-') the
- List (single-level only) is encoded with underscores ('_') the
- otherwise it is a transit symbol (a string)
Therefore, the types high-level data can be directly passed to the function encoded in the URL, or assigned to global variables before a file is loaded.
the
Security
Of course this is a huge hole in security if you directly from the URL of any Lisp file may be downloaded, and any function can be called. For this reason, the application must take care to precisely specify which files and functions are allowed in the URL. The server checks the global variable *Allow, and when its value is not
NIL
, denies access to that does not match its content.Typically, the
*Allow
do not change directly, use the functions allowed and allowthe
(allowed ("app/")
"!start" "@lib.css" "customer.l" "article.l" )
It is usually invoked at the beginning of the application and allows access to the directory "app/", the functions "start" and the files "@lib.css", "customer.l" and "article.l".
Later in the program,
*Allow
can be dynamically extended with allow
the
(allow "!foo")
(allow "newdir/" T)
This adds to the set of allowed elements the function "foo" and the directory "newdir/".
File ".pw"
For use in security control (primarily to use the function
psh
, as in some later examples) it is necessary to create a file with the name ".pw" in the PicoLisp installation directory. This file should contain one line of random data to use as the password.The recommended way to create this file — the function call
pw
, defined in "@lib/http.l"the
$ pil @lib/http.l -'pw 12' -bye
Please run this command.
the
the html
Now back to our example "Hello World". In principle, you could write "project.l" as a sequence of statements
the
########################################################################
(prinl "HTTP/1.0 200 OK^M")
(prinl "Content-Type: text/html; charset=utf-8")
(prinl "^M")
(prinl "<html>")
(prinl "Hello World!")
(prinl "</html>")
########################################################################
but using the function
html
is much more convenient.In addition,
html
— no more than the printing function. You can easily see this if you connect a PicoLisp Shell (psh
) to the server process (you had to generate ".pw"-file to do this) and introduce the function html
the
$ /usr/lib/picolisp/bin/psh 8080
: (html 0 "Hello" "@lib.css" NIL "Hello World!")
HTTP/1.0 200 OK
Server: PicoLisp
Date: Fri, 29 Dec 2006 07:28:58 GMT
Cache-Control: max-age=0
Cache-Control: no-cache
Content-Type: text/html; charset=utf-8
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0
Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Hello</title>
<base href="http://localhost:8080/"/>
<link rel="stylesheet" type="text/css" href="http://localhost:8080/@lib.css"/>
</head>
<body>Hello World!</body>
</html>
-> </html>
: # (type Ctrl-D here to terminate PicoLisp)
The arguments to
html
:-
the
0
: the Value of max-age to control the browser cache (in seconds, zero means "no-cache"). You can set a higher value for pages that change seldom, orNIL
to disable the cache-control.
the "Hello"
: the name of the page.
the "@lib.css"
: the name of the CSS file. PassNIL
if you don't want to use CSS, or a list of file names, if you want to use more than one CSS file.
the NIL
: the Specification of CSS attributes for thebody
(see CSS attributes below).
After these four arguments can be followed by an arbitrary number of expressions. They form the body of the page and are calculated according to special rules. This rules are a bit different from the usual rules of computing:
the
-
the
- If the argument is an atom (number or symbol/string), its value will be printed immediately. the
- otherwise (the list), it is evaluated as Lisp functions (usually some form of print statement).
Thus our source file also can be written as:
the
########################################################################
(html 0 "Hello" "@lib.css" NIL
(prinl "Hello World!") )
########################################################################
The most typical printing function is some HTML-tags:
the
########################################################################
(html 0 "Hello" "@lib.css" NIL
(<h1> NIL, "Hello World!")
(<br> "This is some text.")
(ht:Prin "And this is a number:" (+ 1 2 3)) )
########################################################################
<h1>
and <br>
are functions of tags. <h1>
as its first argument takes a CSS attribute.Note the use of
ht:Prin
instead of prin
. The function ht:Prin
should be used for direct printing in HTML pages, because it escapes special characters.the
CSS Attributes
the
html
and many of functions, accept a CSS attribute. It can be an atom, a cons-pair or a list of cons-pairs. We show this by the example of the <h1>
.Atom (usually a symbol or string) as the name of the CSS class
the
: (<h1> 'foo "Title")
<h1 class="foo">Title</h1>
For a cons-pair CAR is perceived as the attribute name and the CDR as the attribute value
the
: (<h1> '(id . bar) "Title")
<h1 id="bar">Title</h1>
Hence the list of cons-pairs gives a set of pairs attribute-value.
the
: (<h1> '((id abc) (lang . "de")) "Title")
<h1 id="abc" lang="de">Title</h1>
the
All the predefined functions of the XHTML tags can be found in "@lib/xhtml.l". We recommend you to take a look at their definitions and experiment a little, performing them in the PicoLisp-console, or by clicking the browser "Refresh" after you edit the file "project.l".
To obtain suitable PicoLisp-console run PicoLisp Shell (
psh
) in a separate terminal window (only works if you are running the application server and you have created the file ".pw")the
$ /usr/lib/picolisp/bin/psh 8080
:
or just run the interpreter with the module load "@lib/xhtml.l"
the
$ pil @lib/http.l @lib/xhtml.l +
:
Please note that for all these functions the tags are used rules of function evaluation.
Simple Tags
Most of the functions of the tags are simple and clear. Some of them just print their arguments.
the
: (<br> "Hello world")
Hello world<br/>
: (<em> "Hello world")
<em>Hello world</em>
However, the majority of them take the set the CSS attributes as first argument (like
<h1>
above)the
: (<div> 'main "Hello world")
<div class="main">Hello world</div>
: (<p> NIL, "Hello world")
<p>Hello world</p>
: (<p> 'info "Hello world")
<p class="info">Hello world</p>
All these functions take an arbitrary number of arguments and can have arbitrarily deep nesting (as long as the resulting HTML markup is valid)
the
: (<div> 'main
(<h1> NIL "Head")
(<p> NIL
(<br> "Line 1")
"Line"
(<nbsp>)
(+ 1 1) ) )
<div class="main"><h1>Head</h1>
<p>Line 1<br/>
Line 2</p>
</div>
Lists
HTML-lists, implemented by the
<ol>
and <ul>
let you define hierarchical structures. Paste the following code into your copy of "project.l":the
########################################################################
(html 0 "Unordered List" "@lib.css" NIL
(<ul> NIL
(<li> NIL "Item 1")
(<li> NIL
"Sublist 1"
(<ul> NIL
(<li> NIL, "Item 1-1")
(<li> NIL, "Item 1-2") ) )
(<li> NIL, "Item 2")
(<li> NIL
"Sublist 2"
(<ul> NIL
(<li> NIL, "Item 2-1")
(<li> NIL, "Item 2-2") ) )
(<li> NIL, "Item 3") ) )
########################################################################
You also can put arbitrary code into each node of this tree, including the other functions of the tags.
Tables
Like hierarchical structures you can generate a two-dimensional table using the functions
<table>
and <row>
.The following example prints a table of numbers and their squares:
the
########################################################################
(html 0 "Table" "@lib.css" NIL
(<table> NIL NIL NIL
(for N 10 # A table with 10 rows
(<row> NIL N (prin (* N N))) ) ) ) # and 2 columns
########################################################################
The first argument to
<table>
is the usual CSS attribute, the second an optional title, and the third an optional list of column headers. In this list you can transmit the list for each column, with a CSS attribute in the CAR and the body of the tag in the CDR for the content of the column header.The body of the
<table>
contains the function calls <row>
. A characteristic feature is that each expression in its body will go in a separate column in the table. If the column header and the <row>
attribute is specified CSS will be combined with space and passed to the <td>
. This allows you to specify different CSS attributes for each row and column.As an extension of the above example table, let's set some attributes for the table itself (although it is not recommended — better define such styles in a CSS file and then just pass the class name in the
<table>
), align the two columns right-aligned and output each line into variables (red and blue) colorsthe
########################################################################
(html 0 "Table" "@lib.css" NIL
(<table>
'((width . "200px") (style . "border: dotted 1px;")) # table style
"Square Numbers" # caption
'((align "Number") (align "Square")) # 2 headers
(for N 10 # 10 rows
(<row > (xchg '(red) '(blue)) # red or blue
N # 2 columns
(prin (* N N) ) ) ) ) )
########################################################################
If you want to combine two or more cells in the table so that one cell was occupied by multiple columns, you can pass the symbol "
-
" as the additional parameter <row>
. This leads to the fact that the data located to the left of the characters "-
" will be expanded to the right.You can also directly specify the table structure in the normal functions of tags,
<th>
, <tr>
and <td>
.If you just need a two-dimensional arrangement of components, it is possible to apply more simple function
<grid>
:the
########################################################################
(html 0 "Grid" "@lib.css" NIL
(<grid> 3
"A" "B" "C"
123 456 789 ) )
########################################################################
The first parameter is the number of columns (here: 3), and then one expression for each cell. Instead of a number, you can also pass a list of CSS attributes. The length of this list will determine the number of columns. You can change the second line in the above example to:
the
(<grid> '(NIL NIL right)
The third column is aligned right.
Menu and tabs (tabs)
The two most powerful tag functions —
<menu>
and <tab>
. Being used separately or in combination, they form a navigation frameworkthe
-
the
- items menu, in which you can open and close submenu the
- items submenu to navigate to different pages the
- tabs (tabs) to navigate to the various subpages
The following example is not very useful, because the URLS of all items are on the same page "project.l", but this is sufficient to demonstrate the functionality:
the
########################################################################
(html 0 "Menu+Tab" "@lib.css" NIL
(<div> '(id . menu)
(<menu>
(Item "project.l") # Top level item
(NIL (<hr>)) # Plain HTML
(T "Submenu 1" # Submenu
("Subitem's 1.1", "project.l")
(T "Submenu 1.2"
("Subitem's 1.2.1" "project.l")
("Subitem's 1.2.2" "project.l")
("Subitem's 1.2.3" "project.l") )
("Subitem's 1.3" "project.l") )
(T "Submenu 2"
("Subitem's 2.1" "project.l")
("Subitem's 2.2" "project.l") ) ) )
(<div> '(id . main)
(<h1> NIL "Menu+Tab")
(<tab>
("Tab1"
(<h3> NIL "This is Tab 1") )
("Tab2"
(<h3> NIL "This is Tab 2") )
("Tab3"
(<h3> NIL "This is Tab 3") ) ) ) )
########################################################################
<menu>
accepts a sequence of menu items. Each menu item is a Lisp list whose CAR isthe
-
the
NIL
: the inactive menu item, the rest of the list may consist of arbitrary code (usually HTML tags).
the T
: the second element is the name of a submenu and clicking on the name will open or close the corresponding submenu. The tail of the list recursively specifies the submenu (of arbitrary depth).
the - Otherwise: the menu Item specifies a direct action (instead of opening a submenu), where the first element of the list is the name of the menu item and the second element the corresponding URL.
<tab>
takes a list of sub-pages. Each page is simply the name of the tab, and then the arbitrary code (normally HTML tags).Please note that only one menu and one tab can be active at one time.
In HTML, the only possibility for user input — using the
<form>
and <input>
, using the HTTP POST method to communicate with the server."@lib/xhtml.l" defines a function with the name
<post>
and the collection of input tags of data, which allow direct programming of HTML forms. We will show you only one simple example:the
########################################################################
(html 0 "Simple Form" "@lib.css" NIL
( NIL "project.l"
(<field> 10 '*Text)
(<submit> "Save") ) )
########################################################################
This example binds a text input field with the global variable
*Text
. The field displays the current value of *Text
, and clicking the submit button causes a reload of "project.l" *Text
has a string value entered by the user.The application can then use this variable for any useful action, for example to store the value in the database.
The problem with such a straightforward use of forms is:
-
the
- they require the programmer worries about maintaining a large number of global variables. Each input field on a page requires the variable to communicate between the server and the client. the
- they do not retain the internal state of the application. Every POST request creates a separate process on the server that sets the global variables to their new values, generates HTML pages and ends after that. Application state needs to be transferred explicitly, for example using the tag
<hidden>
.
the - they are not very interactive. Normally only one button "Send". The user fills in a (possibly) large number of input fields, but changes will only take effect when you click "Send".
Although we wrote several applications in this style, we recommend a GUI framework provided by the "@lib/form.l". He doesn't need any variables for client-server interactions and implements a class hierarchy of GUI components to abstract the application logic of the action buttons and connection data.
the
Session
First of all, we need to create a persistent environment on the server to handle each individual session (for each connected client).
Technically, it is just a child process of the server, which we launched above, which is not completed immediately after he sent an HTML page to the browser. This is achieved by calling the function
app
somewhere in the initialization code of the application.the
########################################################################
(app) # Start a session
(html 0 "Simple Session" "@lib.css" NIL
( NIL "project.l"
(<field> 10 '*Text)
(<submit> "Save") ) )
########################################################################
No more differences from the previous example. However, when you connect your browser and then look at the terminal window where you launched your application server, you will notice the colon — command line PicoLisp
the
$ pil @lib/http.l @lib/xhtml.l @lib/form.l --server 8080 project.l +
:
A tool such as the Unix utility
ps
, will tell you that it is now running two processes picolisp
, the first of which is the parent of the second.If you enter some text, say "abcdef" in the text box in the browser window, and click the Save button and examine the variable
*Text
the
: *Text
- >"abcdef"
you will see that we now have a dedicated PicoLisp process, "connected" to the client.
You can complete this process (like any interactive session of PicoLisp), pressing
Ctrl-D
an empty command line. Otherwise, he will end himself if the other browser requests not received within the timeout (default 5 minutes).For a start, prodas version (without debugging), the server is typically run without a flag "+" with
-wait
the
$ pil @lib/http.l @lib/xhtml.l @lib/form.l --server 8080 project.l -wait
Under this option, start the command prompt (:) appears when the client connects.
the
Forms (action forms)
Now that we have a session for each client, we can set up an active GUI framework.
To do this, we wrap the call to the function
html
in action
. Inside the body of the html
in addition to all other kinds of tag functions may be one or more calls to form
the
########################################################################
(app) # Start session
(action # Action handler
(html 0 "Form" "@lib.css" NIL # an HTTP/HTML protocol
(form NIL # Form
(gui 'a '(+TextField) 10) # Text Field
(gui '(+Button) "Print" # Button
'(msg (val > (: home a))) ) ) ) )
########################################################################
Please note that there is no longer a global variable, such as
*Text
, to store the contents of the input field. Instead, we gave a local, symbolic name 'a
' component +TextField
the
(gui 'a '(+TextField) 10) # Text Field
Other components can access it.
the
'(msg (val > (: home a)))
(: home)
always returns a reference to the form which contains this GUI component. So (: home a)
— the referenced component 'a
' in its current form. As msg prints its argument to STDERR, and the method val>
retrieves the current content component, when we push the button we will see in the console the text typed into the text box.Individually
action
and form
has no particular meaning. However, inside html
and form
, you can freely mix HTML (and any other Lisp function).A typical page may have the following structure:
the
(action # Action handler
(..html # HTTP/HTML protocol
(<h1> ..) # HTML tags
(form NIL # Form
(<h3> ..)
(gui ..) # GUI component(s)
(gui ..)
.. )
(<h2> ..)
(form NIL # Another form
(<h3> ..)
(gui ..) # GUI component(s)
.. )
(<br> ..)
.. ) )
the gui
The most important function in the body of the
form
— the gui
. This is a workhorse of a visual interface.Outside the function
form
gui
is not defined. The first parameter is an optional alias, the list of classes and additional arguments needed by the constructors of these classes. We saw in the previous example,the
(gui 'a '(+TextField) 10) # Text Field
Here '
a
' is an alias for a component of type (+TextField)
. A numeric argument to 10
is passed to the text field, specifying its width. See other examples in Chapter GUI Classes.During GET-request to
gui
is essentially a frontend for new
. He builds the component stores it in the internal structure of the current form and initialisere it by sending the message init>
. Finally, it sends the message show>
to generate HTML and pass it to the browser.During POST-request
gui
does not build any new components. Instead, existing components are reused. Therefore, gui
do not need to do anything more than sending the message bean show>
.control Flow
At HTTP only two methods to change a browser window: GET and POST. We use these two methods in a clearly defined way:
the
-
the
- GET means that this is new page. It is used when a page is visited for the first time, usually by typing the URL in the address field of your browser, or by clicking on the link (which is often submenu item or tab). the
- POST always leads to the page. It is initiated by pressing the button on the form, updates the data structure corresponding in shape and executes the code associated with this button.
Code associated with the button can do almost anything: read and modify the contents of input fields, communicate with the database to display messages and dialog boxes or even to forge a POST request because a GET request that will cause a completely different document (see Change URL).
GET builds all GUI components on the server. These components are objects that encapsulate the state and behavior of the HTML page in the browser. Whenever the button is pressed, the page reloads with a POST request. Then before sending any data to the browser — control is passed to the function
action
. It performs error checking of all components, processes user input in the HTML page and stores the values in each component in the desired format (text, number, date, object, etc.).The form state is preserved over time. When the user returns to the previous page with Back button of browser, this state and resumes can be sent again (POST-request).
In the following simple example displays two text fields. If you enter some text in the Source field, you can copy it in upper or lowercase in the "Destination" by clicking one of the buttons
the
########################################################################
(app)
(action
(html 0 "Case Conversion" "@lib.css" NIL
(form NIL
(<grid> 2
"Source" (gui 'src '(+TextField) 30)
"Destination" (gui 'dst '(+Lock +TextField) 30) )
(gui '(+JS +Button) "Upper Case"
'(set > (: home dst)
(uppc (val > (: home src))) ) )
(gui '(+JS +Button) "Lower Case"
'(set > (: home dst)
(lowc (val > (: home src))) ) ) ) ) )
########################################################################
Prefix class
+Lock
in the "Destination" makes the field read-only. The only way to put some text in this field is to use one of the buttons.Switching URLS
Because the code of actions (buttons) are performed before
html
can send HTTP header, it can abort the current page and present something different to the user. This can be another HTML page, but it's not a very interesting case, as it would be quite normal links. Instead, the code may cause the download of dynamically generated data.The following example shows a text field and two buttons. Any text typed in the text area is exported to a text file via the first button or a PDF document via the second button
the
########################################################################
(load "@lib/ps.l")
(app)
(action
(html 0 "Export" "@lib.css" NIL
(form NIL
(gui '(+TextField) 30 8)
(gui '(+Button) "Text"
'(let Txt (tmp "export.txt")
(out Txt (prinl (val > (: home gui 1))))
(url Txt) ) )
(gui '(+Button) PDF
'(psOut NIL "foo"
(a4)
(indent 40 40)
(down 60)
(hline 3)
(font (14 . "Times-Roman")
(ps (val > (: home gui 1))) )
(hline 3)
(page) ) ) ) ) )
########################################################################
(when you pass two arguments in class
+TextField
(width and height), creating an element textarea
)Code for the first button creates a temporary file (i.e. a file with the name "export.txt" in the temporary directory of the current process), prints the value of the text area (this time we do not give the name of the gui element, but simply refer to it as the first element in form) in this file, and then calls the function
url
file name.The second button uses the PostScript library "@lib/ps.l" to create a temporary file "foo.pdf". Here the creation of a temporary file and call the function
url
hidden inside psOut
. As a result, the browser receives a PDF document and displays it.Notifications and dialogs
In fact, alerts, and dialogs — not quite what we're used to seeing ;-)
They are not pop-up (popup). In this framework, they are the kind of simple to use forms predefined type. You can call them from the button code, and they always appear on the current page, just before the form that created them.
Let's look at an example that uses two alert and dialog box. In the beginning, it displays a simple form with a locked text field and two buttons
the
########################################################################
(app)
(action
(html 0 "Alerts and Dialogs" "@lib.css" NIL
(form NIL
(gui '(+Init +Lock +TextField) "Initial Text" 20 "My Text")
'(alert NIL "This is an alert" (okButton)) )
(gui '(+Button) "Dialog"
'(dialog NIL
(<br> "This is a dialog.")
(<br>
"You can change the text here "
(gui '(+Init +TextField) (val > (: top 1 gui 1)) 20) )
(<br> "and then re-submit it to the form.")
(gui '(+Button) "Re-Submit"
'(alert NIL "Are you sure? "
(yesButton
'(set > (: home top 2 gui 1)
(val > (: home top 1 gui 1)) ) )
(noButton) ) )
(cancelButton) ) ) ) ) )
########################################################################
Prefix class
+Init
initializefrom field "My Text" with the string "Initial Text". Because the field is locked, this value cannot be changed directly.The first button will show the alert: "This is an alert". You can close it by clicking "OK".
The second button will show a dialog with a text box containing the copy of the value from the text box the main form. You can change this value and send it back to the form if you click "Re-Submit" and answer "Yes" to the warning "Are you sure?".
Sample calculator
Now let's put our test file "project.l" and move on to more substantial and Autonomous practical example. Using what we have learned, build a simple bignum calculator. ("bignum" because PicoLisp has only one type of numbers — bignums (unlimited integer))
It uses one form, a single numeric input field, and a lot of buttons. The original text of the calculator can be found in the PicoLisp distribution (for example, "/usr/share/picolisp/misc/calc.l") together with a directly an executable wrapper script "misc/calc".
calc.l
# 14may11abu
# (c) Software Lab. Alexander Burger
# *Init, *Accu *Stack
(allowed NIL "!calculator" "@lib.css")
(load "@lib/http.l" "@lib/xhtml.l" "@lib/form.l")
# Calculator logic
(de digit (N)
(when *Init (zero *Accu) (off *Init))
(setq *Accu (+ N (* 10 *Accu))) )
(de calc ()
(let (Fun (caar *Stack) Val (cddr (pop '*Stack)))
(setq *Accu
(if (and (== '/ Fun) (=0 *Accu))
(alert "Div / 0")
(Fun Val *Accu) ) ) ) )
(de operand (Fun Prio)
(when (>=(cadar *Stack) Prio) (calc))
(push '*Stack (cons Fun Prio *Accu))
(on *Init) )
(de finish ()
(while *Stack (calc))
(on *Init) )
# Calculator GUI
(de calculator ()
(app)
(action
(html 0 "Bignum Calculator" "@lib.css" NIL
(<h2> NIL "Bignum Calculator")
(form NIL
(<br> (gui '(+Var +NumField) '*Accu 60))
(<grid> 4
(gui '(+JS +Button) "±" '(setq *Accu (- *Accu)))
(gui '(+Able +JS +Button) '(ge0 *Accu) (char 8730)
'(setq *Accu (sqrt *Accu)) )
(gui '(+JS +Button) "\^" '(operand '** 3))
(gui '(+JS +Button) "/" '(operand '/ 2))
(gui '(+JS +Button) "7" '(7 digit))
(gui '(+JS +Button) "8" '(digit 8))
(gui '(+JS +Button) "9" '(digit 9))
(gui '(+JS +Button) "*" '(operand '* 2))
(gui '(+JS +Button) "4" '(4 digit))
(gui '(+JS +Button) "5" '(5 digit))
(gui '(+JS +Button) "6" '(digit 6))
(gui '(+JS +Button) "-" '(operand '- 1))
(gui '(+JS +Button) "1" '(digit 1))
(gui '(+JS +Button) "2" '(digit 2))
(gui '(+JS +Button) "3" '(digit 3))
(gui '(+JS +Button) "+" '(operand '+ 1))
(gui '(+JS +Button) "0" '(digit 0))
(gui '(+JS +Button) "C" '(zero *Accu))
(gui '(+JS +Button) "A" '(main))
(gui '(+JS +Button) "=" '(finish)) ) ) ) ) )
# Initialize
(de main ()
(on *Init)
(zero *Accu)
(off-Stack) )
# Start server
(de go ()
(server 8080 "!calculator") )
To use, go to the PicoLisp installation directory, and run it as
the
$ misc/calc
or call it with an absolute path, for example
the
$ /usr/share/picolisp/misc/calc
If you want to access the interactive session of PicoLisp, run it instead as
the
$ pil misc/calc.l -main-go +
Open as usual, the page 'http://localhost:8080'.
The code for the logic of the calculator and GUI is quite simple. The entry point is the
calculator
. It is called directly (as described in URL Syntax), first, as the default URL of the server, and second, implicitly through POST requests. After starting the calculator, the file access is not required.Please note that for the production version, we insert the operator allowed at the beginning of "misc/calc.l" (as recommended in Chapter Security )
the
(allowed NIL "!calculator" "@lib.css")
This will limit external access only function
calculator
.The calculator uses three global variables,
*Init
, *Accu
and *Stack
. *Init
— Boolean flag set by the buttons of the operators to indicate that follow
Article based on information from habrahabr.ru
It is amazing and wonderful to visit your Blog Web Development Company in Bangalore | Website Design Companies in Bangalore | Web Designing Companies in Bangalore | Website Design Company in Bangalore
ОтветитьУдалить