;;;; cl-scopes/web/dom - "Data Output Model" = simple and dedicated HTML generator (defpackage :scopes/web/dom (:use :common-lisp) (:local-nicknames (:alx :alexandria)) (:export #:render #:dl)) (in-package :scopes/web/dom) ;;;; basic / common stuff (defvar *output* nil) (defmacro render (&body body) `(let ((*output* (make-string-output-stream))) ,@body (get-output-stream-string *output*))) (defmacro put-string (s) `(write-string ,s *output*)) (defmacro put-char (c) `(write-char ,c *output*)) (defmacro nested (tag attrs &body body) `(progn (start ,tag ,attrs) ,@body (end ,tag t))) (defun terminal (tag attrs val) (start tag attrs) (put-string val) (end tag)) (defun start (tag &optional attrs) (put-char #\<) (put-string tag) (put-char #\>)) (defun end (tag &optional newline) (put-string ") (if newline (put-char #\Newline))) ;;;; tag-specific renderers (defun dl (plist) (nested "dl" nil (loop for (key val . r) on plist by #'cddr do (terminal "dt" nil (string-downcase key)) (dd val)))) (defun dd (v) (if (atom v) (setf v (list v))) (dolist (el v) (terminal "dd" nil (string el))))