Content Rendering
Page Rendering
These functions can be used during rendering to retrieve an information about the page:
reblocks/page:render
generic-functionreblocks/page:render-body
generic-functionreblocks/page:render-dependencies
generic-function
Render protocol first renders the widget tree and
only after that renders page HTML
headers.
Thus you might use setf
on these functions during
widget rendering to change the title, description
or keywords:
If you want to change these variables globally for the whole application, then define a before method like this:
(defmethod reblocks/page:render :before ((app disk-analyzer) inner-html &rest rest)
(declare (ignore rest))
(setf (reblocks/page:get-title)
"Cloud Analyzer - Saves space and money!")
(setf (reblocks/page:get-description)
"Helps to save money when storing data in the Cloud.")
(setf (reblocks/page:get-keywords)
(list "cloud"
"storage"
"analyzer")))
HTML Rendering
Out of the box, Reblocks provides a few facilities for HTML
generation.
They are based on Spinneret
templating engine. Old version of Weblocks used
CL-WHO instead. But Spinneret is more flexible and what is more important,
it escapes content by default, preventing HTML
injection vulnerability.
Most of the time, you only will need a reblocks/html:with-html
macro, which is
similary to Spinneret's one, but binds a few special variables to a stream
to write output to and how to write it:
(reblocks/html:with-html ()
(:ul
(:li "One")
(:li "Two")
(:li "Three")))
;.. <ul>
;.. <li>One
;.. <li>Two
;.. <li>Three
;.. </ul>
;=> NIL
Sometimes you might want to get a HTML
string instead. In this case you might use
reblocks/html:with-html-string
:
cl-transcript
(reblocks/html:with-html-string ()
(:ul
(:li "One")
(:li "Two")
(:li "Three")))
;..
;=> "<ul>
;-> <li>One
;-> <li>Two
;-> <li>Three
;-> </ul>"
You can use any other templating engine, just ensure
it writes output to the reblocks/html:*stream*
variable.
For more advanced UI
, look at the REBLOCKS-UI documentation.
Widget Rendering
For rendering a widget content you have to define a method for reblocks/widget:render
generic-function.
Use reblocks/html:with-html
macro to write HTML
using lisp expression. Under the hood, this macro
uses a great Spinneret library:
(defwidget foo ()
())
(defmethod reblocks/widget:render ((obj foo))
(reblocks/html:with-html ()
(:p "Hello world!")))
Also, any string or object, returned from the render method, will be used to render widget's content. For example, you might do:
(defmethod reblocks/widget:render ((obj foo))
"<b>Hello</b> world!")
But in this case, symbols <
and >
will be escaped and you will not see "Hello" in bold font.
If you don't want to use Spinneret for rendering but want to get HTML
non-escaped, you need to write
HTML
string into the reblocks/html:*stream*
stream like this:
Note, in this case we should explicitly say that our method does not return anything useful:
(defmethod reblocks/widget:render ((obj foo))
(write-string "<b>Hello</b> world!"
reblocks/html:*stream*
)
(values))
This will render "Hello" in bold as desired.
You can use this method for rendering some widgets using template engines other than Spinneret, such as:
https://github.com/mmontone/djula
https://github.com/kanru/cl-mustache
https://github.com/moderninterpreters/markup
Just use engine you like and write it's output to reblocks/html:*stream*
!
Sub-widget Rendering
Reblocks pages are represented by a root widget which can have sub-widgets. Thus we have a widgets trivial-mimes:find-mime.types
To render subwidgets, you have to call reblocks/widget:render
generic-function
on each subwidget insite the widget's reblocks/widget:render
generic-function method:
(defmethod reblocks/widget:render ((obj some-widget))
(reblocks/widget:render (header-widget obj))
(reblocks/widget:render (table-widget obj)))
If you are using reblocks/html:with-html
macro and wrap subwidgets with a custom HTML
tag, then you can use implicit rendering and just pass subwidgets to Spinneret's HTML
tag:
(defmethod reblocks/widget:render ((obj some-widget))
(reblocks/html:with-html ()
(:div :class "flex flex-col"
(header-widget obj)
(table-widget obj))))
This works because Reloblocks defines a method for spinneret:html
generic-function.