From d78aa1f5862b98760c23aadeea96720c2d93a60d Mon Sep 17 00:00:00 2001 From: David Botton Date: Fri, 10 May 2024 13:53:31 -0400 Subject: [PATCH] Updates to tutorial 9 --- LEARN.md | 2 +- tutorial/09-tutorial.lisp | 308 ++++++++++++++++++++------------------ tutorial/17-tutorial.lisp | 14 +- tutorial/README.md | 2 +- 4 files changed, 168 insertions(+), 158 deletions(-) diff --git a/LEARN.md b/LEARN.md index 1ade438..51b8b88 100644 --- a/LEARN.md +++ b/LEARN.md @@ -76,7 +76,7 @@ CLOG "The Framework" (Code Tutorials) - [04-tutorial.lisp](tutorial/04-tutorial.lisp) - The event target, reusing event handlers - [05-tutorial.lisp](tutorial/05-tutorial.lisp) - Using connection-data-item - [06-tutorial.lisp](tutorial/06-tutorial.lisp) - Tasking and events -- [07-tutorial.lisp](tutorial/07-tutorial.lisp) - My first CLOG video game (and handling disconnects) +- [07-tutorial.lisp](tutorial/07-tutorial.lisp) - My first CLOG video game - [08-tutorial.lisp](tutorial/08-tutorial.lisp) - Mice Love Containers - [09-tutorial.lisp](tutorial/09-tutorial.lisp) - Tabs, panels, and forms - [10-tutorial.lisp](tutorial/10-tutorial.lisp) - Canvas diff --git a/tutorial/09-tutorial.lisp b/tutorial/09-tutorial.lisp index 3f4d1f6..619d885 100644 --- a/tutorial/09-tutorial.lisp +++ b/tutorial/09-tutorial.lisp @@ -4,162 +4,172 @@ (in-package :clog-tut-9) +;; In this tutorial we demonstrate using forms and form controls +;; this is not traditonal HTML use, as we never leave the original +;; page. It is an interactive live application. + (defun on-new-window (body) (setf (title (html-document body)) "Tutorial 09") - ;; When doing extensive setup of a page using connection cache - ;; reduces rountrip traffic and speeds setup. - (with-connection-cache (body) - (let* (last-tab - ;; Note: Since the there is no need to use the tmp objects - ;; we reuse the same symbol name (tmp) even though the - ;; compiler can mark those for garbage collection early - ;; this not an issue as the element is created already - ;; in the browser window. - ;; - ;; See tutorial 33 for a far more elegant approach - ;; that uses with-clog-create for this type of code - ;; based layout. - ;; - ;; Create tabs and panels - (t1 (create-button body :content "Tab1")) - (t2 (create-button body :content "Tab2")) - (t3 (create-button body :content "Tab3")) - (tmp (create-br body)) - (p1 (create-div body)) - (p2 (create-div body)) - (p3 (create-div body :content "Panel3 - Type here")) - ;; Create form for panel 1 - (f1 (create-form p1)) - (fe1 (create-form-element f1 :text - :label (create-label f1 :content "Fill in blank:"))) - (tmp (create-br f1)) - (fe2 (create-form-element f1 :color :value "#ffffff" - :label (create-label f1 :content "Pick a color:"))) - (tmp (create-br f1)) - (tmp (create-form-element f1 :submit :value "OK")) - (tmp (create-form-element f1 :reset :value "Start Again")) - ;; Create for for panel 2 - (f2 (create-form p2)) - (fs2 (create-fieldset f2 :legend "Stuff")) - (tmp (create-label fs2 :content "Please type here:")) - (ta1 (create-text-area fs2 :columns 60 :rows 8 :label tmp)) - (tmp (create-br fs2)) - (rd1 (create-form-element fs2 :radio :name "rd")) - (tmp (create-label fs2 :content "To Be" :label-for rd1)) - (rd2 (create-form-element fs2 :radio :name "rd")) - (tmp (create-label fs2 :content "No to Be" :label-for rd2)) - (tmp (create-br fs2)) - (ck1 (create-form-element fs2 :checkbox :name "ck")) - (tmp (create-label fs2 :content "Here" :label-for ck1)) - (ck2 (create-form-element fs2 :checkbox :name "ck")) - (tmp (create-label fs2 :content "There" :label-for ck2)) - (tmp (create-br fs2)) - (sl1 (create-select fs2 :label (create-label fs2 :content "Pick one:"))) - (sl2 (create-select fs2 :label (create-label fs2 :content "Pick one:"))) - (sl3 (create-select fs2 :multiple t - :label (create-label fs2 :content "Pick some:"))) - (o1 (create-option sl3 :content "one")) - (o2 (create-option sl3 :content "two")) - (o3 (create-option sl3 :content "three")) - (og1 (create-optgroup sl3 :content "These are a group")) - (o4 (create-option og1 :content "four")) - (o5 (create-option og1 :content "five")) - (tmp (create-form-element f2 :submit :value "OK")) - (tmp (create-form-element f2 :reset :value "Start Again"))) - (declare (ignore tmp)) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ;; Create tabs and panels - a simple file card interface + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + (let* ((tab1 (create-button body :content "Tab1")) + (tab2 (create-button body :content "Tab2")) + (tab3 (create-button body :content "Tab3")) + (tmp (create-br body)) + (panel1 (create-div body)) + (panel2 (create-div body)) + ; styling can be done here also + (panel3 (create-div body :content "Panel3 - Type here" + :style "width:100%;height:400px;border:thin solid black")) + (tab-to-panel (list + (list tab1 panel1) + (list tab2 panel2) + (list tab3 panel3)))) ; an a-list of tabs to panels + (declare (ignore tmp)) ; ignore warnings tmp never used ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - ;; Panel 1 contents + ;; Style the panels - you can program your styles ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - (setf (place-holder fe1) "type here..") - (setf (requiredp fe1) t) - (setf (size fe1) 60) - (make-data-list fe1 '("Cool Title" - "Not So Cool Title" - "Why Not, Another Title")) - (make-data-list fe2 '("#ffffff" - "#ff0000" - "#00ff00" - "#0000ff" - "#ff00ff")) - (set-on-submit f1 - (lambda (obj) - (declare (ignore obj)) - (setf (title (html-document body)) (value fe1)) - (setf (background-color p1) (value fe2)) - (setf (hiddenp f1) t) - (create-span p1 :content - "
Your form has been submitted"))) - (setf (width p1) "100%") - (setf (width p2) "100%") - (setf (width p3) "100%") - (setf (height p1) 400) - (setf (height p2) 400) - (setf (height p3) 400) - (set-border p1 :thin :solid :black) - (set-border p2 :thin :solid :black) - (set-border p3 :thin :solid :black) - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - ;; Panel 2 contents - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - (setf (vertical-align ta1) :top) - (disable-resize ta1) - (setf (vertical-align sl1) :top) - (setf (vertical-align sl2) :top) - (setf (vertical-align sl3) :top) - (setf (size sl1) 3) - (add-select-options sl1 '("one" - "two" - "three" - "four" - "five")) - (add-select-options sl2 '("one" - "two" - "three" - "four" - "five")) - (set-on-change sl3 (lambda (obj) - (declare (ignore obj)) - (when (selectedp o5) - (alert (window body) "Selected 5")))) - (set-on-submit f2 - (lambda (obj) - (declare (ignore obj)) - (setf (hiddenp f2) t) - (create-span p2 :content - (format nil "
Your form has been submitted: -
~A
1 - ~A
2 - ~A
3 - ~A" - (value ta1) - (value sl1) - (value sl2) - (selectedp o2))))) - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - ;; Panel 3 contents - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - (setf (editablep p3) t) + ; can set any value with width and height, as a number (ie pixels). + ; or any valid number + unit as a string. They both return as a numbers + ; the number of pixels. + (setf (width panel1) "100%") + (setf (height panel1) (unit :px 400)) ; work with numbers and set unit + ; you can set many values at one with set-geometry, it's default unit + ; is a pixel + (set-geometry panel2 :width "100%" :height 400) + ; CLOG contains programtic ways to handle most styles + (set-border panel1 :thin :solid :black) + ; You can also set styles with a list + (set-styles panel2 '(("border" "thin solid black"))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Tab functionality ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - (flet ((select-tab (obj) - (setf (hiddenp p1) t) - (setf (hiddenp p2) t) - (setf (hiddenp p3) t) - (setf (background-color t1) :lightgrey) - (setf (background-color t2) :lightgrey) - (setf (background-color t3) :lightgrey) - (setf (background-color last-tab) :lightblue) - (setf (hiddenp obj) nil) - (focus obj))) - (setf last-tab t1) - (select-tab p1) - (set-on-click t1 (lambda (obj) - (setf last-tab obj) - (select-tab p1))) - (set-on-click t2 (lambda (obj) - (setf last-tab obj) - (select-tab p2))) - (set-on-click t3 (lambda (obj) - (setf last-tab obj) - (select-tab p3))))))) + (flet ((select-tab (new-tab) ; can be used as an event handler + (mapcar (lambda (l) + (setf (background-color (first l)) :lightgrey) + (setf (hiddenp (second l)) t)) + tab-to-panel) + (setf (hiddenp (second (assoc new-tab tab-to-panel))) nil) ; not hidden + (setf (background-color new-tab) :lightblue) + (focus new-tab))) + (set-on-click tab1 #'select-tab) ; You can not use 'select-tab the symbol + (set-on-click tab2 #'select-tab) ; value as the symbol is not global. You + (set-on-click tab3 #'select-tab) ; must set the actual function value #' + (select-tab tab1)) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ;; Panel 1 contents + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + (let* ((form (create-form panel1)) + (element1 (create-form-element form :text ; input text box + :label (create-label form ; give it label + :content "Fill in blank:"))) + (tmp (create-br form)) + (element2 (create-form-element form :color ; color picker + :value "#ffffff" + :label (create-label form :content "Pick a color:")))) + (declare (ignore tmp)) + (create-br form) + (create-form-element form :submit :value "OK") + (create-form-element form :reset :value "Start Again") + (setf (place-holder element1) "type here..") + (setf (requiredp element1) t) + (setf (size element1) 60) + (make-data-list element1 '("Cool Title" + "Not So Cool Title" + "Why Not, Another Title")) ; completion list + (make-data-list element2 '("#ffffff" + "#ff0000" + "#00ff00" + "#0000ff" + "#ff00ff")) ; default color palette + (set-on-submit form + (lambda (obj) + (declare (ignore obj)) + (setf (title (html-document body)) + (value element1)) ; change page title + (setf (background-color panel1) + (value element2)) ; change panel background + (setf (hiddenp form) t) ; hide form and all its elements + ; To destroy the contents of tbe panel1 and so also the + ; form, you could also do (setf (text panel1) "") + (create-span panel1 :content + "
Your form has been submitted")))) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ;; Panel 2 contents + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + (let* ((form (create-form panel2)) + (fset (create-fieldset form :legend "Stuff")) + (lbl (create-label fset :content "Please type here:")) + (text-area (create-text-area fset :columns 60 :rows 8 :label lbl)) + (tmp1 (create-br fset)) + (radio1 (create-form-element fset :radio :name "rd")) + (tmp2 (create-label fset :content "To Be" :label-for radio1)) + (radio2 (create-form-element fset :radio :name "rd")) + (tmp3 (create-label fset :content "No to Be" :label-for radio2)) + (tmp4 (create-br fset)) + (check1 (create-form-element fset :checkbox :name "ck")) + (tmp5 (create-label fset :content "Here" :label-for check1)) + (check2 (create-form-element fset :checkbox :name "ck")) + (tmp6 (create-label fset :content "There" :label-for check2)) + (tmp7 (create-br fset)) + (select1 (create-select fset :label (create-label fset :content "Pick one:"))) + (select2 (create-select fset :label (create-label fset :content "Pick one:"))) + (select3 (create-select fset :multiple t + :label (create-label fset :content "Pick some:")))) + (declare (ignore tmp1 tmp2 tmp3 tmp4 tmp5 tmp6 tmp7)) + ;; virticle aling controls with their labels + (setf (vertical-align text-area) :top) + (setf (vertical-align select1) :top) + (setf (vertical-align select2) :top) + (setf (vertical-align select3) :top) + ;; add options to select1 as a list + (setf (size select1) 3) ; turn select1 into a listbox size > 1 + (add-select-options select1 '("one" + "two" + "three" + "four" + "five")) + ;; add options to select1 as a list + ;; size defaults to 1 - so a dropdown list + (add-select-options select2 '("one" + "two" + "three" + "four" + "five")) + + ;; add options to select3 programticly + (create-option select3 :content "one") + (create-option select3 :content "two") + (create-option select3 :content "three") + (let* ((group (create-optgroup select3 :content "These are a group")) + (op4 (create-option group :content "four")) + (op5 (create-option group :content "five"))) + (declare (ignore op4)) + (set-on-change select3 (lambda (obj) ; change event on a control + (declare (ignore obj)) + (when (selectedp op5) + (alert (window body) "Selected 5"))))) + ;; settings for text-area + (disable-resize text-area) + ;; add form buttons + (create-form-element form :submit :value "OK") + (create-form-element form :reset :value "Start Again") + (set-on-submit form + (lambda (obj) + (declare (ignore obj)) + (setf (hiddenp form) t) + (create-span panel2 :content + (format nil "
Your form has been submitted: +
~A
1 - ~A
2 - ~A
3 - ~A" + (value text-area) + (value select1) + (value select2) + (value select3)))))) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ;; Panel 3 contents + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + (setf (editablep panel3) t))) ; turn panel 3 into an editable area (defun start-tutorial () "Start turtorial." diff --git a/tutorial/17-tutorial.lisp b/tutorial/17-tutorial.lisp index 996f75f..9ca13aa 100644 --- a/tutorial/17-tutorial.lisp +++ b/tutorial/17-tutorial.lisp @@ -7,7 +7,7 @@ ;;; In this tutorial we will use a CSS only alternative to bootstrap - ;;; https://www.w3schools.com/w3css/default.asp ;;; -;;; It is also a demonstration of how various ways to use HTML Forms +;;; It is also a demonstration of various ways to use HTML Forms (defun on-index (body) ;; Load css files (load-css (html-document body) "https://www.w3schools.com/w3css/4/w3.css") @@ -29,7 +29,7 @@ (create-label form1 :content "Enter name:"))) (fsubmit (create-form-element form1 :submit)) (tmp (create-br fcontainer)) - (tmp (create-hr data-area)) + (tmp (create-hr data-area)) ;; This is a traditional "get" form that will submit data ;; to a server. (fcontainer (create-div data-area :class "w3-container")) @@ -40,7 +40,7 @@ (create-label form2 :content "Enter name:"))) (fsubmit (create-form-element form2 :submit)) (tmp (create-br fcontainer)) - (tmp (create-hr data-area)) + (tmp (create-hr data-area)) ;; This is a file upload form that will submit data and files ;; to a server. (fcontainer (create-div data-area :class "w3-container")) @@ -52,7 +52,7 @@ (finput (create-form-element form4 :file :name "filename")) (fsubmit (create-form-element form4 :submit)) (tmp (create-br fcontainer)) - (tmp (create-hr data-area)) + (tmp (create-hr data-area)) ;; This is a CLOG style form, instead of submitting data ;; to another page it is dealt with in place. (fcontainer (create-div data-area :class "w3-container")) @@ -63,9 +63,9 @@ (create-label form3 :content "Enter name:"))) (fsubmit3 (create-form-element form3 :submit)) (tmp (create-br fcontainer)) - (tmp (create-hr data-area)) - (footer (create-section body :footer :class "w3-container w3-theme")) - (tmp (create-section footer :p :content "(c) All's well that ends well"))) + (tmp (create-hr data-area)) + (footer (create-section body :footer :class "w3-container w3-theme")) + (tmp (create-section footer :p :content "(c) All's well that ends well"))) (declare (ignore tmp) (ignore finput) (ignore fsubmit)) (set-on-click fsubmit3 diff --git a/tutorial/README.md b/tutorial/README.md index 63b4ed2..f68c0a7 100644 --- a/tutorial/README.md +++ b/tutorial/README.md @@ -32,7 +32,7 @@ Tutorial Summary - 04-tutorial.lisp - The event target, reusing event handlers - 05-tutorial.lisp - Using connection-data-item - 06-tutorial.lisp - Tasking and events -- 07-tutorial.lisp - My first CLOG video game (and handling disconnects) +- 07-tutorial.lisp - My first CLOG video game - 08-tutorial.lisp - Mice Love Containers - 09-tutorial.lisp - Tabs, pannels and forms - 10-tutorial.lisp - Canvas