! Redesign of input-fields.

+ Split input-fields into two structures:
  + surflets/my-input-fields allows you to create your own input-fields.
    (complete with structure surflets/input-field-value)
  + surflets/surflet-input-fields are the proposals for input-fields
    from SUrflets. They support annotated input-fields where
    appropriate (select, radio, checkbox, hidden) and changing of attributes,
    e.g. default values. See test.scm for examples.
  The interface of the structure SURFLETS has only changed slightly
  concerning the input fields
  (make-higher-input-field --> make-multi-input-field should be the
  main change)
+ Adapt examples to new input-field interface
+ Note new structures in documentation.
This commit is contained in:
interp 2003-04-16 12:30:57 +00:00
parent 6d64530779
commit aa6e6aabfc
7 changed files with 723 additions and 288 deletions

View File

@ -5,248 +5,140 @@
;;; input-fields
;;; defines input-fields for surflets
;;; Globals
(define *input-field-trigger* `*input-field*)
(define generate-input-field-name generate-unique-name)
;; GET-BINDINGS?: Transformer will get all bindings of request, not
;; only the one concerning the input-field.
(define-record-type input-field :input-field
(real-make-input-field name transformer html-tree get-bindings?)
;;; Data structure for real-input-field
;; MULTI?: Transformer will get all bindings of request, not only the
;; one concerning the input-field.
(define-record-type real-input-field :real-input-field
(make-real-input-field name type transformer
attributes html-tree-maker
html-tree multi?)
real-input-field?
(name input-field-name)
(transformer input-field-transformer)
(attributes input-field-attributes)
(html-tree input-field-html-tree)
(get-bindings? input-field-get-bindings?))
(name real-input-field-name)
(type real-input-field-type)
(transformer real-input-field-transformer)
(attributes real-input-field-attributes set-real-input-field-attributes!)
(html-tree-maker real-input-field-html-tree-maker)
(html-tree real-input-field-html-tree set-real-input-field-html-tree!)
(multi? real-input-field-multi?))
(define-record-discloser :input-field
(define-record-discloser :real-input-field
(lambda (input-field)
(list 'input-field
(input-field-name input-field))))
(list 'real-input-field
(real-input-field-type input-field)
(real-input-field-name input-field))))
(define-syntax with-real-input-field
(lambda (expr rename compare)
(let ((%if (rename 'if))
(%let (rename 'let))
(%cadr (rename 'cadr))
(%input-field? (rename 'input-field?))
(%error (rename 'error))
(input-field (cadr expr))
(body (cddr expr)))
`(,%if (,%input-field? ,input-field)
(,%let ((real-input-field (,%cadr ,input-field)))
,@body)
(,%error "Invalid argument. Function wants an input-field."
,input-field)))))
;;; Fake input-field record. This is necessary, as the trigger in SXML
;;; may only be symbols, not arbitrary values. Thus, our input-fields
;;; must be preceeded by a trigger symbol to get recognized by the
;;; SXML transforming routines like sxml->html.
;; Constructors: make-input-field, make-multi-input-field
;; Predicates: input-field?
;; Selectors: input-field-name, input-field-type,
;; input-field-transformer, input-field-attributes,
;; input-field-html-tree-maker, input-field-html-tree,
;; input-field-multi?
;; Mutators: set-input-field-attributes!, touch-input-field!
;;; Constructors for input-field / multi-input-field
(define (make-input-field name type transformer attributes
html-tree-maker)
(make-sxml-input-field
(make-real-input-field name type transformer
attributes html-tree-maker #f #f)))
(define (make-multi-input-field name type transformer attributes
html-tree-maker)
(make-sxml-input-field
(make-real-input-field name type transformer
attributes html-tree-maker #f #t)))
(define (make-sxml-input-field real-input-field)
(list *input-field-trigger* real-input-field))
;; Have to do a trick to get around with SSAX: input-field is a list
;; whose first element is *input-field-trigger* and the last (next) one
;; is a real input-field.
(define (input-field? input-field)
(and (pair? input-field)
(eq? *input-field-trigger* (car input-field))
(real-input-field? (cadr input-field))))
(define generate-input-field-name generate-unique-name)
(define identity (lambda (a) a))
(define (make-input-field-selector selector)
(lambda (input-field)
(with-real-input-field input-field
(selector real-input-field))))
;; See note at input-field? for reasons for the list.
(define (make-input-field name transformer html-tree)
(list *input-field-trigger*
(real-make-input-field name transformer html-tree #f)))
(define (make-input-field-setter setter . maybe-reset?)
(let ((reset? (:optional maybe-reset? #f)))
(lambda (input-field value)
(with-real-input-field input-field
(if reset?
(set-real-input-field-html-tree! real-input-field #f))
(setter real-input-field value)))))
(define (make-higher-input-field transformer html-tree)
(list *input-field-trigger*
(real-make-input-field #f transformer html-tree #t)))
(define input-field-name (make-input-field-selector real-input-field-name))
(define input-field-type (make-input-field-selector real-input-field-type))
(define input-field-transformer
(make-input-field-selector real-input-field-transformer))
(define input-field-attributes
(make-input-field-selector real-input-field-attributes))
(define input-field-html-tree-maker
(make-input-field-selector real-input-field-html-tree-maker))
(define (input-field-html-tree input-field)
(with-real-input-field input-field
(cond
((real-input-field-html-tree real-input-field)
=> identity)
(else
(let ((html-tree ((real-input-field-html-tree-maker real-input-field)
input-field)))
(set-real-input-field-html-tree! real-input-field html-tree)
html-tree)))))
(define (make-text-input-field . maybe-further-attributes)
(let ((name (generate-input-field-name "text")))
(optionals maybe-further-attributes
((default-text string?)
(attributes sxml-attribute?))
(make-input-field name
identity
`(input (@ (type "text")
(name ,name)
,(and default-text `(value ,default-text))
;; this will insert a list, but
;; XML->HTML doesn't care about it
,(and attributes (cdr attributes))
))))))
(define input-field-multi?
(make-input-field-selector real-input-field-multi?))
(define make-number-input-field
(let ((number-input-field-transformer
(lambda (string)
(or (string->number string)
(error "wrong type")))
))
(lambda maybe-further-attributes
(let ((name (generate-input-field-name "number")))
(optionals maybe-further-attributes
((default (lambda (a) (or (number? a)
(string-or-symbol? a))))
(attributes sxml-attribute?))
(make-input-field
name
number-input-field-transformer
`(input (@ (type "text")
(name ,name)
,(and default `(value ,default))
,(and attributes (cdr attributes))))))))))
(define set-input-field-attributes! (make-input-field-setter set-real-input-field-attributes! #t))
;; not exported:
(define set-input-field-html-tree! (make-input-field-setter set-real-input-field-html-tree!))
(define (make-password-input-field . maybe-further-attributes)
(let ((name (generate-input-field-name "password")))
(optionals maybe-further-attributes
((attributes sxml-attribute?))
(make-input-field
name
identity
`(input (@ (type "password")
(name ,name)
,(and attributes (cdr attributes))))))))
(define (make-textarea-input-field . maybe-further-attributes)
(let ((name (generate-input-field-name "textarea")))
(optionals maybe-further-attributes
((default-text string?)
(attributes sxml-attribute?))
(make-input-field
name
identity
`(textarea (@ (type "textarea")
(name ,name)
,(and attributes (cdr attributes)))
,(and default-text))))))
;(make-select-input-fields '("this" "that" "those") '(@ ((id "sushi"))))
;(make-select-input-fields '("this" ("that" '(@ (selected))) "those"))
;; dropdown: (size 1)
;; multiple choice: (multiple)
;; preselected option: (selected)
;; changed return value: (value new-value)
;; returns a select input field with several options
(define make-select-input-field
(let ((make-multiple-transformer
(lambda (name)
(lambda (bindings)
(map cdr
(filter (lambda (binding)
(equal? (car binding) name))
bindings))))))
(lambda (options . maybe-further-attributes)
(optionals maybe-further-attributes
((multiple? boolean?)
(attributes sxml-attribute?))
(let* ((name (generate-input-field-name "select"))
(sxml-options
(map (lambda (option)
(cond
((string-or-symbol? option)
(list 'option option))
((list? option)
(cond
((null? (cdr option))
`(option ,option))
((sxml-attribute? (cdr option)) ; w/attribs?
`(option ,(cdr option) ,(car option)))
(else
(error "not an attribute" (cdr option)))))
(else
(error "not an option" option))))
options))
(sxml `(select (@ ((name ,name)
,(if multiple? '(multiple) '())
,(and attributes (cdr attributes))))
#\newline
,sxml-options)))
(if multiple?
(make-higher-input-field (make-multiple-transformer name) sxml)
(make-input-field name identity sxml)))))))
;; returns a *list* of radio buttons
(define (make-radio-input-fields values . maybe-further-attributes)
(let ((name (generate-input-field-name "radio")))
(optionals maybe-further-attributes
((attributes sxml-attribute?))
(map (lambda (value)
(let ((value-value (if (pair? value) (car value) value))
(value-attributes (if (pair? value)
(if (sxml-attribute? (cdr value))
(cddr value)
(error "not an attribute" cdr value))
#f)))
(make-input-field
name
(lambda (select)
select)
`(input (@ ((type "radio")
(name ,name)
(value ,value-value)
,(and value-attributes)
,(and attributes (cdr attributes))))))))
values))))
;; returns a checkbox input field
(define (make-checkbox-input-field . maybe-further-attributes)
(let* ((name (generate-input-field-name "checkbox")))
(optionals maybe-further-attributes
((checked? boolean?)
(value (lambda (a) (or (string? a)
(number? a)
(symbol? a))))
(attributes sxml-attribute?))
(make-input-field
name
(lambda (value)
(or (string=? value "on")
value))
`(input (@ ((type "checkbox")
(name ,name)
,(if value `(value ,value) '())
,(if checked? '(checked) '())
,(and attributes (cdr attributes)))))))))
(define (make-hidden-input-field value . maybe-further-attributes)
(let ((name (generate-input-field-name "hidden")))
(optionals maybe-further-attributes
((attributes sxml-attribute?))
(make-input-field name
identity
`(input (@ (type "hidden")
(name ,name)
(value ,value)
,(and attributes (cdr attributes))))))))
(define (make-button type name button-caption attributes)
(make-input-field name
identity
`(input (@ (type ,type)
(name ,name)
,(and button-caption `(value ,button-caption))
,(and attributes (cdr attributes))))))
(define (string-or-symbol? a)
(or (string? a)
(symbol? a)))
(define (make-submit-button . maybe-further-attributes)
(optionals maybe-further-attributes
((button-caption string-or-symbol?)
(attributes sxml-attribute?))
(make-button "submit" (generate-input-field-name "submit")
button-caption attributes)))
(define (make-reset-button . maybe-further-attributes)
(optionals maybe-further-attributes
((button-caption string-or-symbol?)
(attributes sxml-attribute?))
(make-button "reset" (generate-input-field-name "reset")
button-caption attributes)))
(define (make-image-button image-source . maybe-further-attributes)
(optionals maybe-further-attributes
((attributes sxml-attribute?))
(make-button "image" (generate-input-field-name "imgbtn")
#f `(@ (src ,image-source)
,@(if attributes (cdr attributes) '())))))
;; A touched input-field's html-tree will be recalculated if
;; neccessary.
(define (touch-input-field! input-field)
(set-input-field-html-tree! input-field #f))
;; <input-field>: '(input-field . <real-input-field>)
;; <real-input-field>: #{Input-field "name"}
;; <real-input-field>: #{Real-input-field "name"}
(define (raw-input-field-value input-field bindings)
(let ((input-field (cadr input-field)))
(let ((real-input-field (cadr input-field)))
(cond
((input-field-get-bindings? input-field)
((input-field-transformer input-field) bindings))
((real-input-field-binding input-field bindings) =>
((real-input-field-multi? real-input-field)
((real-input-field-transformer real-input-field) bindings))
((real-input-field-binding real-input-field bindings) =>
(lambda (binding)
((input-field-transformer input-field) (cdr binding))))
((real-input-field-transformer real-input-field) (cdr binding))))
(else
(error "no such input-field" input-field bindings)))))
@ -263,12 +155,15 @@
(let ((default (:optional maybe-default #f)))
(with-fatal-error-handler
(lambda (condition more)
; (format #t "hit error condition: ~s~%" condition)
default)
(raw-input-field-value input-field bindings))))
(define (real-input-field-binding input-field bindings)
(assoc (input-field-name input-field) bindings))
(assoc (real-input-field-name input-field) bindings))
(define (input-field-binding input-field bindings)
(real-input-field-binding (cadr input-field) bindings))
;;EOF

View File

@ -64,6 +64,7 @@
sxml->string
sxml->string/internal
sxml-attribute?
sxml-attribute-attributes
default-rule
text-rule
attribute-rule))
@ -75,6 +76,7 @@
surflet-form-rule
default-rules
plain-html-rule
nbsp-rule
url-rule))
;; Use for advanced users: make your own conversion rules.
@ -100,8 +102,8 @@
set-session-data!))
;; Use for advanced users: access to your sessions and continuations
;; and continuations (currently you get access to all sessions; this
;; should and will be restricted in the future)
;; (currently you get access to all sessions; this should and will be
;; restricted in the future)
(define-interface surflets/my-sessions-interface
(compound-interface
surflets/ids-interface
@ -274,41 +276,82 @@
(export typed-optionals
(optionals :syntax)))
;; Input-fields as Scheme objects
(define-interface surflets/input-fields-interface
(export generate-input-field-name
make-input-field
make-higher-input-field
make-text-input-field
make-hidden-input-field
make-password-input-field
make-number-input-field
make-textarea-input-field
make-select-input-field
make-checkbox-input-field
make-radio-input-fields
make-submit-button
make-reset-button
make-image-button
input-field-value
;; Input-fields as Scheme-Objects
(define-interface surflets/input-field-value-interface
(export input-field?
raw-input-field-value
input-field-binding
input-field?))
input-field-value
input-field-binding))
;;; This is for surflets/surflet-sxml only:
(define-interface surflets/input-fields/internal-interface
(export *input-field-trigger*
input-field-html-tree))
;; For advanced users: creating your own input-fields
(define-interface surflets/my-input-fields-interface
(compound-interface
surflets/input-field-value-interface
(export *input-field-trigger*
generate-input-field-name
make-input-field
make-multi-input-field
input-field-name
input-field-type
input-field-transformer
input-field-attributes
input-field-html-tree-maker
input-field-html-tree
input-field-multi?
set-input-field-attributes!
touch-input-field!)))
(define-interface surflets/surflet-input-fields-interface
(compound-interface
surflets/input-field-value-interface
(export make-text-input-field
set-text-input-field-value!
make-number-input-field
set-number-input-field-value!
make-hidden-input-field
set-hidden-input-field-value!
make-password-input-field
set-password-input-field-value!
make-textarea-input-field
set-textarea-input-field-value!
make-select-input-field
make-annotated-select-input-field
make-simple-sel-if-option
make-annotated-sel-if-option
sel-if-option?
select-sel-if-option!
unselect-sel-if-option!
set-sel-if-option-selected?!
make-radio-input-field-group
make-annotated-radio-input-field-group
make-radio-input-fields
check-radio-input-field!
uncheck-radio-input-field!
set-radio-input-field-checked?!
make-checkbox-input-field
make-annotated-checkbox-input-field
check-checkbox-input-field!
uncheck-checkbox-input-field!
set-checkbox-input-field-checked?!
make-submit-button
make-reset-button
make-image-button)))
;; Some utilities
(define-interface surflets/utilities-interface
(export form-query-list
rev-append
generate-unique-number
generate-unique-name))
generate-unique-name
identity))
;; Intelligent Addresses
(define-interface surflets/addresses-interface
@ -358,7 +401,7 @@
; surflets/sxml-interface
; surflets/surflet-sxml-interface
surflets/send-html-interface
surflets/input-fields-interface
surflets/surflet-input-fields-interface
surflets/addresses-interface
surflets/returned-via-interface
surflets/bindings-interface
@ -412,7 +455,7 @@
(define-structure surflets surflets-interface
(open surflets/session-data
surflets/send-html ;send-html/suspend...
surflets/input-fields
surflets/surflet-input-fields
surflets/addresses ;annotated-address...
surflets/returned-via
surflets/bindings))
@ -460,6 +503,7 @@
define-record-types
let-opt
surflets
surflets/surflet-input-fields
(subset srfi-1 (zip filter find make-list))
handle-fatal-error
)
@ -510,27 +554,41 @@
;; Input fields as Scheme objects
(define-structures
((surflets/input-fields surflets/input-fields-interface)
(surflets/input-fields/internal
surflets/input-fields/internal-interface))
(open scheme
srfi-23 ;error
(subset srfi-1 (filter))
(define-structures
((surflets/input-field-value surflets/input-field-value-interface)
(surflets/my-input-fields surflets/my-input-fields-interface))
(open scheme-with-scsh ;error, format
(subset let-opt (:optional))
handle-fatal-error
define-record-types
(subset typed-optionals (optionals))
surflets/sxml
surflets/utilities ;rev-append,generate-unique-name
surflets/utilities
)
(files input-fields))
(define-structure surlfets/input-fields surflets/my-input-fields)
(define-structure surflets/surflet-input-fields
surflets/surflet-input-fields-interface
(open scheme-with-scsh ;error, format
;; avoid name collision for member
(modify srfi-1 (rename (member member/srfi-1)))
define-record-types
(subset let-opt (:optional))
(subset typed-optionals (optionals))
surflets/my-input-fields
surflets/utilities ;generate-unique-number
surflets/sxml
tables ;make-integer-table
)
(files surflet-input-fields))
;; Extensions to SXML for surflets
(define-structure surflets/surflet-sxml surflets/surflet-sxml-interface
(open scheme-with-scsh ;error,receive
surflets/input-fields/internal
(subset surflets/my-input-fields
(*input-field-trigger* input-field-html-tree))
surflets/sxml
typed-optionals
(subset sxml-tree-trans (pre-post-order)))
@ -578,7 +636,7 @@
(define-structure surflets/returned-via surflets/returned-via-interface
(open scheme
surflets/input-fields
surflets/input-field-value
surflets/addresses
(subset uri (unescape-uri)))
(files returned-via))

View File

@ -0,0 +1,472 @@
;;; SUrflets' input fields
;;; Copyright 2002, 2003 Andreas Bernauer
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Functions to create simple input fields
;; The interface for input-fields does not prescribe what the type of
;; attributes has to be. We choose a record here.
(define-record-type input-field-attributes :input-field-attributes
(make-input-field-attributes default others)
input-field-attributes?
(default input-field-attributes-default set-input-field-attributes-default!)
(others input-field-attributes-others set-input-field-attributes-others!))
;; A simple input-field is a prototype for other input-fields.
;; REPORTED-TYPE is the type of the input-field in HTML, TYPE the
;; internal referenced type and TRANSFORMER the function that
;; translates the HTTP-string of the request into a scheme value.
(define (simple-input-field-maker reported-type type default-pred transformer)
(lambda maybe-further-attributes
(let ((name (generate-input-field-name type)))
(optionals maybe-further-attributes
((default default-pred)
(attributes sxml-attribute?))
(make-input-field name type
transformer
(make-input-field-attributes
(and default `(value ,default))
(sxml-attribute-attributes attributes))
(simple-input-field-maker-html-tree-maker
reported-type))))))
(define (simple-input-field-maker-html-tree-maker reported-type)
(lambda (input-field)
(let ((attributes (input-field-attributes input-field)))
`(input (@ (type ,reported-type)
(name ,(input-field-name input-field))
,(input-field-attributes-default attributes)
,(input-field-attributes-others attributes))))))
(define (make-simple-input-field-default-setter default-pred? wrap?)
(lambda (input-field value)
(if (default-pred? value)
(set-input-field-attributes-default!
(input-field-attributes input-field)
(if wrap? `(value ,value) value))
(error "Default value must be a number or a string or a symbol."
value))
(touch-input-field! input-field)))
(define (string-or-symbol? thing)
(or (string? thing) (symbol? thing)))
(define simple-default? string-or-symbol?)
(define set-simple-input-field-default!
(make-simple-input-field-default-setter simple-default? #t))
;;;;;;;;;;;;;;;;;;;;
;;; Text input field
(define make-text-input-field
(simple-input-field-maker "text" "text"
simple-default? identity))
(define set-text-input-field-value! set-simple-input-field-default!)
;;;;;;;;;;;;;;;;;;;;;;
;;; Number input field
(define (number-input-field-default? value)
(or (number? value)
(simple-default? value)))
(define (number-input-field-transformer string)
(or (string->number string)
(error "wrong type")))
(define make-number-input-field
(simple-input-field-maker "text" "number"
number-input-field-default?
number-input-field-transformer))
(define set-number-input-field-value!
(make-simple-input-field-default-setter number-input-field-default? #t))
;;;;;;;;;;;;;;;;;;;;;;
;;; hidden input-field
;; Little workaraound, as a hidden input-field needs a value. This
;; value is propagated in the slot "default value".
(define make-hidden-input-field
(let ((hidden-input-field-generator
(simple-input-field-maker "hidden" "text"
simple-default? identity)))
(lambda (value . maybe-further-attributes)
(apply hidden-input-field-generator
(cons value maybe-further-attributes)))))
(define set-hidden-input-field-value!
set-simple-input-field-default!)
;;;;;;;;;;;;;;;;;;;;;;;;
;;; Password input field
(define make-password-input-field
(simple-input-field-maker "password" "password"
simple-default? identity))
(define set-password-input-field-value!
set-simple-input-field-default!)
;;; That's it for simple input fields.
;;;;;;;;;;;;;;;;;;;;;;;;
;;; Textarea input field
(define (make-textarea-input-field . maybe-further-attributes)
(let ((name (generate-input-field-name "textarea")))
(optionals maybe-further-attributes
((default-text simple-default?)
(attributes sxml-attribute?))
(make-input-field
name "textarea"
identity
(make-input-field-attributes
(and default-text)
(sxml-attribute-attributes attributes))
make-textarea-input-field-html-tree))))
(define (make-textarea-input-field-html-tree input-field)
(let ((attributes (input-field-attributes input-field)))
`(textarea (@ (type "textarea")
(name ,(input-field-name input-field))
,(input-field-attributes-others attributes))
,(input-field-attributes-default attributes))))
(define set-textarea-input-field-value!
(let ((textarea-default-setter!
(make-simple-input-field-default-setter simple-default? #f)))
(lambda (textarea-input-field value)
(textarea-default-setter! textarea-input-field value))))
;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Selection input field
;; sel-if == select-input-field
;(make-select-input-fields '("this" "that" "those") '(@ ((id "sushi"))))
;(make-select-input-fields '("this" ("that" '(@ (selected))) "those"))
;; dropdown: (size 1)
;;; A selection input field shows a list of options that can be
;;; selected. For this purpose, we introduce an sel-if-option record,
;;; that contains all the information for each option. This is
;;; justified by the fact, that the options list is in HTML seperated,
;;; too.
(define-record-type sel-if-option :sel-if-option
(really-make-sel-if-option tag value selected? attributes)
sel-if-option?
(tag sel-if-option-tag)
(value sel-if-option-value)
(selected? sel-if-option-selected? set-sel-if-option-selected?!)
(attributes sel-if-option-attributes set-sel-if-option-attributes!))
(define (make-sel-if-option tag value selected? attributes)
(if (string? tag)
(really-make-sel-if-option tag value selected?
(sxml-attribute-attributes attributes))
(error "Select-input-field-option's tag must be a string." tag)))
;; Constructor for valued select input-field option.
(define (make-annotated-sel-if-option tag value . maybe-attributes)
(optionals maybe-attributes
((selected? boolean?)
(attributes sxml-attribute?))
(make-sel-if-option tag value selected? attributes)))
;; Constructor for a simple select input-field option (not annotated).
(define (make-simple-sel-if-option tag . maybe-attributes)
(optionals maybe-attributes
((selected? boolean?)
(attributes sxml-attribute?))
(make-sel-if-option tag 'ignored selected? attributes)))
(define-record-discloser :sel-if-option
(lambda (sel-if-option)
(list 'select-input-field-option
(sel-if-option-tag sel-if-option)
(sel-if-option-value sel-if-option)
(sel-if-option-selected? sel-if-option)
(sel-if-option-attributes sel-if-option)
)))
;; Selecting / Unselecting of an option in an select input-field,
;; chosen by tag.
(define (select-sel-if-option! tag sel-if)
(set-select-input-field-option-selected?! tag sel-if #t))
(define (unselect-sel-if-option! tag sel-if)
(set-select-input-field-option-selected?! tag sel-if #f))
(define (set-select-input-field-option-selected?! tag sel-if selected?)
(let ((options (input-field-attributes-default
(input-field-attributes sel-if))))
(if (number? tag)
(set-sel-if-option-selected?! (list-ref options tag)
selected?)
(let lp ((options options))
(if (null? options)
(error "No such option" tag sel-if)
(if (tag=sel-if-option? tag (car options))
(set-sel-if-option-selected?! (car options) selected?)
(lp (cdr options))))))
(touch-input-field! sel-if)))
;; Find sel-if-option in a list by its tag.
(define (tag=sel-if-option? tag sel-if-option)
(string=? tag (sel-if-option-tag sel-if-option)))
(define (find-sel-if-option tag sel-if-options)
(cond ((member/srfi-1 tag sel-if-options tag=sel-if-option?)
=> car)
(else #f)))
(define (find-sel-if-option-value tag sel-if-options)
(cond ((find-sel-if-option tag sel-if-options)
=> sel-if-option-value)
(else #f)))
;; To be compatible with previous versions of MAKE-SELECT-INPUT-FIELD,
;; we accept also a simple list as an option-list. New programs should
;; use sel-if-options-list (easily createable with
;; (map make-simple-sel-if-option option-list))
(define (tolerate-old-sel-if-options sel-if-options)
(if (and (list? sel-if-options)
(every sel-if-option? sel-if-options))
sel-if-options
(map make-simple-sel-if-option sel-if-options)))
(define (make-select-input-field sel-if-options . maybe-further-attributes)
(really-make-select-input-field (tolerate-old-sel-if-options sel-if-options)
#f
maybe-further-attributes))
(define (make-annotated-select-input-field sel-if-options .
maybe-further-attributes)
(really-make-select-input-field sel-if-options #t maybe-further-attributes))
(define (really-make-select-input-field sel-if-options annotated?
maybe-further-attributes)
(let ((real-sel-if-options (tolerate-old-sel-if-options sel-if-options)))
(optionals maybe-further-attributes
((multiple? boolean?)
(attributes sxml-attribute?))
(let ((name (generate-input-field-name "select")))
(if multiple?
(make-multiple-select-input-field name sel-if-options
annotated? attributes)
(make-single-select-input-field name sel-if-options
annotated? attributes))))))
;; internal
(define (make-multiple-select-input-field name sel-if-options
annotated? attributes)
(make-multi-input-field name "mult-select"
(make-sel-if-multiple-transformer name sel-if-options
annotated?)
(make-input-field-attributes
sel-if-options
(list '(multiple)
(sxml-attribute-attributes attributes)))
make-sel-if-html-tree))
;; internal
(define (make-single-select-input-field name sel-if-options
annotated? attributes)
(make-input-field name "select"
(if annotated?
(lambda (tag)
(cond ((find-sel-if-option-value tag sel-if-options)
=> identity)
(else (error "no such option." tag))))
identity)
(make-input-field-attributes
sel-if-options
(sxml-attribute-attributes attributes))
make-sel-if-html-tree))
(define (make-sel-if-multiple-transformer name sel-if-options annotated?)
(lambda (bindings)
(let ((tags (map cdr
(filter (lambda (binding)
(equal? (car binding) name))
bindings))))
(filter-map (if annotated?
(lambda (tag)
(find-sel-if-option-value tag sel-if-options))
(lambda (tag)
(if (find-sel-if-option tag sel-if-options)
tag
#f)))
tags))))
(define (make-sel-if-html-tree sel-if)
(let ((attributes (input-field-attributes sel-if)))
`(select (@ (name ,(input-field-name sel-if))
,(input-field-attributes-others attributes))
#\newline
,@(make-sel-if-options-html-tree
(input-field-attributes-default attributes)))))
(define (make-sel-if-options-html-tree sel-if-options)
(map (lambda (sel-if-option)
`(option (@ ,(and (sel-if-option-selected? sel-if-option) '(selected))
,(sel-if-option-attributes sel-if-option))
,(sel-if-option-tag sel-if-option)))
sel-if-options))
;;;;;;;;;;;;;;;;;;;;;;
;;; radio input-fields
;; Because grouped radio input-fields must use the same name, we
;; cannot just return one radio input-field object, but we must
;; generate several ones with the same name.
(define (make-radio-input-field-group)
(let ((name (generate-input-field-name "radio")))
(lambda (value-string . maybe-further-attributes)
(optionals maybe-further-attributes
((checked? boolean?)
(attributes sxml-attribute?))
(make-input-field name "radio"
identity
(make-input-field-attributes
(if checked? '(checked) #f)
(list `(value ,value-string)
(sxml-attribute-attributes attributes)))
radio-input-field-html-tree-maker)))))
(define (make-annotated-radio-input-field-group)
(let* ((name (generate-input-field-name "radio"))
(value-table (make-integer-table))
(transformer (make-radio-input-field-transformer value-table)))
(lambda (value . maybe-further-attributes)
(optionals maybe-further-attributes
((checked? boolean?)
(attributes sxml-attribute?))
(let ((number (generate-unique-number)))
(table-set! value-table number value)
(make-input-field name "radio"
transformer
(make-input-field-attributes
(if checked? '(checked) #f)
(list`(value ,(number->string number))
(sxml-attribute-attributes attributes)))
radio-input-field-html-tree-maker))))))
(define (make-radio-input-fields values . maybe-further-attributes)
(optionals maybe-further-attributes
((attributes sxml-attribute?))
(let ((radio-gen (make-annotated-radio-input-field-group)))
(map (lambda (value)
(if attributes
(radio-gen value attributes)
(radio-gen value)))
values))))
(define (make-radio-input-field-transformer value-table)
(lambda (tag)
(cond
((string->number tag) =>
(lambda (number)
(let ((value (table-ref value-table number)))
(if value
value
(error "Unknown tag number for radio input-field" tag)))))
(else
(error "Unknown tag number for radio input-field" tag)))))
(define (radio-input-field-html-tree-maker radio-input-field)
(let* ((attributes (input-field-attributes radio-input-field)))
`(input (@ ((type "radio")
(name ,(input-field-name radio-input-field))
,(input-field-attributes-default attributes)
,(input-field-attributes-others attributes))))))
(define (set-input-field-checked?! input-field checked?)
(let ((attributes (input-field-attributes input-field)))
(set-input-field-attributes-default!
attributes
(if checked? '(checked) #f))
(touch-input-field! input-field)))
(define set-radio-input-field-checked?! set-input-field-checked?!)
(define (check-radio-input-field! radio)
(set-radio-input-field-checked?! radio #t))
(define (uncheck-radio-input-field! radio)
(set-radio-input-field-checked?! radio #f))
;;;;;;;;;;;;;;;;;;;;;;;;
;;; checkbox input-field
(define (make-checkbox-input-field . maybe-further-attributes)
(really-make-checkbox-input-field #t
checkbox-transformer
maybe-further-attributes))
(define (make-annotated-checkbox-input-field value . maybe-further-attributes)
(really-make-checkbox-input-field value
(make-checkbox-transformer value)
maybe-further-attributes))
(define (really-make-checkbox-input-field value transformer attributes)
(let ((name (generate-input-field-name "checkbox")))
(optionals attributes
((checked? boolean?)
(attributes sxml-attribute?))
(make-input-field name "checkbox"
transformer
(make-input-field-attributes
(if checked? '(checked) #f)
(sxml-attribute-attributes attributes))
checkbox-input-field-html-tree-maker))))
(define (make-checkbox-transformer value)
(lambda (tag)
(if (string=? tag "on")
value
#f)))
(define checkbox-transformer
(make-checkbox-transformer #t))
(define (checkbox-input-field-html-tree-maker cb-if)
(let ((attributes (input-field-attributes cb-if)))
`(input (@ ((type "checkbox")
(name ,(input-field-name cb-if))
,(input-field-attributes-default attributes)
,(input-field-attributes-others attributes))))))
(define set-checkbox-input-field-checked?! set-input-field-checked?!)
(define (check-checkbox-input-field! checkbox)
(set-checkbox-input-field-checked?! checkbox #t))
(define (uncheck-checkbox-input-field! checkbox)
(set-checkbox-input-field-checked?! checkbox #f))
;;;;;;;;;;;;;;;;;;;;;;
;; button input-fields
(define (make-button type name button-caption attributes)
(make-input-field name type
identity
(make-input-field-attributes
(and button-caption `(value ,button-caption))
(sxml-attribute-attributes attributes))
make-button-html-tree))
(define (make-button-html-tree button-input-field)
(let ((attributes (input-field-attributes button-input-field)))
`(input (@ (type ,(input-field-type button-input-field))
(name ,(input-field-name button-input-field))
,(input-field-attributes-default attributes)
,(input-field-attributes-others attributes)))))
(define (make-submit-button . maybe-further-attributes)
(optionals maybe-further-attributes
((button-caption string?)
(attributes sxml-attribute?))
(make-button "submit" (generate-input-field-name "submit")
button-caption attributes)))
(define (make-reset-button . maybe-further-attributes)
(optionals maybe-further-attributes
((button-caption string?)
(attributes sxml-attribute?))
(make-button "reset" (generate-input-field-name "reset")
button-caption attributes)))
(define (make-image-button image-source . maybe-further-attributes)
(optionals maybe-further-attributes
((attributes sxml-attribute?))
(make-button "image" (generate-input-field-name "imgbtn")
#f `(@ (src ,image-source)
,@(sxml-attribute-attributes attributes)))))
;;EOF

View File

@ -3,7 +3,7 @@ We have three basic layers of structures: -*- Outline -*-
* Overview
(a) Basic User surflets, simple-surflet-api
(b) Advanced User surflets/my-sxml, surflets/my-sessions,
surflets/primitives
surflets/my-input-fields, surflets/primitives
(c) Administrative User surflet-handler/admin, profiling
The fourth layer:
@ -17,12 +17,13 @@ own rules.
provides: . sending of html represented by surflet-sxml
. using special tags in its surflet-sxml:
url, plain-html, surflet-form
. input-fields, input-field-value,...
. input-fields: input-field-value,
input-field-binding, ...
. get-bindings, extract-bindings, ...
. make-address, make-annotated-address, ...
. returned-via?, case-returned-via, ...
. get-session-data, set-session-data!
surflets is splitted in several parts, that can
surflets contains of several parts, that can
be loaded independently from each other.
** structures: (2) simple-surflet-api
@ -57,7 +58,12 @@ own rules.
. session-alive?, session-surflet-name
. access to options: options-session-lifetime,
options-cache-surflets?
** structures: (3) surflet-handler/primitives
** structures: (3) surflets/my-input-fields
provides: . Access to the primitives of input-fields:
. Constructor, selector, mutators, predicate
** structures: (4) surflet-handler/primitives
provides: . Access to the primitives of the
surflet handler:
. send/suspend, ... that send surflet responses
@ -67,7 +73,6 @@ own rules.
content-type, own headers and own content
(string or list of strings)
. surflet-requests...
* (c) Administrative User
** structures: (1) surflet-handler/admin

View File

@ -1,6 +1,7 @@
(define-structure surflet surflet-interface
(open surflets
surflet-requests
surflets/my-input-fields
handle-fatal-error
url
scheme-with-scsh)
@ -16,20 +17,22 @@
(if (= count bits)
'()
(cons
(make-checkbox-input-field (number->string order))
(make-annotated-checkbox-input-field order)
(loop (+ 1 count)
(* 2 order))))))))
(make-higher-input-field
(make-multi-input-field
#f "byte-input"
(lambda (bindings)
(let loop ((sum 0)
(checkboxes checkboxes))
(if (null? checkboxes)
sum
(loop (+ sum (string->number
(or (input-field-value (car checkboxes) bindings)
"0")))
(loop (+ sum (or (input-field-value (car checkboxes) bindings)
0))
(cdr checkboxes)))))
checkboxes)))
'()
(lambda (ignore)
checkboxes))))
(define byte-input-fields (make-byte-input-fields 8))

View File

@ -1,5 +1,6 @@
(define-structure surflet surflet-interface
(open surflets
surflets/my-input-fields
surflet-requests
handle-fatal-error
let-opt
@ -20,17 +21,18 @@
(define operator-input-field
(let ((name (generate-input-field-name "operator")))
(make-input-field
name
name "operator"
(lambda (operator-string)
(cond
((assoc operator-string *operator-alist*) =>
(lambda (a) a))
(else
(error "no such operator" operator-string))))
`(select (@ (name ,name))
,@(map (lambda (operator)
`(option ,(operator-symbol operator)))
*operator-alist*)))))
(let ((operator (assoc operator-string *operator-alist*)))
(if operator
operator
(error "no such operator" operator-string))))
'()
(lambda (input-field)
`(select (@ (name ,name))
,@(map (lambda (operator)
`(option ,(operator-symbol operator)))
*operator-alist*))))))
(define (make-number-input-field/default default)

View File

@ -163,9 +163,9 @@
(and armed?
(map (lambda (type)
(let ((text (cdr (assoc type arm-types))))
(cons (make-checkbox-input-field
(and def-weapons (member? text def-weapons))
text)
(cons (make-annotated-checkbox-input-field
text
(and def-weapons (member? text def-weapons)))
text)))
(ship-data-arm-types (ship-ref class)))))
(energy-input (and armed?
@ -215,7 +215,7 @@
;;; items are taken from the ship data list.
(define (get-extras req class)
(let* ((checkboxes+text (map (lambda (extra)
(cons (make-checkbox-input-field extra)
(cons (make-annotated-checkbox-input-field extra)
(cdr (assoc extra extras))))
(ship-data-extras (ship-ref class))))
(req (send-html/suspend