;;; Copyright 2002, 2003 Andreas Bernauer ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; input-fields ;;; defines input-fields for surflets ;;; Globals (define *input-field-trigger* `*input-field*) (define generate-input-field-name generate-unique-name) ;;; 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 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 :real-input-field (lambda (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)) (define (input-field? input-field) (and (pair? input-field) (eq? *input-field-trigger* (car input-field)) (real-input-field? (cadr input-field)))) (define (make-input-field-selector selector) (lambda (input-field) (with-real-input-field input-field (selector real-input-field)))) (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 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 input-field-multi? (make-input-field-selector real-input-field-multi?)) (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!)) ;; 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 . ) ;; : #{Real-input-field "name"} (define (raw-input-field-value input-field bindings) (let ((real-input-field (cadr input-field))) (cond ((real-input-field-multi? real-input-field) ((real-input-field-transformer real-input-field) input-field bindings)) ((real-input-field-binding real-input-field bindings) => (lambda (binding) ((real-input-field-transformer real-input-field) (cdr binding)))) (else (error "no such input-field" input-field bindings))))) ;; Trys to get a value for INPUT-FIELD in BINDINGS. If this fails ;; (i.e. RAW-INPUT-FIELD-VALUE returns an error), the default-value is ;; returned. The default-value defaults to #f. NOTE: If you do this ;; with input-fields whose valid values may be the same as the default ;; value, you cannot determine by the result if there was such a value ;; or not. Keep in mind, that RAW-INPUT-FIELD-VALUE returns also an ;; error, if there was not such an input field. This makes ;; INPUT-FIELD-VALUE working with checkbox input fields because they ;; miss if they are not checked. (define (input-field-value input-field bindings . maybe-default) (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 (real-input-field-name input-field) bindings)) ;; Returns the binding of the input-field in bindings by the ;; input-field's name. If your input-field will have another name in ;; the bindings than it was created with, use a multi-input-field. (define (input-field-binding input-field bindings) (real-input-field-binding (cadr input-field) bindings)) ;;EOF