Removed Features

During refactoring, I've removed some other interesting conceptions from the core of the framework. They could be reborn as a separate libraries as well as navigation widget.

Views

Views provided convenient ways to define how data object are to be rendered.

Originally, Weblocks supported three types of views:

Form views were especially useful because they let you build forms in a declarative manner, error checking and reporting included.

Views mainly consist of a rendering framework unique to the view and a series of view fields. The table view for example knows how to render a HTML table.

View fields usually map to the slots of your data class but they were flexible enough to be used in any other way. Associated with each view field regardless of the view type are things like a human-readable label and information on how to render the field (presentation).

Form views included additional parameters like how to translate user input to a proper model value (parser) and constraints on the data (satisfies).

Templates

Template were something different from view. It is another layer which allows to customize views look. Most of weblocks code supported templates and this gave us ability to change widget html without changing widget logic.

Templates brought theming functionality into original Weblocks, and intended to improve widgets reusing.

I think it is better to split you render method into a smaller ones and allow user to override these methods. But anyway, here is a short example of how did templated work in old version of the Weblocks.

Note! Following subsections contains only examples and such code is not supported in the latest version of the Weblocks. However you might want to implement something like that on your own or use djula, mustache or other template engine.

Template function

Template function received some key parameters and returned html string. You was able to use any html generation library or template library for templates.

You was encouraged to

Here is a template example.

(defun my-wt (&key (content "I'm template") &allow-other-keys)
    (with-html-to-string 
        (:p (str content))))

Template definition

Template definition is a deftemplate call.

(deftemplate :my-wt 'my-wt)

Here we just connected :my-wt template name with template function 'my-wt.

And here comes most important templates part. We can connect many template functions to template name and only one of them - effective template - will be called. Effectiveness determined by priority which is received from context matchers. Context matcher just receives context and returns priority number.

(defun my-other-wt(&key (content "I'm template") &allow-other-keys)
  (with-html-to-string 
    (:div :class "other-template" (str content))))

(deftemplate :my-wt 'my-other-wt 
  :context-matches (lambda(&rest context)
    100))

my-other-wt has more priority than my-wt so it will be called. And this is how template overriding is done.

There is also :application-class parameter which gives template 10 more priority points.

(deftemplate :page-wt 'my-customized-page-wt 
             :application-class 'my-webapp)

Here 'my-customized-page-wt function will have more priority than one defined in Weblocks.

Note. This context matching logic was too complex and at some places it was intersected with CLOS and generic functions that is why I've decided to exclude templates from the core of the Weblocks.

As an example for the oldschool templating you may see Weblocks Twitter Bootstrap theme.

Footnotes

[1] An acyclic graph with exactly one parent per node.

[2] Đ•ach path component of an URI is a token; for example in "/foo/bar/quux" there are three tokens foo, bar and quux.

[3] I.e. symbols naming a global function and function objects themselves.

Forms

Warning! This section is outdated and belongs to the old Weblocks documention. All widgets, described below, were removed from the core framework. Probably we need only to link to the reblocks-ui here.

Below you'll find a description how did forms work in the original Weblocks. It is given to here to show who one might handle data-models changes. Probably someone will want to resurrect this method in a Weblocks extension library.

Forms enable the user to communicate with a web application.

Usually the server side action boils down to selecting, modifying, creating or deleting data sets (this is sometimes abbreviated as CRUD: Create/Read/Update/Delete)

Building web forms is usually a cumbersome process. Elaborate but complicated solutions have been devised php-quickform, but so far we haven't found any of them to match the ease of use and flexibility of Weblocks' declarative view DSL.

Introduction

The form mechanism consists of two parts, the DATAFORM widget and the FORM-VIEW view type.

Forms are usually built by defining form views using the DEFVIEW macro and instantiating a DATAFORM object with this view.

Simple example

Let's define a view for creating and editing bug reports.

Let the model be defined thus:

(defclass bug-report ()
  ((id :type integer :initform (create-unique-id))
   (status :type (member :new :open :resolved) :initform :new)
   (summary :type string)
   (body :type string)))

This view should apply to users that are not developers: they may enter a summary and body but that's it.

(defview bug-report-form-view
    (:type form :inherit-from '(:scaffold bug-report)
     :caption "Enter a bug report")
  (id :hidep t)
  (status :hidep t))

The SUMMARY and BODY fields will default to strings; every form field is presented as a text input and parsed as a string by default.

Let's use this view to derive the view for developers:

(defview bug-report-form-view/developer
    (:type form :inherit-from 'bug-report-form-view )
  (status :hidep nil))

The status field will automatically be displayed as a dropdown control since the scaffold inspector has decided this upon the slot's type.

You can define scaffolding rules for your own types.

As part of the validation process Weblocks will also check whether a user input matches the slot's type regardless of whether you use scaffolding or not.

But let's assume that we want custom labels for the dropdown:

(defview bug-report-form-view/developer
    (:type form :inherit-from 'bug-report-form-view )
  (status :hidep nil
          :present-as (dropdown :choices '(("This report is totally new, don't trust it!" . :new)
                                           ("Yeah okay, we're working on it." . :open)
                                           ("We've solved that problem already..." . :resolved)))))

Quickforms

Quickforms are specialized Dataforms.

They provide a way to build forms based entirely on a view; they are handy for operations where you don't have the user working on an actual model instance.

Let's dive right into it:

(make-quickform 
  (defview nil 
    (:caption "A Quickform" :type form :persistp nil)
    (some-text  :present-as input))
  :on-success (lambda (form data)
    (with-html 
      "Submitted data - "
      (str (slot-value data 'some-text)))))

This will display form with single field. After form submit we'll see text with value submitted. DATA object here is a class created dynamically from view fields.

:persistp nil

in view definition is necessary, we don't want dynamic class to persist.

There are options in MAKE-QUICKFORM for validation, control flow and other things. See MAKE-QUICKFORM documentation.

Continuations-based tools

Warning! Continuations support support was removed in the Reblocks fork.

This feature will reborn as a separate library with a custom widget class.