diff of 9a7004f18303b19aafe20bbe37869ba705877655
9a7004f18303b19aafe20bbe37869ba705877655
diff --git a/src/murja-newui/newui.lisp b/src/murja-newui/newui.lisp
index 73f6f33..9e9be25 100644
--- a/src/murja-newui/newui.lisp
+++ b/src/murja-newui/newui.lisp
@@ -1,6 +1,6 @@
(defpackage murja.newui
(:use :cl)
- (:export :*server*)
+ (:export :*server* :@newui :c :with-state)
(:local-nicknames (:json :com.inuoe.jzon))
(:import-from :cl-hash-util :hash))
@@ -100,10 +100,17 @@
(defmethod render ((s string))
s)
+(defparameter *single-element-tags* (list :link)
+ "Contains tags that don't expand to <:tag attrs>children</:tag> but instead into <:tag attrs />")
+
(defmethod render ((c component))
(with-slots (tag attrs children) c
- (format nil "<~a ~{~a=\"~a\"~^ ~}>~% ~{~a~}~%</~a>~%"
- tag attrs (mapcar (lambda (kid) (render kid)) children) tag)))
+ (if (member tag *single-element-tags*)
+ (format nil "<~a~{ ~a=\"~a\"~^~} />" tag attrs)
+ (format nil "~a~&
+<~a~{ ~a=\"~a\"~^~}>~% ~{~a~}~%</~a>~%"
+ (if (equalp tag :html) "<!DOCTYPE html>" "")
+ tag attrs (mapcar (lambda (kid) (render kid)) children) tag))))
(defmethod rerender ((c component))
(with-slots (attrs) c
@@ -147,7 +154,8 @@
"(with-state (~{(~a ~a)~})
~a)" (alexandria:hash-table-plist (state-map s)) (root-component s)))
-(defmacro with-state (bindings &rest body)
+(defmacro with-state (bindings (&key (root-id (random 123456)))
+ &body body)
(let* ((rewritten-symbols (map 'list #'first bindings))
(values (map 'list #'second bindings))
(_
@@ -165,7 +173,7 @@
((member element rewritten-symbols) `(get-state current-state (quote ,element)))
(t element))))
`(let ((current-state (make-instance 'state :state (alexandria:plist-hash-table (list ,@actual-bindings-plist))))
- (root-component-id (format nil "id~d" (random 123456))))
+ (root-component-id (format nil "id~a" ,root-id)))
(setf (root-component current-state)
,@(rewrite body))
(with-slots (attrs) (root-component current-state)
diff --git a/test/newui-tests.lisp b/test/newui-tests.lisp
new file mode 100644
index 0000000..c00b73d
--- /dev/null
+++ b/test/newui-tests.lisp
@@ -0,0 +1,91 @@
+(defpackage murja.tests.newui
+ (:use :cl :fiveam :murja.newui)
+ (:import-from :murja.tests :prepare-db-and-server :drakma->string :url :main-suite :prepare-db-and-server))
+
+(in-package :murja.tests.newui)
+
+(in-suite main-suite)
+
+;; testaa sulkeutuvien tagien sulkeutuminen
+;; html:n doctypet, että niitä on vain 1 kerran, ei enempää ei vähempää
+
+
+;; https://rosettacode.org/wiki/Count_occurrences_of_a_substring#Common_Lisp
+(defun count-sub (str pat)
+ (loop with z = 0 with s = 0 while s do
+ (when (setf s (search pat str :start2 s))
+ (incf z) (incf s (length pat)))
+ finally (return z)))
+
+(def-test html-generator-tests ()
+ ;; basic html transformations
+ (is (string= (render (c :p (:id "lol") "Sisältö"))
+ "
+<P ID=\"lol\">
+ Sisältö
+</P>
+"))
+
+ ;; children are rendered somewhat sensibly
+ (is (string= (render (c :body ()
+ (c :h1 (:id "lol" :class "header") "HEADER")
+ (c :article (:id "lol2") "article")))
+ "
+<BODY>
+
+<H1 ID=\"lol\" CLASS=\"header\">
+ HEADER
+</H1>
+
+<ARTICLE ID=\"lol2\">
+ article
+</ARTICLE>
+
+</BODY>
+"))
+
+ ;; with-state doesn't screw up rendering
+ (is (string= (render (c :body ()
+ (c :h1 (:id "lol" :class "header") "HEADER")
+ (with-state ((example-variable "Example content")) (:root-id "testitila")
+ (c :article (:id "lol2") example-variable))))
+ "
+<BODY>
+
+<H1 ID=\"lol\" CLASS=\"header\">
+ HEADER
+</H1>
+
+<ARTICLE ID=\"idtestitila\" ID=\"lol2\">
+ Example content
+</ARTICLE>
+
+</BODY>
+"))
+
+ ;; basic with-state renders too
+ (is (string= (render (with-state ((example-variable "Example content")) (:root-id "testitila")
+ (c :article (:id "lol2") example-variable)))
+ "
+<ARTICLE ID=\"idtestitila\" ID=\"lol2\">
+ Example content
+</ARTICLE>
+"))
+
+
+ ;; doctype tests
+ (let ((html-result (render (c :html (:lang "en") (c :body () (c :p () "Testing"))))))
+ (is (equalp 1 (count-sub html-result "DOCTYPE html"))))
+
+ ;; :link is rendered as <link .../> instead of <link> ... </link>
+
+ (is (string= "<LINK HREF=\"/resources/murja.css\" REL=\"stylesheet\" TYPE=\"text/css\" />"
+ (render (c :link (:href "/resources/murja.css" :rel "stylesheet" :type "text/css") "random child that shouldn't be")))))
+
+
+
+
+
+
+;; (fiveam:explain!
+;; (fiveam:run 'html-generator-tests))