app.html (96992B)
1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/1998/REC-html40-19980424/loose.dtd"> 2 <html lang="en"> 3 <head> 4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 5 <title>PicoLisp Application Development</title> 6 <link rel="stylesheet" href="doc.css" type="text/css"> 7 </head> 8 <body> 9 <a href="mailto:abu@software-lab.de">abu@software-lab.de</a> 10 11 <h1>PicoLisp Application Development</h1> 12 13 <p align=right>(c) Software Lab. Alexander Burger 14 15 <p>This document presents an introduction to writing browser-based applications 16 in PicoLisp. 17 18 <p>It concentrates on the XHTML/CSS GUI-Framework (as opposed to the previous 19 Java-AWT, Java-Swing and Plain-HTML frameworks), which is easier to use, more 20 flexible in layout design, and does not depend on plug-ins, JavaScript, cookies 21 or CSS. 22 23 <p>A plain HTTP/HTML GUI has various advantages: It runs on any browser, and can 24 be fully driven by scripts ("@lib/scrape.l"). 25 26 <p>To be precise: CSS <i>can</i> be used to enhance the layout. And browsers 27 <i>with</i> JavaScript will respond faster and smoother. But this framework 28 works just fine in browsers which do not know anything about CSS or JavaScript. 29 All examples were also tested using the w3m text browser. 30 31 <p>For basic informations about the PicoLisp system please look at the <a 32 href="ref.html">PicoLisp Reference</a> and the <a href="tut.html">PicoLisp 33 Tutorial</a>. Knowledge of HTML, and a bit of CSS and HTTP is assumed. 34 35 <p>The examples assume that PicoLisp was started from a global installation (see 36 <a href="ref.html#inst">Installation</a>). 37 38 <p><ul> 39 <li><a href="#static">Static Pages</a> 40 <ul> 41 <li><a href="#hello">Hello World</a> 42 <ul> 43 <li><a href="#server">Start the application server</a> 44 <li><a href="#how">How does it work?</a> 45 </ul> 46 <li><a href="#urlSyntax">URL Syntax</a> 47 <li><a href="#security">Security</a> 48 <ul> 49 <li><a href="#pw">The ".pw" File</a> 50 </ul> 51 <li><a href="#htmlFoo">The <code>html</code> Function</a> 52 <li><a href="#cssAttr">CSS Attributes</a> 53 <li><a href="#tags">Tag Functions</a> 54 <ul> 55 <li><a href="#simple">Simple Tags</a> 56 <li><a href="#lists">(Un)ordered Lists</a> 57 <li><a href="#tables">Tables</a> 58 <li><a href="#menus">Menus and Tabs</a> 59 </ul> 60 </ul> 61 <li><a href="#forms">Interactive Forms</a> 62 <ul> 63 <li><a href="#sessions">Sessions</a> 64 <li><a href="#actionForms">Action Forms</a> 65 <ul> 66 <li><a href="#guiFoo">The <code>gui</code> Function</a> 67 <li><a href="#ctlFlow">Control Flow</a> 68 <li><a href="#switching">Switching URLs</a> 69 <li><a href="#dialogs">Alerts and Dialogs</a> 70 <li><a href="#calc">A Calculator Example</a> 71 </ul> 72 <li><a href="#charts">Charts</a> 73 <ul> 74 <li><a href="#scrolling">Scrolling</a> 75 <li><a href="#putGet">Put and Get Functions</a> 76 </ul> 77 </ul> 78 <li><a href="#guiClasses">GUI Classes</a> 79 <ul> 80 <li><a href="#inputFields">Input Fields</a> 81 <ul> 82 <li><a href="#numberFields">Numeric Input Fields</a> 83 <li><a href="#timeDateFields">Time & Date</a> 84 <li><a href="#telFields">Telephone Numbers</a> 85 <li><a href="#checkboxes">Checkboxes</a> 86 </ul> 87 <li><a href="#fieldPrefix">Field Prefix Classes</a> 88 <ul> 89 <li><a href="#initPrefix">Initialization</a> 90 <li><a href="#ablePrefix">Disabling and Enabling</a> 91 <li><a href="#formatPrefix">Formatting</a> 92 <li><a href="#sideEffects">Side Effects</a> 93 <li><a href="#validPrefix">Validation</a> 94 <li><a href="#linkage">Data Linkage</a> 95 </ul> 96 <li><a href="#buttons">Buttons</a> 97 <ul> 98 <li><a href="#dialogButtons">Dialog Buttons</a> 99 <li><a href="#jsButtons">Active JavaScript</a> 100 </ul> 101 </ul> 102 <a name="minAppRef"></a> 103 <li><a href="#minApp">A Minimal Complete Application</a> 104 <ul> 105 <li><a href="#getStarted">Getting Started</a> 106 <ul> 107 <li><a href="#localization">Localization</a> 108 <li><a href="#navigation">Navigation</a> 109 <li><a href="#choosing">Choosing Objects</a> 110 <li><a href="#editing">Editing</a> 111 <li><a href="#btnLinks">Buttons vs. Links</a> 112 </ul> 113 <li><a href="#dataModel">The Data Model</a> 114 <li><a href="#usage">Usage</a> 115 <ul> 116 <li><a href="#cuSu">Customer/Supplier</a> 117 <li><a href="#item">Item</a> 118 <li><a href="#order">Order</a> 119 <li><a href="#reports">Reports</a> 120 </ul> 121 <li><a href="#bugs">Bugs</a> 122 </ul> 123 </ul> 124 125 126 <p><hr> 127 <h2><a name="static">Static Pages</a></h2> 128 129 <p>You can use PicoLisp to generate static HTML pages. This does not make much 130 sense in itself, because you could directly write HTML code as well, but it 131 forms the base for interactive applications, and allows us to introduce the 132 application server and other fundamental concepts. 133 134 <p><hr> 135 <h3><a name="hello">Hello World</a></h3> 136 137 <p>To begin with a minimal application, please enter the following two lines 138 into a generic source file named "project.l" in the PicoLisp installation 139 directory. 140 141 <pre><code> 142 ######################################################################## 143 (html 0 "Hello" "@lib.css" NIL 144 "Hello World!" ) 145 ######################################################################## 146 </code></pre> 147 148 <p>(We will modify and use this file in all following examples and experiments. 149 Whenever you find such a program snippet between hash ('#') lines, just copy and 150 paste it into your "project.l" file, and press the "reload" button of your 151 browser to view the effects) 152 153 154 <h4><a name="server">Start the application server</a></h4> 155 156 <p>Open a second terminal window, and start a PicoLisp application server 157 158 <pre><code> 159 $ pil @lib/http.l @lib/xhtml.l @lib/form.l --server 8080 project.l + 160 </code></pre> 161 162 <p>No prompt appears. The server just sits, and waits for connections. You can 163 stop it later by hitting <code>Ctrl-C</code> in that terminal, or by executing 164 '<code>killall pil</code>' in some other window. 165 166 <p>(In the following, we assume that this HTTP server is up and running) 167 168 <p>Now open the URL '<code><a 169 href="http://localhost:8080">http://localhost:8080</a></code>' with your 170 browser. You should see an empty page with a single line of text. 171 172 173 <h4><a name="how">How does it work?</a></h4> 174 175 <p>The above line loads the debugger (via the '+' switch), the HTTP server code 176 ("@lib/http.l"), the XHTML functions ("@lib/xhtml.l") and the input form 177 framework ("@lib/form.l", it will be needed later for <a 178 href="#forms">interactive forms</a>). 179 180 <p>Then the <code>server</code> function is called with a port number and a 181 default URL. It will listen on that port for incoming HTTP requests in an 182 endless loop. Whenever a GET request arrives on port 8080, the file "project.l" 183 will be <code><a href="refL.html#load">(load)</a></code>ed, causing the 184 evaluation (= execution) of all its Lisp expressions. 185 186 <p>During that execution, all data written to the current output channel is sent 187 directly to to the browser. The code in "project.l" is responsible to produce 188 HTML (or anything else the browser can understand). 189 190 191 <p><hr> 192 <h3><a name="urlSyntax">URL Syntax</a></h3> 193 194 <p>The PicoLisp application server uses a slightly specialized syntax when 195 communicating URLs to and from a client. The "path" part of an URL - which 196 remains when 197 198 <p><ul> 199 <li>the preceding protocol, host and port specifications, 200 <li>and the trailing question mark plus arguments 201 </ul> 202 203 are stripped off - is interpreted according so some rules. The most prominent 204 ones are: 205 206 <p><ul> 207 <li>If a path starts with an exclamation-mark ('!'), the rest (without the '!') 208 is taken as the name of a Lisp function to be called. All arguments following 209 the question mark are passed to that function. 210 211 <li>If a path ends with ".l" (a dot and a lower case 'L'), it is taken as a Lisp 212 source file name to be <code><a href="refL.html#load">(load)</a></code>ed. This 213 is the most common case, and we use it in our example "project.l". 214 215 <li>If the extension of a file name matches an entry in the global mime type 216 table <code>*Mimes</code>, the file is sent to the client with mime-type and 217 max-age values taken from that table. 218 219 <li>Otherwise, the file is sent to the client with a mime-type of 220 "application/octet-stream" and a max-age of 1 second. 221 222 </ul> 223 224 <p>An application is free to extend or modify the <code>*Mimes</code> table with 225 the <code>mime</code> function. For example 226 227 <pre><code> 228 (mime "doc" "application/msword" 60) 229 </code></pre> 230 231 <p>defines a new mime type with a max-age of one minute. 232 233 <p>Argument values in URLs, following the path and the question mark, are 234 encoded in such a way that Lisp data types are preserved: 235 236 <p><ul> 237 <li>An internal symbol starts with a dollar sign ('$') 238 <li>A number starts with a plus sign ('+') 239 <li>An external (database) symbol starts with dash ('-') 240 <li>A list (one level only) is encoded with underscores ('_') 241 <li>Otherwise, it is a transient symbol (a plain string) 242 243 </ul> 244 245 <p>In that way, high-level data types can be directly passed to functions 246 encoded in the URL, or assigned to global variables before a file is loaded. 247 248 249 <p><hr> 250 <h3><a name="security">Security</a></h3> 251 252 <p>It is, of course, a huge security hole that - directly from the URL - any 253 Lisp source file can be loaded, and any Lisp function can be called. For that 254 reason, applications must take care to declare exactly which files and functions 255 are to be allowed in URLs. The server checks a global variable <code><a 256 href="refA.html#*Allow">*Allow</a></code>, and - when its value is 257 non-<code>NIL</code> - denies access to anything that does not match its 258 contents. 259 260 <p>Normally, <code>*Allow</code> is not manipulated directly, but set with the 261 <code><a href="refA.html#allowed">allowed</a></code> and <code><a 262 href="refA.html#allow">allow</a></code> functions 263 264 <pre><code> 265 (allowed ("app/") 266 "!start" "!stop" "@lib.css" "!psh" ) 267 </code></pre> 268 269 <p>This is usually called at the beginning of an application, and allows access 270 to the directory "app/", to the functions 'start', 'stop' and 'psh', and to the 271 file "@lib.css". 272 273 <p>Later in the program, <code>*Allow</code> may be dynamically extended with 274 <code>allow</code> 275 276 <pre><code> 277 (allow "!foo") 278 (allow "newdir/" T) 279 </code></pre> 280 281 <p>This adds the function 'foo', and the directory "newdir/", to the set of 282 allowed items. 283 284 285 <h4><a name="pw">The ".pw" File</a></h4> 286 287 <p>For a variety of security checks (most notably for using the <code>psh</code> 288 function, as in some later examples) it is necessary to create a file named 289 ".pw" in the PicoLisp installation directory. This file should contain a single 290 line of arbitrary data, to be used as a password for identifying local 291 resources. 292 293 <p>The recommeded way to create this file is to call the <code>pw</code> 294 function, defined in "@lib/http.l" 295 296 <pre><code> 297 $ pil @lib/http.l -'pw 12' -bye 298 </code></pre> 299 300 <p>Please execute this command. 301 302 303 <p><hr> 304 <h3><a name="htmlFoo">The <code>html</code> Function</a></h3> 305 306 <p>Now back to our "Hello World" example. In principle, you could write 307 "project.l" as a sequence of print statements 308 309 <pre><code> 310 ######################################################################## 311 (prinl "HTTP/1.0 200 OK^M") 312 (prinl "Content-Type: text/html; charset=utf-8") 313 (prinl "^M") 314 (prinl "<html>") 315 (prinl "Hello World!") 316 (prinl "</html>") 317 ######################################################################## 318 </code></pre> 319 320 <p>but using the <code>html</code> function is much more convenient. 321 322 <p>Moreover, <code>html</code> <b>is</b> nothing more than a printing function. 323 You can see this easily if you connect a PicoLisp Shell (<code>psh</code>) to 324 the server process (you must have generated a <a href="#pw">".pw" file</a> for 325 this), and enter the <code>html</code> statement 326 327 <pre><code> 328 $ /usr/lib/picolisp/bin/psh 8080 329 : (html 0 "Hello" "@lib.css" NIL "Hello World!") 330 HTTP/1.0 200 OK 331 Server: PicoLisp 332 Date: Fri, 29 Dec 2006 07:28:58 GMT 333 Cache-Control: max-age=0 334 Cache-Control: no-cache 335 Content-Type: text/html; charset=utf-8 336 337 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 338 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> 339 <head> 340 <title>Hello</title> 341 <base href="http://localhost:8080/"/> 342 <link rel="stylesheet" type="text/css" href="http://localhost:8080/@lib.css"/> 343 </head> 344 <body>Hello World!</body> 345 </html> 346 -> </html> 347 : # (type Ctrl-D here to terminate PicoLisp) 348 </code></pre> 349 350 <p>These are the arguments to <code>html</code>: 351 352 <ol> 353 354 <li><code>0</code>: A max-age value for cache-control (in seconds, zero means 355 "no-cache"). You might pass a higher value for pages that change seldom, or 356 <code>NIL</code> for no cache-control at all. 357 358 <li><code>"Hello"</code>: The page title. 359 360 <li><code>"@lib.css"</code>: A CSS-File name. Pass <code>NIL</code> if you do 361 not want to use any CSS-File, or a list of file names if you want to give more 362 than one CSS-File. 363 364 <li><code>NIL</code>: A CSS style attribute specification (see the description 365 of <a href="#cssAttr">CSS Attributes</a> below). It will be passed to the 366 <code>body</code> tag. 367 368 </ol> 369 370 <p>After these four arguments, an arbitrary number of expressions may follow. 371 They form the body of the resulting page, and are evaluated according to a 372 special rule. <a name="tagRule">This rule</a> is slightly different from the 373 evaluation of normal Lisp expressions: 374 375 <p><ul> 376 377 <li>If an argument is an atom (a number or a symbol (string)), its value is 378 printed immediately. 379 380 <li>Otherwise (a list), it is evaluated as a Lisp function (typically some form 381 of print statement). 382 383 </ul> 384 385 <p>Therefore, our source file might as well be written as: 386 387 <pre><code> 388 ######################################################################## 389 (html 0 "Hello" "@lib.css" NIL 390 (prinl "Hello World!") ) 391 ######################################################################## 392 </code></pre> 393 394 <p>The most typical print statements will be some HTML-tags: 395 396 <pre><code> 397 ######################################################################## 398 (html 0 "Hello" "@lib.css" NIL 399 (<h1> NIL "Hello World!") 400 (<br> "This is some text.") 401 (ht:Prin "And this is a number: " (+ 1 2 3)) ) 402 ######################################################################## 403 </code></pre> 404 405 <p><code><h1></code> and <code><br></code> are tag functions. 406 <code><h1></code> takes a CSS attribute as its first argument. 407 408 <p>Note the use of <code>ht:Prin</code> instead of <code>prin</code>. 409 <code>ht:Prin</code> should be used for all direct printing in HTML pages, 410 because it takes care to escape special characters. 411 412 413 <p><hr> 414 <h3><a name="cssAttr">CSS Attributes</a></h3> 415 416 <p>The <a href="#htmlFoo"><code>html</code> function</a> above, and many of the 417 HTML <a href="#tags">tag functions</a>, accept a CSS attribute specification. 418 This may be either an atom, a cons pair, or a list of cons pairs. We demonstrate 419 the effects with the <code><h1></code> tag function. 420 421 <p>An atom (usually a symbol or a string) is taken as a CSS class name 422 423 <pre><code> 424 : (<h1> 'foo "Title") 425 <h1 class="foo">Title</h1> 426 </code></pre> 427 428 <p>For a cons pair, the CAR is taken as an attribute name, and the CDR as the 429 attribute's value 430 431 <pre><code> 432 : (<h1> '(id . bar) "Title") 433 <h1 id="bar">Title</h1> 434 </code></pre> 435 436 <p>Consequently, a list of cons pairs gives a set of attribute-value pairs 437 438 <pre><code> 439 : (<h1> '((id . "abc") (lang . "de")) "Title") 440 <h1 id="abc" lang="de">Title</h1> 441 </code></pre> 442 443 444 <p><hr> 445 <h3><a name="tags">Tag Functions</a></h3> 446 447 <p>All pre-defined XHTML tag functions can be found in "@lib/xhtml.l". We 448 recommend to look at their sources, and to experiment a bit, by executing them 449 at a PicoLisp prompt, or by pressing the browser's "Reload" button after editing 450 the "project.l" file. 451 452 <p>For a suitable PicoLisp prompt, either execute (in a separate terminal 453 window) the PicoLisp Shell (<code>psh</code>) command (works only if the 454 application server is running, and you did generate a <a href="#pw">".pw" 455 file</a>) 456 457 <pre><code> 458 $ /usr/lib/picolisp/bin/psh 8080 459 : 460 </code></pre> 461 462 <p>or start the interpreter stand-alone, with "@lib/xhtml.l" loaded 463 464 <pre><code> 465 $ pil @lib/http.l @lib/xhtml.l + 466 : 467 </code></pre> 468 469 <p>Note that for all these tag functions the above <a href="#tagRule">tag body 470 evaluation rule</a> applies. 471 472 473 <h4><a name="simple">Simple Tags</a></h4> 474 475 <p>Most tag functions are simple and straightforward. Some of them just print 476 their arguments 477 478 <pre><code> 479 : (<br> "Hello world") 480 Hello world<br/> 481 482 : (<em> "Hello world") 483 <em>Hello world</em> 484 </code></pre> 485 486 <p>while most of them take a <a href="#cssAttr">CSS attribute specification</a> 487 as their first argument (like the <code><h1></code> tag above) 488 489 <pre><code> 490 : (<div> 'main "Hello world") 491 <div class="main">Hello world</div> 492 493 : (<p> NIL "Hello world") 494 <p>Hello world</p> 495 496 : (<p> 'info "Hello world") 497 <p class="info">Hello world</p> 498 </code></pre> 499 500 <p>All of these functions take an arbitrary number of arguments, and may nest to 501 an arbitrary depth (as long as the resulting HTML is legal) 502 503 <pre><code> 504 : (<div> 'main 505 (<h1> NIL "Head") 506 (<p> NIL 507 (<br> "Line 1") 508 "Line" 509 (<nbsp>) 510 (+ 1 1) ) ) 511 <div class="main"><h1>Head</h1> 512 <p>Line 1<br/> 513 Line 2</p> 514 </div> 515 </code></pre> 516 517 518 <h4><a name="lists">(Un)ordered Lists</a></h4> 519 520 <p>HTML-lists, implemented by the <code><ol></code> and 521 <code><ul></code> tags, let you define hierarchical structures. You might 522 want to paste the following code into your copy of "project.l": 523 524 <pre><code> 525 ######################################################################## 526 (html 0 "Unordered List" "@lib.css" NIL 527 (<ul> NIL 528 (<li> NIL "Item 1") 529 (<li> NIL 530 "Sublist 1" 531 (<ul> NIL 532 (<li> NIL "Item 1-1") 533 (<li> NIL "Item 1-2") ) ) 534 (<li> NIL "Item 2") 535 (<li> NIL 536 "Sublist 2" 537 (<ul> NIL 538 (<li> NIL "Item 2-1") 539 (<li> NIL "Item 2-2") ) ) 540 (<li> NIL "Item 3") ) ) 541 ######################################################################## 542 </code></pre> 543 544 <p>Here, too, you can put arbitrary code into each node of that tree, including 545 other tag functions. 546 547 548 <h4><a name="tables">Tables</a></h4> 549 550 <p>Like the hierarchical structures with the list functions, you can generate 551 two-dimensional tables with the <code><table></code> and 552 <code><row></code> functions. 553 554 <p>The following example prints a table of numbers and their squares: 555 556 <pre><code> 557 ######################################################################## 558 (html 0 "Table" "@lib.css" NIL 559 (<table> NIL NIL NIL 560 (for N 10 # A table with 10 rows 561 (<row> NIL N (prin (* N N))) ) ) ) # and 2 columns 562 ######################################################################## 563 </code></pre> 564 565 <p>The first argument to <code><table></code> is the usual CSS attribute, 566 the second an optional title ("caption"), and the third an optional list 567 specifying the column headers. In that list, you may supply a list for a each 568 column, with a CSS attribute in its CAR, and a tag body in its CDR for the 569 contents of the column header. 570 571 <p>The body of <code><table></code> contains calls to the 572 <code><row></code> function. This function is special in that each 573 expression in its body will go to a separate column of the table. If both for 574 the column header and the row function an CSS attribute is given, they will be 575 combined by a space and passed to the HTML <code><td></code> tag. This 576 permits distinct CSS specifications for each column and row. 577 578 <p>As an extension of the above table example, let's pass some attributes for 579 the table itself (not recommended - better define such styles in a CSS file and 580 then just pass the class name to <code><table></code>), right-align both 581 columns, and print each row in an alternating red and blue color 582 583 <pre><code> 584 ######################################################################## 585 (html 0 "Table" "@lib.css" NIL 586 (<table> 587 '((width . "200px") (style . "border: dotted 1px;")) # table style 588 "Square Numbers" # caption 589 '((align "Number") (align "Square")) # 2 headers 590 (for N 10 # 10 rows 591 (<row> (xchg '(red) '(blue)) # red or blue 592 N # 2 columns 593 (prin (* N N) ) ) ) ) ) 594 ######################################################################## 595 </code></pre> 596 597 <p>If you wish to concatenate two or more cells in a table, so that a single 598 cell spans several columns, you can pass the symbol '<code>-</code>' for the 599 additional cell data to <code><row></code>. This will cause the data given 600 to the left of the '<code>-</code>' symbols to expand to the right. 601 602 <p>You can also directly specify table structures with the simple 603 <code><th></code>, <code><tr></code> and <code><td></code> tag 604 functions. 605 606 <p>If you just need a two-dimensional arrangement of components, the even 607 simpler <code><grid></code> function might be convenient: 608 609 <pre><code> 610 ######################################################################## 611 (html 0 "Grid" "@lib.css" NIL 612 (<grid> 3 613 "A" "B" "C" 614 123 456 789 ) ) 615 ######################################################################## 616 </code></pre> 617 618 <p>It just takes a specification for the number of columns (here: 3) as its 619 first argument, and then a single expression for each cell. Instead of a number, 620 you can also pass a list of CSS attributes. Then the length of that list will 621 determine the number of columns. You can change the second line in the above 622 example to 623 624 <pre><code> 625 (<grid> '(NIL NIL right) 626 </code></pre> 627 628 <p>Then the third column will be right aligned. 629 630 631 <h4><a name="menus">Menus and Tabs</a></h4> 632 633 <p>The two most powerful tag functions are <code><menu></code> and 634 <code><tab></code>. Used separately or in combination, they form a 635 navigation framework with 636 637 <p><ul> 638 <li>menu items which open and close submenus 639 <li>submenu items which switch to different pages 640 <li>tabs which switch to different subpages 641 </ul> 642 643 <p>The following example is not very useful, because the URLs of all items link 644 to the same "project.l" page, but it should suffice to demonstrate the 645 functionality: 646 647 <pre><code> 648 ######################################################################## 649 (html 0 "Menu+Tab" "@lib.css" NIL 650 (<div> '(id . menu) 651 (<menu> 652 ("Item" "project.l") # Top level item 653 (NIL (<hr>)) # Plain HTML 654 (T "Submenu 1" # Submenu 655 ("Subitem 1.1" "project.l") 656 (T "Submenu 1.2" 657 ("Subitem 1.2.1" "project.l") 658 ("Subitem 1.2.2" "project.l") 659 ("Subitem 1.2.3" "project.l") ) 660 ("Subitem 1.3" "project.l") ) 661 (T "Submenu 2" 662 ("Subitem 2.1" "project.l") 663 ("Subitem 2.2" "project.l") ) ) ) 664 (<div> '(id . main) 665 (<h1> NIL "Menu+Tab") 666 (<tab> 667 ("Tab1" 668 (<h3> NIL "This is Tab 1") ) 669 ("Tab2" 670 (<h3> NIL "This is Tab 2") ) 671 ("Tab3" 672 (<h3> NIL "This is Tab 3") ) ) ) ) 673 ######################################################################## 674 </code></pre> 675 676 <p><code><menu></code> takes a sequence of menu items. Each menu item is a 677 list, with its CAR either 678 679 <p><ul> 680 <li><code>NIL</code>: The entry is not an active menu item, and the rest of the 681 list may consist of arbitrary code (usually HTML tags). 682 683 <li><code>T</code>: The second element is taken as a submenu name, and a click 684 on that name will open or close the corresponding submenu. The rest of the list 685 recursively specifies the submenu items (may nest to arbitrary depth). 686 687 <li>Otherwise: The menu item specifies a direct action (instead of opening a 688 submenu), where the first list element gives the item's name, and the second 689 element the corresponding URL. 690 691 </ul> 692 693 <p><code><tab></code> takes a list of subpages. Each page is simply a tab 694 name, followed by arbitrary code (typically HTML tags). 695 696 <p>Note that only a single menu and a single tab may be active at the same time. 697 698 699 <p><hr> 700 <h2><a name="forms">Interactive Forms</a></h2> 701 702 <p>In HTML, the only possibility for user input is via <code><form></code> 703 and <code><input></code> elements, using the HTTP POST method to 704 communicate with the server. 705 706 <p>"@lib/xhtml.l" defines a function called <code><post></code>, and a 707 collection of input tag functions, which allow direct programming of HTML forms. 708 We will supply only one simple example: 709 710 <pre><code> 711 ######################################################################## 712 (html 0 "Simple Form" "@lib.css" NIL 713 (<post> NIL "project.l" 714 (<field> 10 '*Text) 715 (<submit> "Save") ) ) 716 ######################################################################## 717 </code></pre> 718 719 <p>This associates a text input field with a global variable <code>*Text</code>. 720 The field displays the current value of <code>*Text</code>, and pressing the 721 submit button causes a reload of "project.l" with <code>*Text</code> set to any 722 string entered by the user. 723 724 <p>An application program could then use that variable to do something useful, 725 for example store its value in a database. 726 727 <p>The problem with such a straightforward use of forms is that 728 729 <p><ol> 730 <li>they require the application programmer to take care of maintaining lots of 731 global variables. Each input field on the page needs an associated variable for 732 the round trip between server and client. 733 734 <li>they do not preserve an application's internal state. Each POST request 735 spawns an individual process on the server, which sets the global variables to 736 their new values, generates the HTML page, and terminates thereafter. The 737 application state has to be passed along explicitly, e.g. using 738 <code><hidden></code> tags. 739 740 <li>they are not very interactive. There is typically only a single submit 741 button. The user fills out a possibly large number of input fields, but changes 742 will take effect only when the submit button is pressed. 743 744 </ol> 745 746 <p>Though we wrote a few applications in that style, we recommend the GUI 747 framework provided by "@lib/form.l". It does not need any variables for the 748 client/server communication, but implements a class hierarchy of GUI components 749 for the abstraction of application logic, button actions and data linkage. 750 751 752 <p><hr> 753 <h3><a name="sessions">Sessions</a></h3> 754 755 <p>First of all, we need to establish a persistent environment on the server, to 756 handle each individual session (for each connected client). 757 758 <p>Technically, this is just a child process of the server we started <a 759 href="#server">above</a>, which does not terminate immediately after it sent its 760 page to the browser. It is achieved by calling the <code>app</code> function 761 somewhere in the application's startup code. 762 763 <pre><code> 764 ######################################################################## 765 (app) # Start a session 766 767 (html 0 "Simple Session" "@lib.css" NIL 768 (<post> NIL "project.l" 769 (<field> 10 '*Text) 770 (<submit> "Save") ) ) 771 ######################################################################## 772 </code></pre> 773 774 <p>Nothing else changed from the previous example. However, when you connect 775 your browser and then look at the terminal window where you started the 776 application server, you'll notice a colon, the PicoLisp prompt 777 778 <pre><code> 779 $ pil @lib/http.l @lib/xhtml.l @lib/form.l --server 8080 project.l + 780 : 781 </code></pre> 782 783 <p>Tools like the Unix <code>ps</code> utility will tell you that now two 784 <code>picolisp</code> processes are running, the first being the parent of the 785 second. 786 787 <p>If you enter some text, say "abcdef", into the text field in the browser 788 window, press the submit button, and inspect the Lisp <code>*Text</code> 789 variable, 790 791 <pre><code> 792 : *Text 793 -> "abcdef" 794 </code></pre> 795 796 <p>you see that we now have a dedicated PicoLisp process, "connected" to the 797 client. 798 799 <p>You can terminate this process (like any interactive PicoLisp) by hitting 800 <code>Ctrl-D</code> on an empty line. Otherwise, it will terminate by itself if 801 no other browser requests arrive within a default timeout period of 5 minutes. 802 803 <p>To start a (non-debug) production version, the server is commonly started 804 without the '+' flag, and with <code>-wait</code> 805 806 <pre><code> 807 $ pil @lib/http.l @lib/xhtml.l @lib/form.l --server 8080 project.l -wait 808 </code></pre> 809 810 <p>In that way, no command line prompt appears when a client connects. 811 812 813 <p><hr> 814 <h3><a name="actionForms">Action Forms</a></h3> 815 816 <p>Now that we have a persistent session for each client, we can set up an 817 active GUI framework. 818 819 <p>This is done by wrapping the call to the <code>html</code> function with 820 <code>action</code>. Inside the body of <code>html</code> can be - in addition 821 to all other kinds of tag functions - one or more calls to <code>form</code> 822 823 <pre><code> 824 ######################################################################## 825 (app) # Start session 826 827 (action # Action handler 828 (html 0 "Form" "@lib.css" NIL # HTTP/HTML protocol 829 (form NIL # Form 830 (gui 'a '(+TextField) 10) # Text Field 831 (gui '(+Button) "Print" # Button 832 '(msg (val> (: home a))) ) ) ) ) 833 ######################################################################## 834 </code></pre> 835 836 <p>Note that there is no longer a global variable like <code>*Text</code> to 837 hold the contents of the input field. Instead, we gave a local, symbolic name 838 '<code>a</code>' to a <code>+TextField</code> component 839 840 <pre><code> 841 (gui 'a '(+TextField) 10) # Text Field 842 </code></pre> 843 844 <p>Other components can refer to it 845 846 <pre><code> 847 '(msg (val> (: home a))) 848 </code></pre> 849 850 <p><code>(: home)</code> is always the form which contains this GUI component. 851 So <code>(: home a)</code> evaluates to the component '<code>a</code>' in the 852 current form. As <code><a href="refM.html#msg">msg</a></code> prints its 853 argument to standard error, and the <code>val></code> method retrieves the 854 current contents of a component, we will see on the console the text typed into 855 the text field when we press the button. 856 857 <p>An <code>action</code> without embedded <code>form</code>s - or a 858 <code>form</code> without a surrounding <code>action</code> - does not make much 859 sense by itself. Inside <code>html</code> and <code>form</code>, however, calls 860 to HTML functions (and any other Lisp functions, for that matter) can be freely 861 mixed. 862 863 <p>In general, a typical page may have the form 864 865 <pre><code> 866 (action # Action handler 867 (html .. # HTTP/HTML protocol 868 (<h1> ..) # HTML tags 869 (form NIL # Form 870 (<h3> ..) 871 (gui ..) # GUI component(s) 872 (gui ..) 873 .. ) 874 (<h2> ..) 875 (form NIL # Another form 876 (<h3> ..) 877 (gui ..) # GUI component(s) 878 .. ) 879 (<br> ..) 880 .. ) ) 881 </code></pre> 882 883 884 <h4><a name="guiFoo">The <code>gui</code> Function</a></h4> 885 886 <p>The most prominent function in a <code>form</code> body is <code>gui</code>. 887 It is the workhorse of GUI construction. 888 889 <p>Outside of a <code>form</code> body, <code>gui</code> is undefined. 890 Otherwise, it takes an optional alias name, a list of classes, and additional 891 arguments as needed by the constructors of these classes. We saw this example 892 before 893 894 <pre><code> 895 (gui 'a '(+TextField) 10) # Text Field 896 </code></pre> 897 898 Here, '<code>a</code>' is an alias name for a component of type 899 <code>(+TextField)</code>. The numeric argument <code>10</code> is passed to the 900 text field, specifying its width. See the chapter on <a href="#guiClasses">GUI 901 Classes</a> for more examples. 902 903 <p>During a GET request, <code>gui</code> is basically a front-end to 904 <code>new</code>. It builds a component, stores it in the internal structures of 905 the current form, and initializes it by sending the <code>init></code> 906 message to the component. Finally, it sends it the <code>show></code> 907 message, to produce HTML code and transmit it to the browser. 908 909 <p>During a POST request, <code>gui</code> does not build any new components. 910 Instead, the existing components are re-used. So <code>gui</code> does not have 911 much more to do than sending the <code>show></code> message to a component. 912 913 914 <h4><a name="ctlFlow">Control Flow</a></h4> 915 916 <p>HTTP has only two methods to change a browser window: GET and POST. We employ 917 these two methods in a certain defined, specialized way: 918 919 <p><ul> 920 <li>GET means, a <b>new page</b> is being constructed. It is used when a page is 921 visited for the first time, usually by entering an URL into the browser's 922 address field, or by clicking on a link (which is often a <a 923 href="#menus">submenu item or tab</a>). 924 925 <li>POST is always directed to the <b>same page</b>. It is triggered by a button 926 press, updates the corresponding form's data structures, and executes that 927 button's action code. 928 929 </ul> 930 931 <p>A button's action code can do almost anything: Read and modify the contents 932 of input fields, communicate with the database, display alerts and dialogs, or 933 even fake the POST request to a GET, with the effect of showing a completely 934 different document (See <a href="#switching">Switching URLs</a>). 935 936 <p>GET builds up all GUI components on the server. These components are objects 937 which encapsulate state and behavior of the HTML page in the browser. Whenever a 938 button is pressed, the page is reloaded via a POST request. Then - before any 939 output is sent to the browser - the <code>action</code> function takes control. 940 It performs error checks on all components, processes possible user input on the 941 HTML page, and stores the values in correct format (text, number, date, object 942 etc.) in each component. 943 944 <p>The state of a form is preserved over time. When the user returns to a 945 previous page with the browser's BACK button, that state is reactivated, and may 946 be POSTed again. 947 948 <p>The following silly example displays two text fields. If you enter some text 949 into the "Source" field, you can copy it in upper or lower case to the 950 "Destination" field by pressing one of the buttons 951 952 <pre><code> 953 ######################################################################## 954 (app) 955 956 (action 957 (html 0 "Case Conversion" "@lib.css" NIL 958 (form NIL 959 (<grid> 2 960 "Source" (gui 'src '(+TextField) 30) 961 "Destination" (gui 'dst '(+Lock +TextField) 30) ) 962 (gui '(+JS +Button) "Upper Case" 963 '(set> (: home dst) 964 (uppc (val> (: home src))) ) ) 965 (gui '(+JS +Button) "Lower Case" 966 '(set> (: home dst) 967 (lowc (val> (: home src))) ) ) ) ) ) 968 ######################################################################## 969 </code></pre> 970 971 <p>The <code>+Lock</code> prefix class in the "Destination" field makes that 972 field read-only. The only way to get some text into that field is by using one 973 of the buttons. 974 975 976 <h4><a name="switching">Switching URLs</a></h4> 977 978 <p>Because an action code runs before <code>html</code> has a chance to output 979 an HTTP header, it can abort the current page and present something different to 980 the user. This might, of course, be another HTML page, but would not be very 981 interesting as a normal link would suffice. Instead, it can cause the download 982 of dynamically generated data. 983 984 <p>The next example shows a text area and two buttons. Any text entered into the 985 text area is exported either as a text file via the first button, or a PDF 986 document via the second button 987 988 <pre><code> 989 ######################################################################## 990 (load "@lib/ps.l") 991 992 (app) 993 994 (action 995 (html 0 "Export" "@lib.css" NIL 996 (form NIL 997 (gui '(+TextField) 30 8) 998 (gui '(+Button) "Text" 999 '(let Txt (tmp "export.txt") 1000 (out Txt (prinl (val> (: home gui 1)))) 1001 (url Txt) ) ) 1002 (gui '(+Button) "PDF" 1003 '(psOut NIL "foo" 1004 (a4) 1005 (indent 40 40) 1006 (down 60) 1007 (hline 3) 1008 (font (14 . "Times-Roman") 1009 (ps (val> (: home gui 1))) ) 1010 (hline 3) 1011 (page) ) ) ) ) ) 1012 ######################################################################## 1013 </code></pre> 1014 1015 <p>(a text area is built when you supply two numeric arguments (columns and 1016 rows) to a <code>+TextField</code> class) 1017 1018 <p>The action code of the first button creates a temporary file (i.e. a file 1019 named "export.txt" in the current process's temporary space), prints the value 1020 of the text area (this time we did not bother to give it a name, we simply refer 1021 to it as the form's first gui list element) into that file, and then calls the 1022 <code>url</code> function with the file name. 1023 1024 <p>The second button uses the PostScript library "@lib/ps.l" to create a 1025 temporary file "foo.pdf". Here, the temporary file creation and the call to the 1026 <code>url</code> function is hidden in the internal mechanisms of 1027 <code>psOut</code>. The effect is that the browser receives a PDF document and 1028 displays it. 1029 1030 1031 <h4><a name="dialogs">Alerts and Dialogs</a></h4> 1032 1033 <p>Alerts and dialogs are not really what they used to be ;-) 1034 1035 <p>They do not "pop up". In this framework, they are just a kind of 1036 simple-to-use, pre-fabricated form. They can be invoked by a button's action 1037 code, and appear always on the current page, immediately preceding the form 1038 which created them. 1039 1040 <p>Let's look at an example which uses two alerts and a dialog. In the 1041 beginning, it displays a simple form, with a locked text field, and two buttons 1042 1043 <pre><code> 1044 ######################################################################## 1045 (app) 1046 1047 (action 1048 (html 0 "Alerts and Dialogs" "@lib.css" NIL 1049 (form NIL 1050 (gui '(+Init +Lock +TextField) "Initial Text" 20 "My Text") 1051 (gui '(+Button) "Alert" 1052 '(alert NIL "This is an alert " (okButton)) ) 1053 (gui '(+Button) "Dialog" 1054 '(dialog NIL 1055 (<br> "This is a dialog.") 1056 (<br> 1057 "You can change the text here " 1058 (gui '(+Init +TextField) (val> (: top 1 gui 1)) 20) ) 1059 (<br> "and then re-submit it to the form.") 1060 (gui '(+Button) "Re-Submit" 1061 '(alert NIL "Are you sure? " 1062 (yesButton 1063 '(set> (: home top 2 gui 1) 1064 (val> (: home top 1 gui 1)) ) ) 1065 (noButton) ) ) 1066 (cancelButton) ) ) ) ) ) 1067 ######################################################################## 1068 </code></pre> 1069 1070 <p>The <code>+Init</code> prefix class initializes the "My Text" field with the 1071 string "Initial Text". As the field is locked, you cannot modify this value 1072 directly. 1073 1074 <p>The first button brings up an alert saying "This is an alert.". You can 1075 dispose it by pressing "OK". 1076 1077 <p>The second button brings up a dialog with an editable text field, containing 1078 a copy of the value from the form's locked text field. You can modify this 1079 value, and send it back to the form, if you press "Re-Submit" and answer "Yes" 1080 to the "Are you sure?" alert. 1081 1082 1083 <h4><a name="calc">A Calculator Example</a></h4> 1084 1085 <p>Now let's forget our "project.l" test file for a moment, and move on to a 1086 more substantial and practical, stand-alone, example. Using what we have learned 1087 so far, we want to build a simple bignum calculator. ("bignum" because PicoLisp 1088 can do <i>only</i> bignums) 1089 1090 <p>It uses a single form, a single numeric input field, and lots of buttons. It 1091 can be found in the PicoLisp distribution (e.g. under "/usr/share/picolisp/") in 1092 "misc/calc.l", together with a directly executable wrapper script "misc/calc". 1093 1094 <p>To use it, change to the PicoLisp installation directory, and start it as 1095 1096 <pre><code> 1097 $ misc/calc 1098 </code></pre> 1099 1100 <p>or call it with an absolute path, e.g. 1101 1102 <pre><code> 1103 $ /usr/share/picolisp/misc/calc 1104 </code></pre> 1105 1106 <p>If you like to get a PicoLisp prompt for inspection, start it instead as 1107 1108 <pre><code> 1109 $ pil misc/calc.l -main -go + 1110 </code></pre> 1111 1112 <p>Then - as before - point your browser to '<code><a 1113 href="http://localhost:8080">http://localhost:8080</a></code>'. 1114 1115 <p>The code for the calculator logic and the GUI is rather straightforward. The 1116 entry point is the single function <code>calculator</code>. It is called 1117 directly (as described in <a href="#urlSyntax">URL Syntax</a>) as the server's 1118 default URL, and implicitly in all POST requests. No further file access is 1119 needed once the calculator is running. 1120 1121 <p>Note that for a production application, we inserted an allow-statement (as 1122 recommended by the <a href="#security">Security</a> chapter) 1123 1124 <pre><code> 1125 (allowed NIL "!calculator" "@lib.css") 1126 </code></pre> 1127 1128 <p>at the beginning of "misc/calc.l". This will restrict external access to that 1129 single function. 1130 1131 <p>The calculator uses three global variables, <code>*Init</code>, 1132 <code>*Accu</code> and <code>*Stack</code>. <code>*Init</code> is a boolean flag 1133 set by the operator buttons to indicate that the next digit should initialize 1134 the accumulator to zero. <code>*Accu</code> is the accumulator. It is always 1135 displayed in the numeric input field, accepts user input, and it holds the 1136 results of calculations. <code>*Stack</code> is a push-down stack, holding 1137 postponed calculations (operators, priorities and intermediate results) with 1138 lower-priority operators, while calculations with higher-priority operators are 1139 performed. 1140 1141 <p>The function <code>digit</code> is called by the digit buttons, and adds 1142 another digit to the accumulator. 1143 1144 <p>The function <code>calc</code> does an actual calculation step. It pops the 1145 stack, checks for division by zero, and displays an error alert if necessary. 1146 1147 <p><code>operand</code> processes an operand button, accepting a function and a 1148 priority as arguments. It compares the priority with that in the top-of-stack 1149 element, and delays the calculation if it is less. 1150 1151 <p><code>finish</code> is used to calculate the final result. 1152 1153 <p>The <code>calculator</code> function has one numeric input field, with a 1154 width of 60 characters 1155 1156 <pre><code> 1157 (gui '(+Var +NumField) '*Accu 60) 1158 </code></pre> 1159 1160 <p>The <code>+Var</code> prefix class associates this field with the global 1161 variable <code>*Accu</code>. All changes to the field will show up in that 1162 variable, and modification of that variable's value will appear in the field. 1163 1164 <p>The <a name="sqrtButton">square root operator button</a> has an 1165 <code>+Able</code> prefix class 1166 1167 <pre><code> 1168 (gui '(+Able +JS +Button) '(ge0 *Accu) (char 8730) 1169 '(setq *Accu (sqrt *Accu)) ) 1170 </code></pre> 1171 1172 1173 <p>with an argument expression which checks that the current value in the 1174 accumulator is positive, and disables the button if otherwise. 1175 1176 <p>The rest of the form is just an array (grid) of buttons, encapsulating all 1177 functionality of the calculator. The user can enter numbers into the input 1178 field, either by using the digit buttons, or by directly typing them in, and 1179 perform calculations with the operator buttons. Supported operations are 1180 addition, subtraction, multiplication, division, sign inversion, square root and 1181 power (all in bignum integer arithmetic). The '<code>C</code>' button just 1182 clears the accumulator, while the '<code>A</code>' button also clears all 1183 pending calculations. 1184 1185 <p>All that in 53 lines of code! 1186 1187 1188 <p><hr> 1189 <h3><a name="charts">Charts</a></h3> 1190 1191 <p>Charts are virtual components, maintaining the internal representation of 1192 two-dimensional data. 1193 1194 <p>Typically, these data are nested lists, database selections, or some kind of 1195 dynamically generated tabular information. Charts make it possible to view them 1196 in rows and columns (usually in HTML <a href="#tables">tables</a>), scroll up 1197 and down, and associate them with their corresponding visible GUI components. 1198 1199 <p>In fact, the logic to handle charts makes up a substantial part of the whole 1200 framework, with large impact on all internal mechanisms. Each GUI component must 1201 know whether it is part of a chart or not, to be able to handle its contents 1202 properly during updates and user interactions. 1203 1204 <p>Let's assume we want to collect textual and numerical data. We might create a 1205 table 1206 1207 <pre><code> 1208 ######################################################################## 1209 (app) 1210 1211 (action 1212 (html 0 "Table" "@lib.css" NIL 1213 (form NIL 1214 (<table> NIL NIL '((NIL "Text") (NIL "Number")) 1215 (do 4 1216 (<row> NIL 1217 (gui '(+TextField) 20) 1218 (gui '(+NumField) 10) ) ) ) 1219 (<submit> "Save") ) ) ) 1220 ######################################################################## 1221 </code></pre> 1222 1223 <p>with two columns "Text" and "Number", and four rows, each containing a 1224 <code>+TextField</code> and a <code>+NumField</code>. 1225 1226 <p>You can enter text into the first column, and numbers into the second. 1227 Pressing the "Save" button stores these values in the components on the server 1228 (or produces an error message if a string in the second column is not a legal 1229 number). 1230 1231 <p>There are two problems with this solution: 1232 1233 <p><ol> 1234 <li>Though you can get at the user input for the individual fields, e.g. 1235 1236 <pre><code> 1237 : (val> (get *Top 'gui 2)) # Value in the first row, second column 1238 -> 123 1239 </code></pre> 1240 1241 there is no direct way to get the whole data structure as a single list. 1242 Instead, you have to traverse all GUI components and collect the data. 1243 1244 <li>The user cannot input more than four rows of data, because there is no easy 1245 way to scroll down and make space for more. 1246 1247 </ol> 1248 1249 <p>A chart can handle these things: 1250 1251 <pre><code> 1252 ######################################################################## 1253 (app) 1254 1255 (action 1256 (html 0 "Chart" "@lib.css" NIL 1257 (form NIL 1258 (gui '(+Chart) 2) # Inserted a +Chart 1259 (<table> NIL NIL '((NIL "Text") (NIL "Number")) 1260 (do 4 1261 (<row> NIL 1262 (gui 1 '(+TextField) 20) # Inserted '1' 1263 (gui 2 '(+NumField) 10) ) ) ) # Inserted '2' 1264 (<submit> "Save") ) ) ) 1265 ######################################################################## 1266 </code></pre> 1267 1268 <p>Note that we inserted a <code>+Chart</code> component before the GUI 1269 components which should be managed by the chart. The argument '2' tells the 1270 chart that it has to expect two columns. 1271 1272 <p>Each component got an index number (here '1' and '2') as the first argument 1273 to <code>gui</code>, indicating the column into which this component should go 1274 within the chart. 1275 1276 <p>Now - if you entered "a", "b" and "c" into the first, and 1, 2, and 3 into 1277 the second column - we can retrieve the chart's complete contents by sending it 1278 the <code>val></code> message 1279 1280 <pre><code> 1281 : (val> (get *Top 'chart 1)) # Retrieve the value of the first chart 1282 -> (("a" 1) ("b" 2) ("c" 3)) 1283 </code></pre> 1284 1285 <p>BTW, a more convenient function is <code>chart</code> 1286 1287 <pre><code> 1288 : (val> (chart)) # Retrieve the value of the current chart 1289 -> (("a" 1) ("b" 2) ("c" 3)) 1290 </code></pre> 1291 1292 <p><code>chart</code> can be used instead of the above construct when we want to 1293 access the "current" chart, i.e. the chart most recently processed in the 1294 current form. 1295 1296 1297 <h4><a name="scrolling">Scrolling</a></h4> 1298 1299 <p>To enable scrolling, let's also insert two buttons. We use the pre-defined 1300 classes <code>+UpButton</code> and <code>+DnButton</code> 1301 1302 <pre><code> 1303 ######################################################################## 1304 (app) 1305 1306 (action 1307 (html 0 "Scrollable Chart" "@lib.css" NIL 1308 (form NIL 1309 (gui '(+Chart) 2) 1310 (<table> NIL NIL '((NIL "Text") (NIL "Number")) 1311 (do 4 1312 (<row> NIL 1313 (gui 1 '(+TextField) 20) 1314 (gui 2 '(+NumField) 10) ) ) ) 1315 (gui '(+UpButton) 1) # Inserted two buttons 1316 (gui '(+DnButton) 1) 1317 (----) 1318 (<submit> "Save") ) ) ) 1319 ######################################################################## 1320 </code></pre> 1321 1322 <p>to scroll down and up a single (argument '1') line at a time. 1323 1324 <p>Now it is possible to enter a few rows of data, scroll down, and continue. It 1325 is not necessary (except in the beginning, when the scroll buttons are still 1326 disabled) to press the "Save" button, because <b>any</b> button in the form will 1327 send changes to the server's internal structures before any action is performed. 1328 1329 1330 <h4><a name="putGet">Put and Get Functions</a></h4> 1331 1332 <p>As we said, a chart is a virtual component to edit two-dimensional data. 1333 Therefore, a chart's native data format is a list of lists: Each sublist 1334 represents a single row of data, and each element of a row corresponds to a 1335 single GUI component. 1336 1337 <p>In the example above, we saw a row like 1338 1339 <pre><code> 1340 ("a" 1) 1341 </code></pre> 1342 1343 <p>being mapped to 1344 1345 <pre><code> 1346 (gui 1 '(+TextField) 20) 1347 (gui 2 '(+NumField) 10) 1348 </code></pre> 1349 1350 <p>Quite often, however, such a one-to-one relationship is not desired. The 1351 internal data structures may have to be presented in a different form to the 1352 user, and user input may need conversion to an internal representation. 1353 1354 <p>For that, a chart accepts - in addition to the "number of columns" argument - 1355 two optional function arguments. The first function is invoked to 'put' the 1356 internal representation into the GUI components, and the second to 'get' data 1357 from the GUI into the internal representation. 1358 1359 <p>A typical example is a chart displaying customers in a database. While the 1360 internal representation is a (one-dimensional) list of customer objects, 'put' 1361 expands each object to a list with, say, the customer's first and second name, 1362 telephone number, address and so on. When the user enters a customer's name, 1363 'get' locates the matching object in the database and stores it in the internal 1364 representation. In the following, 'put' will in turn expand it to the GUI. 1365 1366 <p>For now, let's stick with a simpler example: A chart that holds just a list 1367 of numbers, but expands in the GUI to show also a textual form of each number 1368 (in German). 1369 1370 <pre><code> 1371 ######################################################################## 1372 (app) 1373 1374 (load "@lib/zahlwort.l") 1375 1376 (action 1377 (html 0 "Numerals" "@lib.css" NIL 1378 (form NIL 1379 (gui '(+Init +Chart) (1 5 7) 2 1380 '((N) (list N (zahlwort N))) 1381 car ) 1382 (<table> NIL NIL '((NIL "Numeral") (NIL "German")) 1383 (do 4 1384 (<row> NIL 1385 (gui 1 '(+NumField) 9) 1386 (gui 2 '(+Lock +TextField) 90) ) ) ) 1387 (gui '(+UpButton) 1) 1388 (gui '(+DnButton) 1) 1389 (----) 1390 (<submit> "Save") ) ) ) 1391 ######################################################################## 1392 </code></pre> 1393 1394 <p>"@lib/zahlwort.l" defines the utility function <code>zahlwort</code>, which 1395 is required later by the 'put' function. <code>zahlwort</code> accepts a number 1396 and returns its wording in German. 1397 1398 <p>Now look at the code 1399 1400 <pre><code> 1401 (gui '(+Init +Chart) (1 5 7) 2 1402 '((N) (list N (zahlwort N))) 1403 car ) 1404 </code></pre> 1405 1406 <p>We prefix the <code>+Chart</code> class with <code>+Init</code>, and pass it 1407 a list of numbers <code>(1 5 7)</code> for the initial value of the chart. Then, 1408 following the '2' (the chart has two columns), we pass a 'put' function 1409 1410 <pre><code> 1411 '((N) (list N (zahlwort N))) 1412 </code></pre> 1413 1414 <p>which takes a number and returns a list of that number and its wording, and a 1415 'get' function 1416 1417 <pre><code> 1418 car ) 1419 </code></pre> 1420 1421 <p>which in turn accepts such a list and returns a number, which happens to be 1422 the list's first element. 1423 1424 <p>You can see from this example that 'get' is the inverse function of 'put'. 1425 'get' can be omitted, however, if the chart is read-only (contains no (or only 1426 locked) input fields). 1427 1428 <p>The field in the second column 1429 1430 <pre><code> 1431 (gui 2 '(+Lock +TextField) 90) ) ) ) 1432 </code></pre> 1433 1434 <p>is locked, because it displays the text generated by 'put', and is not 1435 supposed to accept any user input. 1436 1437 <p>When you start up this form in your browser, you'll see three pre-filled 1438 lines with "1/eins", "5/fünf" and "7/sieben", according to the 1439 <code>+Init</code> argument <code>(1 5 7)</code>. Typing a number somewhere into 1440 the first column, and pressing ENTER or one of the buttons, will show a suitable 1441 text in the second column. 1442 1443 1444 <p><hr> 1445 <h2><a name="guiClasses">GUI Classes</a></h2> 1446 1447 <p>In previous chapters we saw examples of GUI classes like 1448 <code>+TextField</code>, <code>+NumField</code> or <code>+Button</code>, often 1449 in combination with prefix classes like <code>+Lock</code>, <code>+Init</code> 1450 or <code>+Able</code>. Now we take a broader look at the whole hierarchy, and 1451 try more examples. 1452 1453 <p>The abstract class <code>+gui</code> is the base of all GUI classes. A live 1454 view of the class hierarchy can be obtained with the <code><a 1455 href="refD.html#dep">dep</a></code> ("dependencies") function: 1456 1457 <pre><code> 1458 : (dep '+gui) 1459 +gui 1460 +JsField 1461 +Button 1462 +UpButton 1463 +PickButton 1464 +DstButton 1465 +ClrButton 1466 +ChoButton 1467 +Choice 1468 +GoButton 1469 +BubbleButton 1470 +DelRowButton 1471 +ShowButton 1472 +DnButton 1473 +Img 1474 +field 1475 +Checkbox 1476 +TextField 1477 +FileField 1478 +ClassField 1479 +numField 1480 +NumField 1481 +FixField 1482 +BlobField 1483 +DateField 1484 +SymField 1485 +UpField 1486 +MailField 1487 +SexField 1488 +AtomField 1489 +PwField 1490 +ListTextField 1491 +LinesField 1492 +TelField 1493 +TimeField 1494 +HttpField 1495 +Radio 1496 -> +gui 1497 </code></pre> 1498 1499 <p>We see, for example, that <code>+DnButton</code> is a subclass of 1500 <code>+Button</code>, which in turn is a subclass of <code>+gui</code>. 1501 Inspecting <code>+DnButton</code> directly 1502 1503 <pre><code> 1504 : (dep '+DnButton) 1505 +Tiny 1506 +Rid 1507 +JS 1508 +Able 1509 +gui 1510 +Button 1511 +DnButton 1512 -> +DnButton 1513 </code></pre> 1514 1515 <p>shows that <code>+DnButton</code> inherits from <code>+Tiny</code>, 1516 <code>+Rid</code>, <code>+Able</code> and <code>+Button</code>. The actual 1517 definition of <code>+DnButton</code> can be found in "@lib/form.l" 1518 1519 <pre><code> 1520 (class +DnButton +Tiny +Rid +JS +Able +Button) 1521 ... 1522 </code></pre> 1523 1524 <p>In general, "@lib/form.l" is the ultimate reference to the framework, and 1525 should be freely consulted. 1526 1527 1528 <p><hr> 1529 <h3><a name="inputFields">Input Fields</a></h3> 1530 1531 <p>Input fields implement the visual display of application data, and allow - 1532 when enabled - input and modification of these data. 1533 1534 <p>On the HTML level, they can take the form of 1535 1536 <ul> 1537 <li>Normal text input fields 1538 <li>Textareas 1539 <li>Checkboxes 1540 <li>Drop-down selections 1541 <li>Password fields 1542 <li>HTML links 1543 <li>Plain HTML text 1544 </ul> 1545 1546 <p>Except for checkboxes, which are implemented by the <a 1547 href="#checkboxes">Checkbox</a> class, all these HTML representations are 1548 generated by <code>+TextField</code> and its content-specific subclasses like 1549 <code>+NumField</code>, <code>+DateField</code> etc. Their actual appearance (as 1550 one of the above forms) depends on their arguments: 1551 1552 <p>We saw already "normal" text fields. They are created with a single numeric 1553 argument. This example creates an editable field with a width of 10 characters: 1554 1555 <pre><code> 1556 (gui '(+TextField) 10) 1557 </code></pre> 1558 1559 <p>If you supply a second numeric for the line count ('4' in this case), you'll 1560 get a text area: 1561 1562 <pre><code> 1563 (gui '(+TextField) 10 4) 1564 </code></pre> 1565 1566 <p>Supplying a list of values instead of a count yields a drop-down selection 1567 (combo box): 1568 1569 <pre><code> 1570 (gui '(+TextField) '("Value 1" "Value 2" "Value 3")) 1571 </code></pre> 1572 1573 <p>In addition to these arguments, you can pass a string. Then the field is 1574 created with a label: 1575 1576 <pre><code> 1577 (gui '(+TextField) 10 "Plain") 1578 (gui '(+TextField) 10 4 "Text Area") 1579 (gui '(+TextField) '("Value 1" "Value 2" "Value 3") "Selection") 1580 </code></pre> 1581 1582 <p>Finally, without any arguments, the field will appear as a plain HTML text: 1583 1584 <pre><code> 1585 (gui '(+TextField)) 1586 </code></pre> 1587 1588 <p>This makes mainly sense in combination with prefix classes like 1589 <code>+Var</code> and <code>+Obj</code>, to manage the contents of these fields, 1590 and achieve special behavior as HTML links or scrollable chart values. 1591 1592 1593 <h4><a name="numberFields">Numeric Input Fields</a></h4> 1594 1595 <p>A <code>+NumField</code> returns a number from its <code>val></code> 1596 method, and accepts a number for its <code>set></code> method. It issues an 1597 error message when user input cannot be converted to a number. 1598 1599 <p>Large numbers are shown with a thousands-separator, as determined by the 1600 current locale. 1601 1602 <pre><code> 1603 ######################################################################## 1604 (app) 1605 1606 (action 1607 (html 0 "+NumField" "@lib.css" NIL 1608 (form NIL 1609 (gui '(+NumField) 10) 1610 (gui '(+JS +Button) "Print value" 1611 '(msg (val> (: home gui 1))) ) 1612 (gui '(+JS +Button) "Set to 123" 1613 '(set> (: home gui 1) 123) ) ) ) ) 1614 ######################################################################## 1615 </code></pre> 1616 1617 <p>A <code>+FixField</code> needs an additional scale factor argument, and 1618 accepts/returns scaled fixpoint numbers. 1619 1620 <p>The decimal separator is determined by the current locale. 1621 1622 <pre><code> 1623 ######################################################################## 1624 (app) 1625 1626 (action 1627 (html 0 "+FixField" "@lib.css" NIL 1628 (form NIL 1629 (gui '(+FixField) 3 10) 1630 (gui '(+JS +Button) "Print value" 1631 '(msg (format (val> (: home gui 1)) 3)) ) 1632 (gui '(+JS +Button) "Set to 123.456" 1633 '(set> (: home gui 1) 123456) ) ) ) ) 1634 ######################################################################## 1635 </code></pre> 1636 1637 1638 <h4><a name="timeDateFields">Time & Date</a></h4> 1639 1640 <p>A <code>+DateField</code> accepts and returns a <code><a 1641 href="refD.html#date">date</a></code> value. 1642 1643 <pre><code> 1644 ######################################################################## 1645 (app) 1646 1647 (action 1648 (html 0 "+DateField" "@lib.css" NIL 1649 (form NIL 1650 (gui '(+DateField) 10) 1651 (gui '(+JS +Button) "Print value" 1652 '(msg (datStr (val> (: home gui 1)))) ) 1653 (gui '(+JS +Button) "Set to \"today\"" 1654 '(set> (: home gui 1) (date)) ) ) ) ) 1655 ######################################################################## 1656 </code></pre> 1657 1658 <p>The format displayed to - and entered by - the user depends on the current 1659 locale (see <code><a href="refD.html#datStr">datStr</a></code> and <code><a 1660 href="refE.html#expDat">expDat</a></code>). You can change it, for example to 1661 1662 <pre><code> 1663 : (locale "DE" "de") 1664 -> NIL 1665 </code></pre> 1666 1667 <p>If no locale is set, the format is YYYY-MM-DD. Some pre-defined locales use 1668 patterns like DD.MM.YYYY (DE), YYYY/MM/DD (JP), DD/MM/YYYY (UK), or MM/DD/YYYY 1669 (US). 1670 1671 <p>An error is issued when user input does not match the current locale's date 1672 format. 1673 1674 <p>Independent from the locale setting, a <code>+DateField</code> tries to 1675 expand abbreviated input from the user. A small number is taken as that day of 1676 the current month, larger numbers expand to day and month, or to day, month and 1677 year: 1678 1679 <ul> 1680 <li>"7" gives the 7th of the current month 1681 <li>"031" or "0301" give the 3rd of January of the current year 1682 <li>"311" or "3101" give the 31st of January of the current year 1683 <li>"0311" gives the 3rd of November of the current year 1684 <li>"01023" or "010203" give the first of February in the year 2003 1685 <li>and so on 1686 </ul> 1687 1688 <p>Similar is the <code>+TimeField</code>. It accepts and returns a <code><a 1689 href="refT.html#time">time</a></code> value. 1690 1691 <pre><code> 1692 ######################################################################## 1693 (app) 1694 1695 (action 1696 (html 0 "+TimeField" "@lib.css" NIL 1697 (form NIL 1698 (gui '(+TimeField) 8) 1699 (gui '(+JS +Button) "Print value" 1700 '(msg (tim$ (val> (: home gui 1)))) ) 1701 (gui '(+JS +Button) "Set to \"now\"" 1702 '(set> (: home gui 1) (time)) ) ) ) ) 1703 ######################################################################## 1704 </code></pre> 1705 1706 <p>When the field width is '8', like in this example, time is displayed in the 1707 format <code>HH:MM:SS</code>. Another possible value would be '5', causing 1708 <code>+TimeField</code> to display its value as <code>HH:MM</code>. 1709 1710 <p>An error is issued when user input cannot be converted to a time value. 1711 1712 <p>The user may omit the colons. If he inputs just a small number, it should be 1713 between '0' and '23', and will be taken as a full hour. '125' expands to 1714 "12:05", '124517' to "12:45:17", and so on. 1715 1716 1717 <h4><a name="telFields">Telephone Numbers</a></h4> 1718 1719 <p>Telephone numbers are represented internally by the country code (without a 1720 leading plus sign or zero) followed by the local phone number (ideally separated 1721 by spaces) and the phone extension (ideally separated by a hyphen). The exact 1722 format of the phone number string is not enforced by the GUI, but further 1723 processing (e.g. database searches) normally uses <code><a 1724 href="refF.html#fold">fold</a></code> for better reproducibility. 1725 1726 <p>To display a phone number, <code>+TelField</code> replaces the country code 1727 with a single zero if it is the country code of the current locale, or prepends 1728 it with a plus sign if it is a foreign country (see <code><a 1729 href="refT.html#telStr">telStr</a></code>). 1730 1731 <p>For user input, a plus sign or a double zero is simply dropped, while a 1732 single leading zero is replaced with the current locale's country code (see 1733 <code><a href="refE.html#expTel">expTel</a></code>). 1734 1735 <pre><code> 1736 ######################################################################## 1737 (app) 1738 (locale "DE" "de") 1739 1740 (action 1741 (html 0 "+TelField" "@lib.css" NIL 1742 (form NIL 1743 (gui '(+TelField) 20) 1744 (gui '(+JS +Button) "Print value" 1745 '(msg (val> (: home gui 1))) ) 1746 (gui '(+JS +Button) "Set to \"49 1234 5678-0\"" 1747 '(set> (: home gui 1) "49 1234 5678-0") ) ) ) ) 1748 ######################################################################## 1749 </code></pre> 1750 1751 1752 <h4><a name="checkboxes">Checkboxes</a></h4> 1753 1754 <p>A <code>+Checkbox</code> is straightforward. User interaction is restricted 1755 to clicking it on and off. It accepts boolean (<code>NIL</code> or 1756 non-<code>NIL</code>) values, and returns <code>T</code> or <code>NIL</code>. 1757 1758 <pre><code> 1759 ######################################################################## 1760 (app) 1761 1762 (action 1763 (html 0 "+Checkbox" "@lib.css" NIL 1764 (form NIL 1765 (gui '(+Checkbox)) 1766 (gui '(+JS +Button) "Print value" 1767 '(msg (val> (: home gui 1))) ) 1768 (gui '(+JS +Button) "On" 1769 '(set> (: home gui 1) T) ) 1770 (gui '(+JS +Button) "Off" 1771 '(set> (: home gui 1) NIL) ) ) ) ) 1772 ######################################################################## 1773 </code></pre> 1774 1775 1776 <p><hr> 1777 <h3><a name="fieldPrefix">Field Prefix Classes</a></h3> 1778 1779 <p>A big part of this framework's power is owed to the combinatorial flexibility 1780 of prefix classes for GUI- and DB-objects. They allow to surgically override 1781 individual methods in the inheritance tree, and can be combined in various ways 1782 to achieve any desired behavior. 1783 1784 <p>Technically, there is nothing special about prefix classes. They are just 1785 normal classes. They are called "prefix" because they are intended to be written 1786 <i>before</i> other classes in a class's or object's list of superclasses. 1787 1788 <p>Usually they take their own arguments for their <code>T</code> method from 1789 the list of arguments to the <code>gui</code> function. 1790 1791 1792 <h4><a name="initPrefix">Initialization</a></h4> 1793 1794 <p><code>+Init</code> overrides the <code>init></code> method for that 1795 component. The <code>init></code> message is sent to a <code>+gui</code> 1796 component when the page is loaded for the first time (during a GET request). 1797 <code>+Init</code> takes an expression for the initial value of that field. 1798 1799 <pre><code> 1800 (gui '(+Init +TextField) "This is the initial text" 30) 1801 </code></pre> 1802 1803 <p>Other classes which automatically give a value to a field are 1804 <code>+Var</code> (linking the field to a variable) and <code>+E/R</code> 1805 (linking the field to a database entity/relation). 1806 1807 <p><code>+Cue</code> can be used, for example in "mandatory" fields, to give a 1808 hint to the user about what he is supposed to enter. It will display the 1809 argument value, in angular brackets, if and only if the field's value is 1810 <code>NIL</code>, and the <code>val></code> method will return 1811 <code>NIL</code> despite the fact that this value is displayed. 1812 1813 <p>Cause an empty field to display "<Please enter some text here>": 1814 1815 <pre><code> 1816 (gui '(+Cue +TextField) "Please enter some text here" 30) 1817 </code></pre> 1818 1819 1820 <h4><a name="ablePrefix">Disabling and Enabling</a></h4> 1821 1822 <p>An important feature of an interactive GUI is the context-sensitive disabling 1823 and enabling of individual components, or of a whole form. 1824 1825 <p>The <code>+Able</code> prefix class takes an argument expression, and 1826 disables the component if this expression returns <code>NIL</code>. We saw an 1827 example for its usage already in the <a href="#sqrtButton">square root 1828 button</a> of the calculator example. Or, for illustration purposes, imagine a 1829 button which is supposed to be enabled only after Christmas 1830 1831 <pre><code> 1832 (gui '(+Able +Button) 1833 '(>= (cdr (date (date))) (12 24)) 1834 "Close this year" 1835 '(endOfYearProcessing) ) 1836 </code></pre> 1837 1838 <p>or a password field that is disabled as long as somebody is logged in 1839 1840 <pre><code> 1841 (gui '(+Able +PwField) '(not *Login) 10 "Password") 1842 </code></pre> 1843 1844 <p>A special case is the <code>+Lock</code> prefix, which permanently and 1845 unconditionally disables a component. It takes no arguments 1846 1847 <pre><code> 1848 (gui '(+Lock +NumField) 10 "Count") 1849 </code></pre> 1850 1851 <p>('10' and "Count" are for the <code>+NumField</code>), and creates a 1852 read-only field. 1853 1854 <p>The whole form can be disabled by calling <code>disable</code> with a 1855 non-<code>NIL</code> argument. This affects all components in this form. Staying 1856 with the above example, we can make the form read-only until Christmas 1857 1858 <pre><code> 1859 (form NIL 1860 (disable (> (12 24) (cdr (date (date))))) # Disable whole form 1861 (gui ..) 1862 .. ) 1863 </code></pre> 1864 1865 <p>Even in a completely disabled form, however, it is often necessary to 1866 re-enable certain components, as they are needed for navigation, scrolling, or 1867 other activities which don't affect the contents of the form. This is done by 1868 prefixing these fields with <code>+Rid</code> (i.e. getting "rid" of the lock). 1869 1870 <pre><code> 1871 (form NIL 1872 (disable (> (12 24) (cdr (date (date))))) 1873 (gui ..) 1874 .. 1875 (gui '(+Rid +Button) ..) # Button is enabled despite the disabled form 1876 .. ) 1877 </code></pre> 1878 1879 1880 <h4><a name="formatPrefix">Formatting</a></h4> 1881 1882 <p>GUI prefix classes allow a fine-grained control of how values are stored in - 1883 and retrieved from - components. As in predefined classes like 1884 <code>+NumField</code> or <code>+DateField</code>, they override the 1885 <code>set></code> and/or <code>val></code> methods. 1886 1887 <p><code>+Set</code> takes an argument function which is called whenever that 1888 field is set to some value. To convert all user input to upper case 1889 1890 <pre><code> 1891 (gui '(+Set +TextField) uppc 30) 1892 </code></pre> 1893 1894 <p><code>+Val</code> is the complement to <code>+Set</code>. It takes a function 1895 which is called whenever the field's value is retrieved. To return the square of 1896 a field's value 1897 1898 <pre><code> 1899 (gui '(+Val +NumField) '((N) (* N N)) 10) 1900 </code></pre> 1901 1902 <p><code>+Fmt</code> is just a combination of <code>+Set</code> and 1903 <code>+Val</code>, and takes two functional arguments. This example will display 1904 upper case characters, while returning lower case characters internally 1905 1906 <pre><code> 1907 (gui '(+Fmt +TextField) uppc lowc 30) 1908 </code></pre> 1909 1910 <p><code>+Map</code> does (like <code>+Fmt</code>) a two-way translation. It 1911 uses a list of cons pairs for a linear lookup, where the CARs represent the 1912 displayed values which are internally mapped to the values in the CDRs. If a 1913 value is not found in this list during <code>set></code> or 1914 <code>val></code>, it is passed through unchanged. 1915 1916 <p>Normally, <code>+Map</code> is used in combination with the combo box 1917 incarnation of text fields (see <a href="#inputFields">Input Fields</a>). This 1918 example displays "One", "Two" and "Three" to the user, but returns a number 1, 2 1919 or 3 internally 1920 1921 <pre><code> 1922 ######################################################################## 1923 (app) 1924 1925 (action 1926 (html 0 "+Map" "@lib.css" NIL 1927 (form NIL 1928 (gui '(+Map +TextField) 1929 '(("One" . 1) ("Two" . 2) ("Three" . 3)) 1930 '("One" "Two" "Three") ) 1931 (gui '(+Button) "Print" 1932 '(msg (val> (field -1))) ) ) ) ) 1933 ######################################################################## 1934 </code></pre> 1935 1936 1937 <h4><a name="sideEffects">Side Effects</a></h4> 1938 1939 <p>Whenever a button is pressed in the GUI, any changes caused by 1940 <code>action</code> in the current environment (e.g. the database or application 1941 state) need to be reflected in the corresponding GUI fields. For that, the 1942 <code>upd></code> message is sent to all components. Each component then 1943 takes appropriate measures (e.g. refresh from database objects, load values from 1944 variables, or calculate a new value) to update its value. 1945 1946 <p>While the <code>upd></code> method is mainly used internally, it can be 1947 overridden in existing classes via the <code>+Upd</code> prefix class. Let's 1948 print updated values to standard error 1949 1950 <pre><code> 1951 ######################################################################## 1952 (app) 1953 (default *Number 0) 1954 1955 (action 1956 (html 0 "+Upd" "@lib.css" NIL 1957 (form NIL 1958 (gui '(+Upd +Var +NumField) 1959 '(prog (extra) (msg *Number)) 1960 '*Number 8 ) 1961 (gui '(+JS +Button) "Increment" 1962 '(inc '*Number) ) ) ) ) 1963 ######################################################################## 1964 </code></pre> 1965 1966 1967 <h4><a name="validPrefix">Validation</a></h4> 1968 1969 <p>To allow automatic validation of user input, the <code>chk></code> message 1970 is sent to all components at appropriate times. The corresponding method should 1971 return <code>NIL</code> if the value is all right, or a string describing the 1972 error otherwise. 1973 1974 <p>Many of the built-in classes have a <code>chk></code> method. The 1975 <code>+NumField</code> class checks for legal numeric input, or the 1976 <code>+DateField</code> for a valid calendar date. 1977 1978 <p>An on-the-fly check can be implemented with the <code>+Chk</code> prefix 1979 class. The following code only accepts numbers not bigger than 9: The 1980 <code>or</code> expression first delegates the check to the main 1981 <code>+NumField</code> class, and - if it does not give an error - returns an 1982 error string when the current value is greater than 9. 1983 1984 <pre><code> 1985 ######################################################################## 1986 (app) 1987 1988 (action 1989 (html 0 "+Chk" "@lib.css" NIL 1990 (form NIL 1991 (gui '(+Chk +NumField) 1992 '(or 1993 (extra) 1994 (and (> (val> This) 9) "Number too big") ) 1995 12 ) 1996 (gui '(+JS +Button) "Print" 1997 '(msg (val> (field -1))) ) ) ) ) 1998 ######################################################################## 1999 </code></pre> 2000 2001 <p>A more direct kind of validation is built-in via the <code>+Limit</code> 2002 class. It controls the <code>maxlength</code> attribute of the generated HTML 2003 input field component. Thus, it is impossible to type to more characters than 2004 allowed into the field. 2005 2006 <pre><code> 2007 ######################################################################## 2008 (app) 2009 2010 (action 2011 (html 0 "+Limit" "@lib.css" NIL 2012 (form NIL 2013 (gui '(+Limit +TextField) 4 8) 2014 (gui '(+JS +Button) "Print" 2015 '(msg (val> (field -1))) ) ) ) ) 2016 ######################################################################## 2017 </code></pre> 2018 2019 2020 <h4><a name="linkage">Data Linkage</a></h4> 2021 2022 <p>Although <code>set></code> and <code>val></code> are the official 2023 methods to get a value in and out of a GUI component, they are not very often 2024 used explicitly. Instead, components are directly linked to internal Lisp data 2025 structures, which are usually either variables or database objects. 2026 2027 <p>The <code>+Var</code> prefix class takes a variable (described as the 2028 <code>var</code> data type - either a symbol or a cons pair - in the <a 2029 href="ref.html#fun">Function Reference</a>). In the following example, we 2030 initialize a global variable with the value "abc", and let a 2031 <code>+TextField</code> operate on it. The "Print" button can be used to display 2032 its current value. 2033 2034 <pre><code> 2035 ######################################################################## 2036 (app) 2037 2038 (setq *TextVariable "abc") 2039 2040 (action 2041 (html 0 "+Var" "@lib.css" NIL 2042 (form NIL 2043 (gui '(+Var +TextField) '*TextVariable 8) 2044 (gui '(+JS +Button) "Print" 2045 '(msg *TextVariable) ) ) ) ) 2046 ######################################################################## 2047 </code></pre> 2048 2049 <p><code>+E/R</code> takes an entity/relation specification. This is a cons 2050 pair, with a relation in its CAR (e.g. <code>nm</code>, for an object's name), 2051 and an expression in its CDR (typically <code>(: home obj)</code>, the object 2052 stored in the <code>obj</code> property of the current form). 2053 2054 <p>For an isolated, simple example, we create a temporary database, and access 2055 the <code>nr</code> and <code>nm</code> properties of an object stored in a 2056 global variable <code>*Obj</code>. 2057 2058 <pre><code> 2059 ######################################################################## 2060 (when (app) # On start of session 2061 (class +Tst +Entity) # Define data model 2062 (rel nr (+Number)) # with a number 2063 (rel nm (+String)) # and a string 2064 (pool (tmp "db")) # Create temporary DB 2065 (setq *Obj # and a single object 2066 (new! '(+Tst) 'nr 1 'nm "New Object") ) ) 2067 2068 (action 2069 (html 0 "+E/R" "@lib.css" NIL 2070 (form NIL 2071 (gui '(+E/R +NumField) '(nr . *Obj) 8) # Linkage to 'nr' 2072 (gui '(+E/R +TextField) '(nm . *Obj) 20) # Linkage to 'nm' 2073 (gui '(+JS +Button) "Show" # Show the object 2074 '(out 2 (show *Obj)) ) ) ) ) # on standard error 2075 ######################################################################## 2076 </code></pre> 2077 2078 2079 <p><hr> 2080 <h3><a name="buttons">Buttons</a></h3> 2081 2082 <p>Buttons are, as explained in <a href="#ctlFlow">Control Flow</a>, the only 2083 way (via POST requests) for an application to communicate with the server. 2084 2085 <p>Basically, a <code>+Button</code> takes 2086 2087 <ul> 2088 <li>a label, which may be either a string or the name of an image file 2089 <li>an optional alternative label, shown when the button is disabled 2090 <li>and an executable expression. 2091 </ul> 2092 2093 <p>Here is a minimal button, with just a label and an expression: 2094 2095 <pre><code> 2096 (gui '(+Button) "Label" '(doSomething)) 2097 </code></pre> 2098 2099 <p>And this is a button displaying different labels, depending on the state: 2100 2101 <pre><code> 2102 (gui '(+Button) "Enabled" "Disabled" '(doSomething)) 2103 </code></pre> 2104 2105 <p>To show an image instead of plain text, the label(s) must be preceeded by the 2106 <code>T</code> symbol: 2107 2108 <pre><code> 2109 (gui '(+Button) T "img/enabled.png" "img/disabled.png" '(doSomething)) 2110 </code></pre> 2111 2112 <p>The expression will be executed during <code>action</code> handling (see <a 2113 href="#actionForms">Action Forms</a>), when this button was pressed. 2114 2115 <p>Like other components, buttons can be extended and combined with prefix 2116 classes, and a variety of predefined classes and class combinations are 2117 available. 2118 2119 2120 <h4><a name="dialogButtons">Dialog Buttons</a></h4> 2121 2122 <p>Buttons are essential for the handling of <a href="#dialogs">alerts and 2123 dialogs</a>. Besides buttons for normal functions, like <a 2124 href="#scrolling">scrolling</a> in charts or other <a href="#sideEffects">side 2125 effects</a>, special buttons exist which can <i>close</i> an alert or dialog in 2126 addition to doing their principal job. 2127 2128 <p>Such buttons are usually subclasses of <code>+Close</code>, and most of them 2129 can be called easily with ready-made functions like <code>closeButton</code>, 2130 <code>cancelButton</code>, <code>yesButton</code> or <code>noButton</code>. We 2131 saw a few examples in <a href="#dialogs">Alerts and Dialogs</a>. 2132 2133 2134 <h4><a name="jsButtons">Active JavaScript</a></h4> 2135 2136 <p>When a button inherits from the <code>+JS</code> class (and JavaScript is 2137 enabled in the browser), that button will possibly show a much faster response 2138 in its action. 2139 2140 <p>The reason is that the activation of a <code>+JS</code> button will - instead 2141 of doing a normal POST - first try to send only the contents of all GUI 2142 components via an XMLHttpRequest to the server, and receive the updated values 2143 in response. This avoids the flicker caused by reloading and rendering of the 2144 whole page, is much faster, and also does not jump to the beginning of the page 2145 if it is larger than the browser window. The effect is especially noticeable 2146 while scrolling in charts. 2147 2148 <p>Only if this fails, for example because an error message was issued, or a 2149 dialog popped up, it will fall back, and the form will be POSTed in the normal 2150 way. 2151 2152 <p>Thus it makes no sense to use the <code>+JS</code> prefix for buttons that 2153 cause a change of the HTML code, open a dialog, or jump to another page. In such 2154 cases, overall performance will even be worse, because the XMLHttpRequest is 2155 tried first (but in vain). 2156 2157 <p>When JavaScript is disabled int the browser, the XMLHttpRequest will not be 2158 tried at all. The form will be fully usable, though, with identical 2159 functionality and behavior, just a bit slower and not so smooth. 2160 2161 2162 <p><hr> 2163 <h2><a name="minApp">A Minimal Complete Application</a></h2> 2164 2165 <p>The PicoLisp release includes in the "app/" directory a minimal, yet complete 2166 reference application. This application is typical, in the sense that it 2167 implements many of the techniques described in this document, and it can be 2168 easily modified and extended. In fact, we use it as templates for our own 2169 production application development. 2170 2171 <p>It is a kind of simplified ERP system, containing customers/suppliers, 2172 products (items), orders, and other data. The order input form performs live 2173 updates of customer and product selections, price, inventory and totals 2174 calculations, and generates on-the-fly PDF documents. Fine-grained access 2175 permissions are controlled via users, roles and permissions. It comes localized 2176 in six languages (English, Spanish, German, Norwegian, Russian and Japanese), 2177 with some initial data and two sample reports. 2178 2179 2180 <p><hr> 2181 <h3><a name="getStarted">Getting Started</a></h3> 2182 2183 <p>For a global installation (see <a href="ref.html#inst">Installation</a>), 2184 please create a symbolic link to the place where the program files are 2185 installed. This is necessary because the application needs read/write access to 2186 the current working directory (for the database and other runtime data). 2187 2188 <pre><code> 2189 $ ln -s /usr/share/picolisp/app 2190 </code></pre> 2191 2192 <p>As ever, you may start up the application in debugging mode 2193 2194 <pre><code> 2195 $ pil app/main.l -main -go + 2196 </code></pre> 2197 2198 <p>or in (non-debug) production mode 2199 2200 <pre><code> 2201 $ pil app/main.l -main -go -wait 2202 </code></pre> 2203 2204 <p>and go to '<code><a 2205 href="http://localhost:8080">http://localhost:8080</a></code>' with your 2206 browser. You can login as user "admin", with password "admin". The demo data 2207 contain several other users, but those are more restricted in their role 2208 permissions. 2209 2210 <p>Another possibility is to try the online version of this application at <a 2211 href="http://app.7fach.de">app.7fach.de</a>. 2212 2213 2214 <h4><a name="localization">Localization</a></h4> 2215 2216 <p>Before or after you logged in, you can select another language, and click on 2217 the "Change" button. This will effect all GUI components (though not text from 2218 the database), and also the numeric, date and telephone number formats. 2219 2220 2221 <h4><a name="navigation">Navigation</a></h4> 2222 2223 <p>The navigation menu on the left side shows two items "Home" and "logout", and 2224 three submenus "Data", "Report" and "System". 2225 2226 <p>Both "Home" and "logout" bring you back to the initial login form. Use 2227 "logout" if you want to switch to another user (say, for another set of 2228 permissions), and - more important - before you close your browser, to release 2229 possible locks and process resources on the server. 2230 2231 <p>The "Data" submenu gives access to application specific data entry and 2232 maintenance: Orders, product items, customers and suppliers. The "Report" 2233 submenu contains two simple inventory and sales reports. And the "System" 2234 submenu leads to role and user administration. 2235 2236 <p>You can open and close each submenu individually. Keeping more than one 2237 submenu open at a time lets you switch rapidly between different parts of the 2238 application. 2239 2240 <p>The currently active menu item is indicated by a highlighted list style (no 2241 matter whether you arrived at this page directly via the menu or by clicking on 2242 a link somewhere else). 2243 2244 2245 <h4><a name="choosing">Choosing Objects</a></h4> 2246 2247 <p>Each item in the "Data" or "System" submenu opens a search dialog for that 2248 class of entities. You can specify a search pattern, press the top right 2249 "Search" button (or just ENTER), and scroll through the list of results. 2250 2251 <p>While the "Role" and "User" entities present simple dialogs (searching just 2252 by name), other entities can be searched by a variety of criteria. In those 2253 cases, a "Reset" button clears the contents of the whole dialog. A new object 2254 can be created with bottom right "New" button. 2255 2256 <p>In any case, the first column will contain either a "@"-link (to jump to that 2257 object) or a "@"-button (to insert a reference to that object into the current 2258 form). 2259 2260 <p>By default, the search will list all database objects with an attribute value 2261 greater than or equal to the search criterion. The comparison is done 2262 arithmetically for numbers, and alphabetically (case sensitive!) for text. This 2263 means, if you type "Free" in the "City" field of the "Customer/Supplier" dialog, 2264 the value of "Freetown" will be matched. On the other hand, an entry of "free" 2265 or "town" will yield no hits. 2266 2267 <p>Some search fields, however, show a different behavior depending on the 2268 application: 2269 2270 <ul> 2271 <li>The names of persons, companies or products allow a tolerant search, 2272 matching either a slightly misspelled name ("Mühler" instead of "Miller") or a 2273 substring ("Oaks" will match "Seven Oaks Ltd."). 2274 2275 <li>The search field may specify an upper instead of a lower limit, resulting in 2276 a search for database objects with an attribute value less than or equal to the 2277 search criterion. This is useful, for example in the "Order" dialog, to list 2278 orders according to their number or date, by starting with the newest then and 2279 going backwards. 2280 2281 </ul> 2282 2283 <p>Using the bottom left scroll buttons, you can scroll through the result list 2284 without limit. Clicking on a link will bring up the corresponding object. Be 2285 careful here to select the right column: Some dialogs (those for "Item" and 2286 "Order") also provide links for related entities (e.g. "Supplier"). 2287 2288 2289 <h4><a name="editing">Editing</a></h4> 2290 2291 <p>A database object is usually displayed in its own individual form, which is 2292 determined by its entity class. 2293 2294 <p>The basic layout should be consistent for all classes: Below the heading 2295 (which is usually the same as the invoking menu item) is the object's identifier 2296 (name, number, etc.), and then a row with an "Edit" button on the left, and 2297 "Delete" button, a "Select" button and two navigation links on the right side. 2298 2299 <p>The form is brought up initially in read-only mode. This is necessary to 2300 prevent more than one user from modifying an object at the same time (and 2301 contrary to the previous PicoLisp Java frameworks, where this was not a problem 2302 because all changes were immediately reflected in the GUIs of other users). 2303 2304 <p>So if you want to modify an object, you have to gain exclusive access by 2305 clicking on the "Edit" button. The form will be enabled, and the "Edit" button 2306 changes to "Done". Should any other user already have reserved this object, you 2307 will see a message telling his name and process ID. 2308 2309 <p>An exception to this are objects that were just created with "New". They will 2310 automatically be reserved for you, and the "Edit" button will show up as "Done". 2311 2312 <p>The "Delete" button pops up an alert, asking for confirmation. If the object 2313 is indeed deleted, this button changes to "Restore" and allows to undelete the 2314 object. Note that objects are never completely deleted from the database as long 2315 as there are any references from other objects. When a "deleted" object is 2316 shown, its identifier appears in square brackets. 2317 2318 <p>The "Select" button (re-)displays the search dialog for this class of 2319 entities. The search criteria are preserved between invocations of each dialog, 2320 so that you can conveniently browse objects in this context. 2321 2322 <p>The navigation links, pointing left and right, serve a similar purpose. They 2323 let you step sequentially through all objects of this class, in the order of the 2324 identifier's index. 2325 2326 <p>Other buttons, depending on the entity, are usually arranged at the bottom of 2327 the form. The bottom rightmost one should always be another "Edit" / "Done" 2328 button. 2329 2330 <p>As we said in the chapter on <a href="#scrolling">Scrolling</a>, any button 2331 in the form will save changes to the underlying data model. As a special case, 2332 however, the "Done" button releases the object and reverts to "Edit". Besides 2333 this, the edit mode will also cease as soon as another object is displayed, be 2334 it by clicking on an object link (the pencil icon), the top right navigation 2335 links, or a link in a search dialog. 2336 2337 2338 <h4><a name="btnLinks">Buttons vs. Links</a></h4> 2339 2340 <p>The only way to interact with a HTTP-based application server is to click 2341 either on a HTML link, or on a submit button (see also <a 2342 href="#ctlFlow">Control Flow</a>). It is essential to understand the different 2343 effects of such a click on data entered or modified in the current form. 2344 2345 <ul> 2346 <li>A click on a link will leave or reload the page. Changes are discarded. 2347 <li>A click on a button will commit changes, and perform the associated action. 2348 </ul> 2349 2350 <p>For that reason the layout design should clearly differentiate between links 2351 and buttons. Image buttons are not a good idea when in other places images are 2352 used for links. The standard button components should be preferred; they are 2353 usually rendered by the browser in a non-ambiguous three-dimensional look and 2354 feel. 2355 2356 <p>Note that if JavaScript is enabled in the browser, changes will be 2357 automatically committed to the server. 2358 2359 <p>The enabled or disabled state of a button is an integral part of the 2360 application logic. It must be indicated to the user with appropriate styles. 2361 2362 2363 <p><hr> 2364 <h3><a name="dataModel">The Data Model</a></h3> 2365 2366 <p>The data model for this mini application consists of only six entity classes 2367 (see the E/R diagram at the beginning of "app/er.l"): 2368 2369 <ul> 2370 <li>The three main entities are <code>+CuSu</code> (Customer/Supplier), 2371 <code>+Item</code> (Product Item) and <code>+Ord</code> (Order). 2372 2373 <li>A <code>+Pos</code> object is a single position in an order. 2374 2375 <li><code>+Role</code> and <code>+User</code> objects are needed for 2376 authentication and authorization. 2377 2378 </ul> 2379 2380 <p>The classes <code>+Role</code> and <code>+User</code> are defined in 2381 "@lib/adm.l". A <code>+Role</code> has a name, a list of permissions, and a list 2382 of users assigned to this role. A <code>+User</code> has a name, a password and 2383 a role. 2384 2385 <p>In "app/er.l", the <code>+Role</code> class is extended to define an 2386 <code>url></code> method for it. Any object whose class has such a method is 2387 able to display itself in the GUI. In this case, the file "app/role.l" will be 2388 loaded - with the global variable <code>*ID</code> pointing to it - whenever an 2389 HTML link to this role object is activated. 2390 2391 <p>The <code>+User</code> class is also extended. In addition to the login name, 2392 a full name, telephone number and email address is declared. And, of course, the 2393 ubiquitous <code>url></code> method. 2394 2395 <p>The application logic is centered around orders. An order has a number, a 2396 date, a customer (an instance of <code>+CuSu</code>) and a list of positions 2397 (<code>+Pos</code> objects). The <code>sum></code> method calculates the 2398 total amount of this order. 2399 2400 <p>Each position has an <code>+Item</code> object, a price and a quantity. The 2401 price in the position overrides the default price from the item. 2402 2403 <p>Each item has a number, a description, a supplier (also an instance of 2404 <code>+CuSu</code>), an inventory count (the number of these items that were 2405 counted at the last inventory taking), and a price. The <code>cnt></code> 2406 method calculates the current stock of this item as the difference of the 2407 inventory and the sold item counts. 2408 2409 <p>The call to <code>dbs</code> at the end of "app/er.l" configures the physical 2410 database storage. Each of the supplied lists has a number in its CAR which 2411 determines the block size as (64 << N) of the corresponding database file. 2412 The CDR says that the instances of this class (if the element is a class symbol) 2413 or the tree nodes (if the element is a list of a class symbol and a property 2414 name) are to be placed into that file. This allows for some optimizations in the 2415 database layout. 2416 2417 2418 <p><hr> 2419 <h3><a name="usage">Usage</a></h3> 2420 2421 <p>When you are connected to the application (see <a href="#getStarted">Getting 2422 Started</a>) you might try to do some "real" work with it. Via the "Data" menu 2423 (see <a href="#navigation">Navigation</a>) you can create or modify customers, 2424 suppliers, items and orders, and produce simple overviews via the "Report" menu. 2425 2426 2427 <h4><a name="cuSu">Customer/Supplier</a></h4> 2428 2429 <p align=right>Source in "app/cusu.l" 2430 2431 <p>The Customer/Supplier search dialog (<code>choCuSu</code> in "app/gui.l") 2432 supports a lot of search criteria. These become necessary when the database 2433 contains a large number of customers, and can filter by zip, by phone number 2434 prefixes, and so on. 2435 2436 <p>In addition to the basic layout (see <a href="#editing">Editing</a>), the 2437 form is divided into four separate tabs. Splitting a form into several tabs 2438 helps to reduce traffic, with possibly better GUI response. In this case, four 2439 tabs are perhaps overkill, but ok for demonstration purposes, and they leave 2440 room for extensions. 2441 2442 <p>Be aware that when data were modified in one of the tabs, the "Done" button 2443 has to be pressed before another tab is clicked, because tabs are implemented as 2444 HTML links (see <a href="#btnLinks">Buttons vs. Links</a>). 2445 2446 <p>New customers or suppliers will automatically be assigned the next free 2447 number. You can enter another number, but an error will result if you try to use 2448 an existing number. The "Name" field is mandatory, you need to overwrite the 2449 "<Name>" clue. 2450 2451 <p>Phone and fax numbers in the "Contact" tab must be entered in the correct 2452 format, depending on the locale (see <a href="#telFields">Telephone 2453 Numbers</a>). 2454 2455 <p>The "Memo" tab contains a single text area. It is no problem to use it for 2456 large pieces of text, as it gets stored in a database blob internally. 2457 2458 2459 <h4><a name="item">Item</a></h4> 2460 2461 <p align=right>Source in "app/item.l" 2462 2463 <p>Items also have a unique number, and a mandatory "Description" field. 2464 2465 <p>To assign a supplier, click on the "+" button. The Customer/Supplier search 2466 dialog will appear, and you can pick the desired supplier with the "@" button in 2467 the first column. Alternatively, if you are sure to know the exact spelling of 2468 the supplier's name, you can also enter it directly into the text field. 2469 2470 <p>In the search dialog you may also click on a link, for example to inspect a 2471 possible supplier, and then return to the search dialog with the browser's back 2472 button. The "Edit" mode will then be lost, however, as another object has been 2473 visited (this is described in the last part of <a href="#editing">Editing</a>). 2474 2475 <p>You can enter an inventory count, the number of items currently in stock. The 2476 following field will automatically reflect the remaining pieces after some of 2477 these items were sold (i.e. referenced in order positions). It cannot be changed 2478 manually. 2479 2480 <p>The price should be entered with the decimal separator according to the 2481 current locale. It will be formatted with two places after the decimal 2482 separator. 2483 2484 <p>The "Memo" is for an arbitrary info text, like in <a 2485 href="#cuSu">Customer/Supplier</a> above, stored in a database blob. 2486 2487 <p>Finally, a JPEG picture can be stored in a blob for this item. Choose a file 2488 with the browser's file select control, and click on the "Install" button. The 2489 picture will appear at the bottom of the page, and the "Install" button changes 2490 to "Uninstall", allowing the picture's removal. 2491 2492 2493 <h4><a name="order">Order</a></h4> 2494 2495 <p align=right>Source in "app/ord.l" 2496 2497 <p>Oders are identified by number and date. 2498 2499 <p>The number must be unique. It is assigned when the order is created, and 2500 cannot be changed for compliance reasons. 2501 2502 <p>The date is initialized to "today" for a newly created order, but may be 2503 changed manually. The date format depends on the locale. It is YYYY-MM-DD (ISO) 2504 by default, DD.MM.YYYY in the German and YYYY/MM/DD in the Japanese locale. As 2505 described in <a href="#timeDateFields">Time & Date</a>, this field allows 2506 input shortcuts, e.g. just enter the day to get the full date in the current 2507 month. 2508 2509 <p>To assign a customer to this order, click on the "+" button. The 2510 Customer/Supplier search dialog will appear, and you can pick the desired 2511 customer with the "@" button in the first column (or enter the name directly 2512 into the text field), just as described above for <a href="#item">Item</a>s. 2513 2514 <p>Now enter order the positions: Choose an item with the "+" button. The 2515 "Price" field will be preset with the item's default price, you may change it 2516 manually. Then enter a quantity, and click a button (typically the "+" button to 2517 select the next item, or a scroll button go down in the chart). The form will be 2518 automatically recalculated to show the total prices for this position and the 2519 whole order. 2520 2521 <p>Instead of the "+" or scroll buttons, as recommended above, you could of 2522 course also press the "Done" button to commit changes. This is all right, but 2523 has the disadvantage that the button must be pressed a second time (now "Edit") 2524 if you want to continue with the entry of more positions. 2525 2526 <p>The "x" button at the right of each position deletes that position without 2527 further confirmation. It has to be used with care! 2528 2529 <p>The "^" button is a "bubble" button. It exchanges a row with the row above it. 2530 Therefore, it can be used to rearrange all items in a chart, by "bubbling" them 2531 to their desired positions. 2532 2533 <p>The "PDF-Print" button generates and displays a PDF document for this order. 2534 The browser should be configured to display downloaded PDF documents in an 2535 appropriate viewer. The source for the postscript generating method is in 2536 "app/lib.l". It produces one or several A4 sized pages, depending on the number 2537 of positions. 2538 2539 2540 <h4><a name="reports">Reports</a></h4> 2541 2542 <p align=right>Sources in "app/inventory.l and "app/sales.l" 2543 2544 <p>The two reports ("Inventory" and "Sales") come up with a few search fields 2545 and a "Show" button. 2546 2547 <p>If no search criteria are entered, the "Show" button will produce a listing 2548 of the relevant part of the whole database. This may take a long time and cause 2549 a heavy load on the browser if the database is large. 2550 2551 <p>So in the normal case, you will limit the domain by stating a range of item 2552 numbers, a description pattern, and/or a supplier for the inventory report, or a 2553 range of order dates and/or a customer for the sales report. If a value in a 2554 range specification is omitted, the range is considered open in that direction. 2555 2556 <p>At the end of each report appears a "CSV" link. It downloads a file with the 2557 TAB-separated values generated by this report. 2558 2559 </body> 2560 </html>