(define url-rule `(url *preorder* . ,(lambda (tag uri . maybe-text) (surflet-sxml->low-level-sxml `(a (@ (href ,uri)) ,(if (null? maybe-text) uri maybe-text)))))) (define plain-html-rule `(plain-html *preorder* . ,(lambda (tag . text) text))) (define nbsp-rule `(nbsp . ,(lambda (_) " "))) (define comment-rule `(*COMMENT* *preorder* . ,(lambda (tag . elems) `("")))) (define default-rules `(,attribute-rule ,default-rule ,text-rule ,comment-rule ,url-rule ,plain-html-rule ,nbsp-rule)) (define surflet-form-rule `(surflet-form ;; Must do something to prevent the k-url string to be HTML ;; escaped. *preorder* . ,(lambda (trigger k-url . args) (receive (parameters elems) (optionals-first (list symbol? sxml-attribute?) args) (make-surflet-form k-url ; k-url (car parameters) ; POST, GET or #f=GET (cadr parameters); attributes elems))))) (define (make-surflet-form k-url method attributes elems) (let ((real-method (case method ((get GET) "GET") ((post POST) "POST") ((#f) "GET") (else (error "invalid method type" method))))) (surflet-sxml->low-level-sxml `(form (@ ((method ,real-method) (action ,k-url) ,@(if attributes (cdr attributes) '()))) ,@elems)))) (define input-field-rule `(,*input-field-trigger* *preorder* . ,(lambda (trigger input-field) (surflet-sxml->low-level-sxml ;; We need a real input-field for input-field-html-tree. (input-field-html-tree (list trigger input-field)))))) (define surflet-sxml-rules `(,@default-rules ;; form contents: ,input-field-rule ,surflet-form-rule)) ;; Low-Level-SXML is a list that can be understood by ;; display-low-level-sxml. In contains only characters, strings, and ;; thunks. (define (surflet-sxml->low-level-sxml sxml-tree) (pre-post-order sxml-tree surflet-sxml-rules)) ;;; Helping funtion for surflet-sxml-rule ;; PRED-LIST contains list of predicates that recognizes optional ;; leading parameters. FURTHER-ATTRIBUTES is the optional parameter ;; list as got by procedure call. TYPED-OPTIONALS returns two values: ;; a list of the same length as PRED-LIST and a list containing the ;; left arguments that did not fit the predicates. ;; ;; With the help of OPTIONALS-FIRST you can define a function ;; like `make-submit-button [string] [further-attributes]' this way: ;; (define (make-submit-button . args) ;; (receive (params rest-args) ;; (prefix-optionals (list string? xml-attribute?) args) ;; (if (pair? rest-args) ;; (error "too many arguments to make-submit-button)) ;; (let ((value (first params)) ;; (attributes (second params))) ;; ...)))) ;; (define (optionals-first pred-list args) (let loop ((results '()) (pred-list pred-list) (args args)) (cond ((null? pred-list) (values (reverse results) args)) ((null? args) (values (rev-append results (make-list (length pred-list) #f)) '())) (((car pred-list) (car args)) (loop (cons (car args) results) (cdr pred-list) (cdr args))) (else (loop (cons #f results) (cdr pred-list) args)))))