Content Rendering

Page Rendering

These functions can be used during rendering to retrieve an information about the page:

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:

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.