first shot on servlet's new form interface

This commit is contained in:
interp 2002-09-24 16:56:00 +00:00
parent 8e4a0c2872
commit 9f2754cff5
4 changed files with 247 additions and 55 deletions

View File

@ -104,9 +104,19 @@
send/finish send/finish
send-html/suspend send-html/suspend
send-html/finish send-html/finish
send-html
form-query form-query
extract-bindings extract-bindings
extract-single-binding)) extract-single-binding
make-text-input-field
make-password-input-field
make-number-input-field
make-textarea-input-field
make-select-input-field
make-submit-button
input-field-value
make-callback))
(define-structure plugin-utilities plugin-utilities-interface (define-structure plugin-utilities plugin-utilities-interface
(open servlet-handler/plugin (open servlet-handler/plugin
@ -114,6 +124,10 @@
parse-html-forms parse-html-forms
sxml-to-html ;SXML->HTML sxml-to-html ;SXML->HTML
srfi-1 ;FILTER srfi-1 ;FILTER
sxml-tree-trans
url
httpd-request
define-record-types
scsh scsh
scheme) scheme)
(files utilities)) (files utilities))

View File

@ -6,9 +6,7 @@
(lambda (new-url) (lambda (new-url)
(make-usual-html-response (make-usual-html-response
(lambda (out options) (lambda (out options)
(with-current-output-port* ; FIXME: will change in further revision (servlet-XML->HTML out (html-tree-maker new-url)))))))
out
(lambda () (SXML->HTML (html-tree-maker new-url)))))))))
(define (send-html/finish html-tree) (define (send-html/finish html-tree)
(do-sending send/finish html-tree)) (do-sending send/finish html-tree))
@ -16,13 +14,10 @@
(define (send-html html-tree) (define (send-html html-tree)
(do-sending send html-tree)) (do-sending send html-tree))
(define (do-sending sending-version html-tree) (define (do-sending send html-tree)
(sending-version (send (make-usual-html-response
(make-usual-html-response (lambda (out options)
(lambda (out options) (servlet-XML->HTML out html-tree)))))
(with-current-output-port* ; FIXME: will change in further revision
out
(lambda () (SXML->HTML html-tree)))))))
(define (make-usual-html-response writer-proc) (define (make-usual-html-response writer-proc)
(make-response (make-response
@ -57,4 +52,207 @@
key bindings)))) key bindings))))
;; adapted from Oleg's SXML-tree-trans.scm
;; extended by port argument
;; #t: current-output-port
;; #f: string
;; port: port
;; else: error
(define (formated-reply port . fragments)
(cond
((not port)
(call-with-string-output-port
(lambda (port)
(real-formated-reply port fragments))))
((eq? port #t)
(real-formated-reply (current-output-port) fragments))
((output-port? port)
(real-formated-reply port fragments))
(else
(error "invalid port argument to FORMATED-REPLY" port))))
(define (real-formated-reply port fragments)
(let loop ((fragments fragments) (result #f))
(cond
((null? fragments) result)
((not (car fragments)) (loop (cdr fragments) result))
((null? (car fragments)) (loop (cdr fragments) result))
((pair? (car fragments))
(loop (cdr fragments) (loop (car fragments) result)))
((procedure? (car fragments))
((car fragments))
(loop (cdr fragments) #t))
(else
(display (car fragments) port)
(loop (cdr fragments) #t)))))
;; adapted from Oleg's SXML-to-HTML.scm
;; extended by additional port argument
(define (servlet-XML->HTML out html-tree)
(formated-reply out
(pre-post-order html-tree
;; Universal transformation rules. Work for every HTML,
;; present and future
`(,@default-rules
(form *preorder* .
,(lambda (trigger call-back-function . elems)
(list "<form method=\"GET\" action=\"" call-back-function
(if (and (pair? elems) (pair? (car elems)) (eq? '@ (caar elems)))
(list (car elems) "\">\n" (parse-form-elems (cdr elems)) "</form>")
(list "\">\n" (parse-form-elems elems) "</form>"))))))
)))
(define (parse-form-elems elems)
(map (lambda (elem)
(if (input-field? elem)
(post-order (input-field-HTML-tree elem) default-rules)
(post-order elem default-rules)))
elems))
(define text-html-rule
`(*text* . ,(lambda (trigger str)
(if (string? str) (string->goodHTML str) str))))
(define default-rules
`((@ ; local override for attributes
((*default*
. ,(lambda (attr-key . value) ((enattr attr-key) value))))
. ,(lambda (trigger . value) (list '@ value)))
(*default* . ,(lambda (tag . elems) (apply (entag tag) elems)))
,text-html-rule
(URL . ,(lambda (tag URI text) (list "<a href=\"" URI "\">" text "</a>"))))
)
(define (make-callback function)
(call-with-current-continuation
(lambda (exit)
(let* ((req (send/suspend (lambda (new-url)
(exit new-url))))
(bindings (form-query (http-url:search (request:url req)))))
(function bindings)))))
(define-record-type input-field :input-field
(make-input-field name transformer HTML-tree)
input-field?
(name input-field-name)
(transformer input-field-transformer)
(attributes input-field-attributes)
(HTML-tree input-field-HTML-tree))
(define-record-discloser :input-field
(lambda (input-field)
(list 'input-field (input-field-name input-field))))
;; FIXME: consider creating small names
(define generate-input-field-name
(let ((id 0))
(lambda (type-string)
(set! id (+ 1 id))
(string-append type-string (number->string id)))))
(define identity (lambda (a) a))
(define (make-text-input-field . maybe-further-attributes)
(let ((name (generate-input-field-name "text")))
(make-input-field name
identity
`(input (@ (type "text")
(name ,name)
,@maybe-further-attributes)))))
(define (make-number-input-field . maybe-further-attributes)
(let ((name (generate-input-field-name "number")))
(make-input-field name
(lambda (string)
(or (string->number string)
(error "wrong type")))
`(input (@ (type "text")
(name ,name)
,@maybe-further-attributes)))))
(define (make-password-input-field . maybe-further-attributes)
(let ((name (generate-input-field-name "password")))
(make-input-field name
identity
`(input (@ (type "password")
(name ,name)
,@maybe-further-attributes)))))
(define (make-textarea-input-field . maybe-further-attributes)
(let ((name (generate-input-field-name "textarea"))
(default-text (if (and (pair? maybe-further-attributes)
(string? (car maybe-further-attributes)))
(car maybe-further-attributes)
'())))
(make-input-field name
identity
`(textarea (@ (type "textarea")
(name ,name)
,@maybe-further-attributes)
,default-text))))
(define (make-select-input-field options . maybe-further-attributes)
(let ((name (generate-input-field-name "select")))
(make-input-field name
(lambda (select)
select) ;FIXME[extension] refer to list elements
`(select (@ ((name ,name)
,@maybe-further-attributes))
#\newline
,@(map (lambda (option)
(if (pair? option) ; with attributes?
`(option (@ ,@(cdr option)) ,(car option))
`(option ,option)))
options)))))
;; in work
(define (make-radio-input-field values . maybe-further-attributes)
(let ((name (generate-input-field-name "radio")))
(make-input-field name
(lambda (select)
select) ;FIXME refer to list elements
(map (lambda (value)
`((input (@ ((type "radio")
(name ,name)
,@maybe-further-attributes
,(if (pair? value) ; with attributes?
(cdr value)
'())))) ;FIXME: add value field
,(if (pair? value) ; with attributes?
(car value)
value)))
values))))
(define (make-submit-button . maybe-further-attributes)
(if (and (pair? maybe-further-attributes)
(string? (car maybe-further-attributes)))
`(input (@ (type "submit")
(value ,(car maybe-further-attributes))
,@maybe-further-attributes))
`(input (@ (type "submit")
,@maybe-further-attributes))))
(define (input-field-value input-field bindings)
(cond
((assoc (input-field-name input-field) bindings) =>
(lambda (binding)
((input-field-transformer input-field) (cdr binding))))
(else
(error "no such input-field" input-field bindings))))
(define number-input-field (make-number-input-field))
(define test
`(html
(title "My Title")
(body
(p (URL "reset" "click here to reset"))
(p (form "return-URI" (table (tr (td "Enter a number ") (td ,number-input-field )))
,(make-submit-button))))))

View File

@ -6,41 +6,27 @@
scheme) scheme)
(begin (begin
(define (add-call-back continue) (define number-input-field (make-number-input-field '(maxlength 10)))
(make-call-back
(lambda (bindings)
(continue
(string->number (extract-single-binding bindings "number"))))))
(define (make-call-back function)
(call-with-current-continuation
(lambda (exit)
(let* ((req (send/suspend (lambda (new-url)
(exit new-url))))
(bindings (form-query (http-url:search (request:url req)))))
;; I know the names and the types from God
(function bindings)))))
(define (get-number input-text . maybe-title) (define (get-number input-text . maybe-title)
(let* ((title (if (pair? maybe-title) (car maybe-title) #f)) (let* ((title (if (pair? maybe-title) (car maybe-title) #f))
(result (call-with-current-continuation (result
(lambda (exit) (send-html/suspend
(send-html (lambda (new-url)
(lambda (new-url) `(html ,(if title
`(html ,(if title `(title ,title) '())
`(title ,title) '()) (body
(body ,(if title `(h1 ,title) '())
,(if title `(h1 ,title) '()) (p (a (@ href "reset")
(p (a (@ href "reset") "click here to reset server's plugin cache")) "click here to reset server's plugin cache"))
(p (p
(form (@ (method "get") (form ,new-url
(action ,(add-call-back exit))) ,input-text
,input-text ,number-input-field
(input (@ (type "text") ,(make-submit-button)))))))))
(name "number"))
(input (@ (type "submit"))))))))))))))
(if result (if result
result (input-field-value number-input-field
(form-query (http-url:search (request:url result))))
(get-number input-text "Please enter a number")))) (get-number input-text "Please enter a number"))))
(define (get-number1) (define (get-number1)
@ -52,11 +38,12 @@
(define (main req) (define (main req)
(let ((number1 (get-number1)) (let ((number1 (get-number1))
(number2 (get-number2))) (number2 (get-number2)))
(send-html/finish (send-html
`(html (title "Result") `(html (title "Result")
(body (h1 "Result") (body (h1 "Result")
(p ,(number->string (+ number1 number2))) (p ,(number->string (+ number1 number2)))
(a (@ (href "/")) "done")))) (a (@ (href "/")) "done"))))
"this will never be evaluated"))
"this string will never be evaluated"))
)) ))

View File

@ -1,16 +1,9 @@
(define-structure plugin plugin-interface (define-structure plugin plugin-interface
(open scsh (open scsh
scheme scheme
plugin-utilities
httpd-responses) httpd-responses)
(begin (begin
(define (main send/suspend) (define (main req)
(make-response (send-html/finish
http-status/ok '(html (body (h1 "This is from servlet")))))))
(status-code->text http-status/ok)
(time)
"text/html"
'()
(make-writer-body
(lambda (out options)
(format out "<HTML><BODY><H1>THIS IS FROM SERVLET</H1></BODY></HTML>~%")))))))