#lang scheme/base
(require net/url
scheme/contract
(file "../javascript/render.ss")
(file "../javascript/struct.ss")
(file "struct-internal.ss"))
(define (quotable-value->string val [pretty? #t])
(cond [(string? val) val]
[(symbol? val) (symbol->string val)]
[(bytes? val) (bytes->string/utf-8 val)]
[(number? val) (number->string val)]
[(boolean? val) (if val "yes" "no")]
[(url? val) (url->string val)]
[(javascript? val) (if pretty?
(javascript->pretty-string val)
(javascript->string val))]
[else (error (format "Expected val, received ~s." val))]))
(define (preserve-singletons? tag)
(if (memq tag '(script div p ul li span th td a iframe))
#t
#f))
(define (attribute->raw attr)
(make-raw (list (render display-attribute attr))))
(define (quote-javascript-attribute-value val)
(if (javascript? val)
(javascript->string val)
val))
(define (render display-proc arg)
(let ([out (open-output-string)])
(display-proc arg out)
(get-output-string out)))
(define (display-attribute attr out)
(define name (attribute-name attr))
(define val (attribute-value attr))
(display #\space out)
(display name out)
(display "=\"" out)
(if (raw? val)
(display (raw-data val) out)
(display-quotable-value (atom-data val) out))
(display #\" out))
(define (display-quotable-value val out)
(cond [(boolean? val) (display (if val "true" "false") out)]
[(number? val) (display val out)]
[(string? val) (display-quoted-string val out)]
[(symbol? val) (display-quoted-string (symbol->string val) out)]
[(bytes? val) (display-quoted-string (bytes->string/utf-8 val) out)]
[(url? val) (display-quoted-string (url->string val) out)]
[else (error (format "Expected (U boolean number string symbol bytes), received ~s" val))]))
(define (display-quoted-string val out)
(let ([len (string-length val)])
(let loop ([i 0])
(when (< i len)
(let ([char (string-ref val i)])
(cond [(eq? char #\&) (display "&" out)]
[(eq? char #\") (display """ out)]
[(eq? char #\<) (display "<" out)]
[(eq? char #\>) (display ">" out)]
[else (display char out)])
(loop (add1 i)))))))
(provide/contract
[quotable-value->string (->* (quotable-value?) (boolean?) string?)]
[preserve-singletons? (-> symbol? boolean?)]
[attribute->raw (-> attribute? raw?)]
[quote-javascript-attribute-value (-> quotable-value? quotable-value?)])