Refactor and format
This commit is contained in:
parent
1880f9d25a
commit
1109779a5f
2 changed files with 65 additions and 61 deletions
|
@ -38,10 +38,14 @@
|
||||||
|
|
||||||
;;; the h macro for avoiding import all builtin html element functions
|
;;; the h macro for avoiding import all builtin html element functions
|
||||||
#:h
|
#:h
|
||||||
|
|
||||||
|
;;; helper for generate html string
|
||||||
#:element-string
|
#:element-string
|
||||||
#:elem-str))
|
#:elem-str))
|
||||||
(in-package #:piccolo/elements)
|
(in-package #:piccolo/elements)
|
||||||
|
|
||||||
|
;;; classes
|
||||||
|
|
||||||
(defclass element ()
|
(defclass element ()
|
||||||
((tag :initarg :tag
|
((tag :initarg :tag
|
||||||
:accessor element-tag)
|
:accessor element-tag)
|
||||||
|
@ -60,8 +64,9 @@
|
||||||
((expand-to :initarg :expander
|
((expand-to :initarg :expander
|
||||||
:accessor user-element-expander)))
|
:accessor user-element-expander)))
|
||||||
|
|
||||||
(defclass fragment (element)
|
(defclass fragment (element) ())
|
||||||
())
|
|
||||||
|
;;; constructors
|
||||||
|
|
||||||
(defun make-builtin-element (&key tag attrs children)
|
(defun make-builtin-element (&key tag attrs children)
|
||||||
(make-instance 'builtin-element
|
(make-instance 'builtin-element
|
||||||
|
@ -95,6 +100,8 @@
|
||||||
:attrs (make-attrs :alist nil)
|
:attrs (make-attrs :alist nil)
|
||||||
:children (util:escape-children children)))
|
:children (util:escape-children children)))
|
||||||
|
|
||||||
|
;;; attributes
|
||||||
|
|
||||||
(defstruct (attrs (:constructor %make-attrs))
|
(defstruct (attrs (:constructor %make-attrs))
|
||||||
alist)
|
alist)
|
||||||
|
|
||||||
|
@ -121,7 +128,7 @@
|
||||||
(defmethod attr ((element element) key)
|
(defmethod attr ((element element) key)
|
||||||
(attr (element-attrs element) key))
|
(attr (element-attrs element) key))
|
||||||
|
|
||||||
(defvar *builtin-elements* (make-hash-table))
|
;;; elements
|
||||||
|
|
||||||
(defun split-attrs-and-children (attrs-and-children)
|
(defun split-attrs-and-children (attrs-and-children)
|
||||||
(cond
|
(cond
|
||||||
|
@ -147,6 +154,9 @@
|
||||||
(t
|
(t
|
||||||
(values (make-attrs :alist nil) (lol:flatten attrs-and-children)))))
|
(values (make-attrs :alist nil) (lol:flatten attrs-and-children)))))
|
||||||
|
|
||||||
|
(defparameter *builtin-elements* (make-hash-table))
|
||||||
|
(setf (gethash :html *builtin-elements*) t)
|
||||||
|
|
||||||
(defun %html (&rest attrs-and-children)
|
(defun %html (&rest attrs-and-children)
|
||||||
(multiple-value-bind (attrs children)
|
(multiple-value-bind (attrs children)
|
||||||
(split-attrs-and-children attrs-and-children)
|
(split-attrs-and-children attrs-and-children)
|
||||||
|
@ -158,8 +168,6 @@
|
||||||
(defmacro html (&body attrs-and-children)
|
(defmacro html (&body attrs-and-children)
|
||||||
`(%html ,@attrs-and-children))
|
`(%html ,@attrs-and-children))
|
||||||
|
|
||||||
(setf (gethash :html *builtin-elements*) t)
|
|
||||||
|
|
||||||
(defmacro define-builtin-element (element-name)
|
(defmacro define-builtin-element (element-name)
|
||||||
(let ((%element-name (alx:symbolicate '% element-name)))
|
(let ((%element-name (alx:symbolicate '% element-name)))
|
||||||
`(progn
|
`(progn
|
||||||
|
@ -191,32 +199,61 @@
|
||||||
style sub summary sup svg table tbody td template textarea tfoot th
|
style sub summary sup svg table tbody td template textarea tfoot th
|
||||||
thead |time| title tr track u ul var video wbr)
|
thead |time| title tr track u ul var video wbr)
|
||||||
|
|
||||||
|
(lol:defmacro! define-element (name (&rest args) &body body)
|
||||||
|
(let ((%name (alx:symbolicate '% name)))
|
||||||
|
`(progn
|
||||||
|
(defun ,%name (&rest attrs-and-children)
|
||||||
|
(multiple-value-bind (,g!attrs ,g!children)
|
||||||
|
(split-attrs-and-children attrs-and-children)
|
||||||
|
(make-user-element
|
||||||
|
:tag (string-downcase ',name)
|
||||||
|
:attrs ,g!attrs
|
||||||
|
:children ,g!children
|
||||||
|
:expander (lambda (tag attrs ,g!exp-children)
|
||||||
|
(declare (ignorable tag attrs))
|
||||||
|
(let ((children (and ,g!exp-children
|
||||||
|
(make-fragment :children ,g!exp-children))))
|
||||||
|
(declare (ignorable children))
|
||||||
|
(let ,(mapcar (lambda (arg)
|
||||||
|
(list arg `(attr attrs (alx:make-keyword ',arg))))
|
||||||
|
args)
|
||||||
|
(progn ,@body)))))))
|
||||||
|
(defmacro ,name (&body attrs-and-children)
|
||||||
|
`(,',%name ,@attrs-and-children)))))
|
||||||
|
|
||||||
|
(defun %<> (&rest children)
|
||||||
|
(make-fragment :children children))
|
||||||
|
|
||||||
|
(defmacro <> (&body children)
|
||||||
|
`(%<> ,@children))
|
||||||
|
|
||||||
|
;;; print-object
|
||||||
|
|
||||||
(defparameter *boolean-attrs*
|
(defparameter *boolean-attrs*
|
||||||
'(allowfullscreen async autofocus autoplay checked controls default defer
|
'(allowfullscreen async autofocus autoplay checked controls default defer
|
||||||
disabled formnovalidate inert ismap itemscope loop multiple muted nomodule
|
disabled formnovalidate inert ismap itemscope loop multiple muted nomodule
|
||||||
novalidate open playsinline readonly required reversed selected))
|
novalidate open playsinline readonly required reversed selected))
|
||||||
|
|
||||||
(defmethod print-object ((attrs attrs) stream)
|
|
||||||
(if (attrs-alist attrs)
|
|
||||||
(let ((alist (attrs-alist attrs)))
|
|
||||||
(dolist (pair alist)
|
|
||||||
(let ((key (car pair))
|
|
||||||
(value (cdr pair)))
|
|
||||||
(if (member key *boolean-attrs* :test #'string=)
|
|
||||||
(when value
|
|
||||||
(format stream " ~a" (string-downcase key)))
|
|
||||||
(format stream " ~a=~s" (string-downcase key) value)))))
|
|
||||||
(format stream "")))
|
|
||||||
|
|
||||||
(defparameter *self-closing-tags*
|
(defparameter *self-closing-tags*
|
||||||
'(area base br col embed hr img input keygen
|
'(area base br col embed hr img input keygen
|
||||||
link meta param source track wbr))
|
link meta param source track wbr))
|
||||||
|
|
||||||
|
(defparameter *expand-user-element* t)
|
||||||
|
|
||||||
(defun self-closing-p (tag)
|
(defun self-closing-p (tag)
|
||||||
(member (make-symbol (string-upcase tag))
|
(member (make-symbol (string-upcase tag))
|
||||||
*self-closing-tags*
|
*self-closing-tags*
|
||||||
:test #'string=))
|
:test #'string=))
|
||||||
|
|
||||||
|
(defmethod print-object ((attrs attrs) stream)
|
||||||
|
(loop
|
||||||
|
:for (k . v) :in (attrs-alist attrs)
|
||||||
|
:do (format stream (if (member k *boolean-attrs* :test #'string=)
|
||||||
|
"~@[ ~a~]"
|
||||||
|
" ~a=~s")
|
||||||
|
(string-downcase k)
|
||||||
|
v)))
|
||||||
|
|
||||||
(defmethod print-object ((element element) stream)
|
(defmethod print-object ((element element) stream)
|
||||||
(if (element-children element)
|
(if (element-children element)
|
||||||
(format stream (if (rest (element-children element))
|
(format stream (if (rest (element-children element))
|
||||||
|
@ -237,41 +274,11 @@
|
||||||
(format stream "~a~%" (element-prefix element))
|
(format stream "~a~%" (element-prefix element))
|
||||||
(call-next-method))
|
(call-next-method))
|
||||||
|
|
||||||
(lol:defmacro! define-element (name (&rest args) &body body)
|
|
||||||
(let ((%name (alx:symbolicate '% name)))
|
|
||||||
`(progn
|
|
||||||
(defun ,%name (&rest attrs-and-children)
|
|
||||||
(multiple-value-bind (,g!attrs ,g!children)
|
|
||||||
(split-attrs-and-children attrs-and-children)
|
|
||||||
(make-user-element
|
|
||||||
:tag (string-downcase ',name)
|
|
||||||
:attrs ,g!attrs
|
|
||||||
:children ,g!children
|
|
||||||
:expander (lambda (tag attrs ,g!exp-children)
|
|
||||||
(declare (ignorable tag attrs ,g!exp-children))
|
|
||||||
(let ((children (and ,g!exp-children
|
|
||||||
(make-fragment :children ,g!exp-children))))
|
|
||||||
(declare (ignorable children))
|
|
||||||
(let ,(mapcar (lambda (arg)
|
|
||||||
(list arg `(attr attrs (alx:make-keyword ',arg))))
|
|
||||||
args)
|
|
||||||
(progn ,@body)))))))
|
|
||||||
(defmacro ,name (&body attrs-and-children)
|
|
||||||
`(,',%name ,@attrs-and-children)))))
|
|
||||||
|
|
||||||
(defvar *expand-user-element* t)
|
|
||||||
|
|
||||||
(defmethod print-object ((element user-element) stream)
|
(defmethod print-object ((element user-element) stream)
|
||||||
(if *expand-user-element*
|
(if *expand-user-element*
|
||||||
(print-object (user-element-expand-to element) stream)
|
(print-object (user-element-expand-to element) stream)
|
||||||
(call-next-method)))
|
(call-next-method)))
|
||||||
|
|
||||||
(defun %<> (&rest children)
|
|
||||||
(make-fragment :children children))
|
|
||||||
|
|
||||||
(defmacro <> (&body children)
|
|
||||||
`(%<> ,@children))
|
|
||||||
|
|
||||||
(defmethod print-object ((element fragment) stream)
|
(defmethod print-object ((element fragment) stream)
|
||||||
(if (element-children element)
|
(if (element-children element)
|
||||||
(format stream (if (rest (element-children element))
|
(format stream (if (rest (element-children element))
|
||||||
|
@ -279,6 +286,8 @@
|
||||||
"~<~a~:>")
|
"~<~a~:>")
|
||||||
(element-children element))))
|
(element-children element))))
|
||||||
|
|
||||||
|
;;; h macro
|
||||||
|
|
||||||
(defun html-element-p (node)
|
(defun html-element-p (node)
|
||||||
(and (symbolp node)
|
(and (symbolp node)
|
||||||
(not (keywordp node))
|
(not (keywordp node))
|
||||||
|
@ -295,6 +304,8 @@
|
||||||
(declare (ignorable node))
|
(declare (ignorable node))
|
||||||
(find-symbol (string-upcase node) :piccolo)))))
|
(find-symbol (string-upcase node) :piccolo)))))
|
||||||
|
|
||||||
|
;;; helper for generate html string
|
||||||
|
|
||||||
(defmethod element-string ((element element))
|
(defmethod element-string ((element element))
|
||||||
(with-output-to-string (s)
|
(with-output-to-string (s)
|
||||||
(write element :stream s)))
|
(write element :stream s)))
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
(:export
|
(:export
|
||||||
;;; list utility
|
;;; list utility
|
||||||
#:plist-alist
|
#:plist-alist
|
||||||
#:alist-plist
|
|
||||||
|
|
||||||
;;; escape utility
|
;;; escape utility
|
||||||
#:*escape-html*
|
#:*escape-html*
|
||||||
|
@ -22,13 +21,7 @@
|
||||||
(loop for (k v) on plist by #'cddr
|
(loop for (k v) on plist by #'cddr
|
||||||
collect (cons k v)))
|
collect (cons k v)))
|
||||||
|
|
||||||
(defun alist-plist (alist)
|
(defparameter *escape-html* :utf8
|
||||||
(mapcan (lambda (kv)
|
|
||||||
(list (string-downcase (car kv))
|
|
||||||
(cdr kv)))
|
|
||||||
alist))
|
|
||||||
|
|
||||||
(defvar *escape-html* :utf8
|
|
||||||
"Specify the escape option when generate html, can be :UTF8, :ASCII, :ATTR or NIL.
|
"Specify the escape option when generate html, can be :UTF8, :ASCII, :ATTR or NIL.
|
||||||
If :UTF8, escape only #\<, #\> and #\& in body, and \" in attribute keys. #\' will
|
If :UTF8, escape only #\<, #\> and #\& in body, and \" in attribute keys. #\' will
|
||||||
in attribute keys will not be escaped since piccolo will always use double quote for
|
in attribute keys will not be escaped since piccolo will always use double quote for
|
||||||
|
|
Loading…
Reference in a new issue