From the translator:A few weeks ago, my wife asked for a small application — an online database of addresses and contact information for family members, relatives, friends, and so on.
We continue to fill the lack of information in Russian about the most interesting Lisp dialect. Previous article: Web Application Development in PicoLisp
Project home page: http://picolisp.com
+QueryChart
. (class +Prs +Entity) (rel nm (+Sn +IdxFold +String)) # Name (rel adr (+IdxFold +String)) # Address (rel em (+String)) # E-Mail (rel tel (+String)) # Telephone (rel dob (+Date)) # Date of birth
If necessary, the class can be easily expanded.work
. It starts with the standard functions app
(= set session), action
(= form event handling) and html
(= generate HTML pages), which is typical for each PicoLisp application. The optional <ping>
function uses JavaScript to create a keep-alive event. (de work () (app) (action (html 0 Ttl "@lib.css" NIL (<ping> 2)
Then, as an elementary security measure, it displays the password field in the first form, with the password "mypass" hard-wired. (ifn *Login (form NIL (gui 'pw '(+PwField) 20 ,"Password") (gui '(+Button) ,"login" '(ifn (= "mypass" (val> (: home pw))) (error ,"Permission denied") (on *Login) (url "!work") ) ) )
(The real application uses full user / password authentication (using lib / adm.l libraries). We omitted it here only for brevity) (form NIL (<grid> "--." "Name" (gui 'nm '(+DbHint +TextField) '(nm +Prs) 20) (searchButton '(init> (: home query))) "Address" (gui 'adr '(+DbHint +TextField) '(adr +Prs) 20) (resetButton '(nm adr query)) )
It displays two search fields, "Name" and "Address", and two buttons "Search" and "Reset". Search fields use the + DbHint prefix class to display a drop-down list with matching names already available in the database. The "Reset" button clears all fields.+QueryChart
class both for searching for records, and for creating and editing them.+QueryChart
used in all search dialogs. It uses the Pilog query to search for a given set of criteria, and displays a possible unlimited number of results as long as there are suitable elements, and the user continues to press the scroll buttons. (gui 'query '(+QueryChart) 12 '(goal (quote @Nm (val> (: home nm)) @Adr (val> (: home adr)) (select (@@) ((nm +Prs @Nm) (adr +Prs @Adr)) (tolr @Nm @@ nm) (part @Adr @@ adr) ) ) )
The first argument (here 12) gives the initial number of matches to fill the table. The second argument is the Pilog query, which uses the values of the Name and Address search fields for fuzzy and partial searches. See http://software-lab.de/doc/select.html for details.+Chart
class +Chart
6 '((This) (list (: nm) (: adr) (: em) (: tel) (: dob))) '((LD) (cond (D (mapc '((KV) (put!> DKV)) '(nm adr em tel dob) L ) D ) ((car L) (new! '(+Prs) 'nm (car L)) ) ) ) )
namely, the number of columns (here 6) and the function put
and get
.+Chart
class calls these functions whenever something happens in the GUI. The put function converts the logical content of the table row (here the address of the object) to the physical display of the name, address, email, etc.: '((This) (list (: nm) (: adr) (: em) (: tel) (: dob)))
The argument for a put-function is an object, and it expands to a list of values for a row in a table.get
function performs the opposite action, translating the values in the string to the properties of the object. It accepts in L
list of values from the GUI (strings, numbers, dates, etc., entered by the user), and in D
address of the object in the database. '((LD)
It then checks in the cond
expression whether the object D
exists. If so, it stores the values from L
in the properties of the corresponding object, thus updating the database as necessary: (D (mapc '((KV) (put!> DKV)) '(nm adr em tel dob) L ) D )
If the object does not exist, but the first column of the table contains the name (which the user has just entered), a new object is created in the database with this name: ((car L) (new! '(+Prs) 'nm (car L)) ) ) ) )
That's all! This is all the logic needed to create and edit records.+Chart
or +QueryChart
is an internal object that implements the logic of this graphical interface +QueryChart
we need physical components to interact with the user +QueryChart
them in a table (<table> NIL (choTtl "Entries" '+Prs)
with appropriate headings (quote (NIL "Name") (NIL "Address") (NIL "E-Mail") (NIL "Telephone") (NIL "Date of birth") )
12 lines follow with fields of text, email and phone (do 12 (<row> NIL (gui 1 '(+TextField) 30) (gui 2 '(+TextField) 40) (gui 3 '(+MailField) 20) (gui 4 '(+TelField) 15) (gui 5 '(+DateField) 10) (gui 6 '(+DelRowButton) '(lose!> (curr)) '(text "Delete Entry @1?" (curr 'nm)) ) ) ) )
Note the +DelRowButton
button in the last column. It can be used to delete a record from the database. It brings up a dialog confirming whether the user really wants to delete the entry. However, if you delete multiple lines, it will not prompt the user next time. (scroll 12) ) ) ) ) )
They allow scrolling table contents line by page and page by page.main
and go
. The main
function should initialize the working environment, and go
should start the GUI event loop. (de main () (locale "UK") (pool "adr.db") ) (de go () (server 8080 "!work") )
locale
is mainly needed for correct processing of the +TelField
field with phone numbers. You can provide your localization settings in the loc/
directory. $ pil minDbGui.l -main -go -wait
either in debug mode: $ pil minDbGui.l -main -go +
# 11jan15abu # (c) Software Lab. Alexander Burger (allowed () "!work" "@lib.css" ) (load "@lib/http.l" "@lib/xhtml.l" "@lib/form.l") (class +Prs +Entity) (rel nm (+Sn +IdxFold +String)) # Name (rel adr (+IdxFold +String)) # Address (rel em (+String)) # E-Mail (rel tel (+String)) # Telephone (rel dob (+Date)) # Date of birth (de work () (app) (action (html 0 Ttl "@lib.css" NIL (<ping> 2) (ifn *Login (form NIL (gui 'pw '(+PwField) 20 ,"Password") (gui '(+Button) ,"login" '(ifn (= "mypass" (val> (: home pw))) (error ,"Permission denied") (on *Login) (url "!work") ) ) ) (form NIL (<grid> "--." "Name" (gui 'nm '(+DbHint +TextField) '(nm +Prs) 20) (searchButton '(init> (: home query))) "Address" (gui 'adr '(+DbHint +TextField) '(adr +Prs) 20) (resetButton '(nm adr query)) ) (gui 'query '(+QueryChart) 12 '(goal (quote @Nm (val> (: home nm)) @Adr (val> (: home adr)) (select (@@) ((nm +Prs @Nm) (adr +Prs @Adr)) (tolr @Nm @@ nm) (part @Adr @@ adr) ) ) ) 6 '((This) (list (: nm) (: adr) (: em) (: tel) (: dob))) '((LD) (cond (D (mapc '((KV) (put!> DKV)) '(nm adr em tel dob) L ) D ) ((car L) (new! '(+Prs) 'nm (car L)) ) ) ) ) (<table> NIL (choTtl "Entries" '+Prs) (quote (NIL "Name") (NIL "Address") (NIL "E-Mail") (NIL "Telephone") (NIL "Date of birth") ) (do 12 (<row> NIL (gui 1 '(+TextField) 30) (gui 2 '(+TextField) 40) (gui 3 '(+MailField) 20) (gui 4 '(+TelField) 15) (gui 5 '(+DateField) 10) (gui 6 '(+DelRowButton) '(lose!> (curr)) '(text "Delete Entry @1?" (curr 'nm)) ) ) ) ) (scroll 12) ) ) ) ) ) (de main () (locale "UK") (pool "adr.db") ) (de go () (server 8080 "!work") ) # vi:et:ts=3:sw=3
Source: https://habr.com/ru/post/247965/
All Articles