This is the caveman2-widgets Reference Manual, version 0.5, generated automatically by Declt version 4.0 beta 2 "William Riker" on Sun Dec 08 16:34:18 2024 GMT+0.
caveman2-widgets/caveman2-widgets.asd
caveman2-widgets/src/util.lisp
caveman2-widgets/src/widget.lisp
caveman2-widgets/src/callback-widget.lisp
caveman2-widgets/src/default-widgets.lisp
caveman2-widgets/src/login.lisp
caveman2-widgets/src/document.lisp
caveman2-widgets/src/navigation.lisp
caveman2-widgets/src/caveman2-widgets.lisp
The main system appears first, followed by any subsystem dependency.
caveman2-widgets
Weblocks like widgets for caveman2.
Richard Paul Bäck
LLGPL
* caveman2-widgets
** What is it
caveman2-widgets is an extension library to [[https://github.com/fukamachi/caveman][caveman2]]. It is influenced
by [[https://github.com/skypher/weblocks][Weblocks]] and introduces its widget system for the developer. By
only using its widget concept it does not control the developer as
much as Weblocks itself. For people who don’t now Weblocks’ approach:
the developer can create web applications (more) like a normal GUI
application by using subclassable widgets which can have callbacks and
their like. Each Widget is only responsible for its own content but
might interfere with other objects through a given context.
#+LATEX: \\\\
But the really cool part is that the framework automatically creates
your site for dynamically (JavaScript based) access *and* normal
access. For the dynamic approach this means that you don’t have to
manage or even care to refresh parts of your website, because widgets
can do that by themselves!
#+CAPTION: Quick overview where caveman2-widgets is in the caveman2 ecosystem
#+ATTR_LATEX: :width 10cm
#+LABEL: fig:overview
[[overview.jpg]]
** Installation
You can use caveman2-widgets with Quicklisp!
#+BEGIN_SRC lisp
(ql:quickload :caveman2-widgets)
#+END_SRC
If you want to contribute or be always up to date you can clone this
git-repository into "~/quicklisp/local-projects" or (if you are using
[[https://github.com/roswell/roswell][Roswell]]) "~/.roswell/local-projects" to QUICKLOAD it.
** See also
- [[https://github.com/ritschmaster/caveman2-widgets-bootstrap][caveman2-widgets-bootstrap]] :: Introduces new widgets that use
[[https://getbootstrap.com/][Bootstrap]].
- [[https://github.com/ritschmaster/caveman2-widgets-blog][caveman2-widgets-blog]] :: An example application to demonstrate
caveman2-widgets
** Websites running caveman2-widgets
- [[https://free-your-pc.com][Free-your-PC]] :: My personal website where I have among others a web
shop
Let me know if you use it too, to include you here!
** Contributions
You are very welcomed to contribute to this project! You can contribute by:
- Using it and spreading the word!
- Finding flaws and submitting [[https://github.com/ritschmaster/caveman2-widgets/issues][Issues]].
- Finding flaws and removing them (as [[https://github.com/ritschmaster/caveman2-widgets/pulls][Pull-requests]]).
- Adding new features (as [[https://github.com/ritschmaster/caveman2-widgets/pulls][Pull-requests]]). Before shooting in the dark
create either an [[https://github.com/ritschmaster/caveman2-widgets/issues][Issues]] or mail me. Maybe your feature is on my
agenda too.
- Showing your appreciation through a donation (please mail me for my
IBAN). It may be a donation in kind too! Via PayPal you can donate
to: richard.baeck@free-your-pc.com
If you add new features, please document them. Otherwise other
developers will have a hard time using this framework.
** Usage
*** General
The only important thing is to run the function INIT-WIDGETS with an
<APP>. If you use caveman’s MAKE-PROJECT function you will get file
called "src/web.lisp". In this file you can adapt the following:
#+BEGIN_SRC lisp
(defpackage my-caveman2-webapp.web
(:use :cl
:caveman2
:caveman2-widgets ;; easy use of the external symbols of this project
:my-caveman2-webapp.config
:my-caveman2-webapp.view
:my-caveman2-webapp.db
:datafly
:sxql)
(:export :*web*))
;; some other code
;; the following will be generated through MAKE-PROJECT but is very important:
(defclass <web> (<app>) ())
(defvar *web* (make-instance ’<web>))
(clear-routing-rules *web*)
;; the neccessary call to initialize the widgets:
(init-widgets *web*)
;; from now on you can do whatever you want
#+END_SRC
*If you create objects from your widget classes, then please always
use the MAKE-WIDGET function!* This method should be used, since it
does all the background stuff for you.
*** Global scope
There are two scopes: /global/ and /session/. The global scope
"limits" the widget to *all* users. Therefore if you create a stateful
widget the state will be displayed to all users of your site. Use
MAKE-WIDGET with :GLOBAL to get a globally scoped widget.
#+LATEX: \\\\
A very simple example of what you can do with it:
#+BEGIN_SRC lisp
(defclass <global-widget> (<widget>)
((enabled
:initform nil
:accessor enabled)))
(defmethod render-widget ((this <global-widget>))
(if (enabled this)
"<h1>enabled!</h1>"
"<h1>not enabled</h1>"))
(defvar *global-widget* (make-widget :global ’<global-widget>))
(defroute "/" ()
(render-widget *global-widget*))
(defroute "/disable" ()
(setf (enabled *global-widget*) nil)
"disabled it")
(defroute "/enable" ()
(setf (enabled *global-widget*) t)
"enabled it")
#+END_SRC
A good practice to create disposable widgets is to mark
them :GLOBAL. In the following example the widget will be created when
a user connects and will afterwards immediately be destroyed again by
the garbage collector.
#+BEGIN_SRC lisp
(defroute "/" ()
(render-widget
(make-widget :global ’<string-widget>
:text "Hello world!"))
#+END_SRC
*** Session scope
The other option is to use a /session/ scope. This is a bit more
tricky because all your /session/ widgets must be stored within the
session (but not as user of this framework). :SESSION is the keyword
for MAKE-WIDGET to get a /session/ widget. Of course you only need to
save the top level (highest) widget of a widget tree in the session
(the children will be saved where the parent is). A short overview of
the functions:
- SET-WIDGET-FOR-SESSION :: Saves a widget in the session
variable. This should be considered ONLY for session scoped
widgets.
- GET-WIDGET-FOR-SESSION :: Gets a previously saved widget from the
session variable (e.g. to render it).
- REMOVE-WIDGET-FOR-SESSION :: Removes a saved widget from the session
variable.
An example (with children):
#+BEGIN_SRC lisp
(defclass <display-id-widget> (<widget>)
())
(defmethod render-widget ((this <display-id-widget>))
(concatenate ’string
"<h3>display-id-widget id: <a href=\"/rest/display-id-widget?id="
(caveman2-widgets.widget::id this)
"\">"
(caveman2-widgets.widget::id this)
"</a></h3>"))
(defclass <session-widget> (<widget>)
((id-widget
:initform (make-widget :session ’<display-id-widget>)
:reader id-widget)))
(defmethod render-widget ((this <session-widget>))
(concatenate ’string
"<h1>The id of your widget</h1>"
"<h2>It should be different for each session</h2>"
"<p>My id: <a href=\"/rest/session-widget?id="
(caveman2-widgets.widget::id this)
"\">"
(caveman2-widgets.widget::id this)
"</a></p>"
(render-widget (id-widget this))))
(defroute "/" ()
(set-widget-for-session :session-widget
(make-widget :session ’<session-widget>))
(concatenate ’string
"<head>
<script src=\"https://code.jquery.com/jquery-2.2.2.min.js\" type=\"text/javascript\"></script>
<script src=\"/widgets/js/widgets.js\" type=\"text/javascript\"></script>
</head>"
(render-widget
(get-widget-for-session :session-widget))
(render-widget
(make-widget :global ’<button-widget>
:label "Reset session"
:callback #’(lambda ()
(remove-widget-for-session
:session-widget))))))
(defroute "/reset-session" ()
(remove-widget-for-session :session-widget)
"reset your session")
#+END_SRC
*** Some default widgets and layouts
There are some helpful default widgets which may help you with your
code organisation. These are:
- <COMPOSITE-WIDGET> :: A layout which contains widgets that will be rendered
vertically.
- <HCOMPOSITE-WIDGET> :: A layout like the <COMPOSITE-WIDGET> but renders the
widgets horizontally.
- <BORDER-WIDGET> :: A layout which features sections to put widgets
in. Please note that this widget has styles in
*/static/css/widgets.css*.
- <STRING-WIDGET> :: A widget which renders only a string.
- <FUNCTION-WIDGET> :: A widget which uses a supplied function for
rendering. Therefore the supplied function has to return a
string!
A simple example:
#+BEGIN_SRC lisp
(defroute "/composite" ()
(with-html-document
(doc
(make-instance ’<header-widget>))
(setf (body doc)
(make-widget
:global ’<border-widget>
:east (make-widget :global ’<string-widget>
:text "<h2>Hello from east</h2>")
:center
(make-widget
:global ’<hcomposite-widget>
:widgets (list
(make-widget :global ’<string-widget>
:text "<h1>Hello from left</h1>")
(make-widget :global ’<function-widget>
:function
#’(lambda ()
"<h1>Hello from the mid</h1>"))
(make-widget :global ’<string-widget>
:text "<h1>Hello from right</h1>")))
:west (make-widget :global ’<string-widget>
:text "<h2>Hello from west</h2>")))))
#+END_SRC
*** Buttons and links
You can use buttons and links that call specific functions. When you
create a button/link only for a session the created route will be
guarded. Therefore only the user with the associated route may
actually access his button.
#+LATEX: \\\\
For each button there will be an URI like "/buttons/BUTTONID". You can
access buttons via POST only. Links get a URI like "/links/LINKID" and
can be accessed either by GET (get a redirect to the stored link) or
by POST (return only the value of the link). In any case the callback
function gets called - please keep that in mind.
#+LATEX: \\\\
If the return value of the link matches the current path then the side
will be reloaded entirely or, if JavaScript is enabled, the dirty
widgets will be reloaded. Please leave out the starting "/" If you
want to address a target on the localhost. E.g. you are on the page
"/test", then return "test" if you want to stay on it.
#+LATEX: \\\\
The BUTTONID and LINKID are the ID slots of the widget - which is
default a symbol generated by GENSYM. But you can change that by
giving your <CALLBACK-WIDGET> a specific ID (like in the example
below). This will ensure that the route will persist otherwise the
route for the <CALLBACK-WIDGET> will change with every restart of your
website or with every new session (depends on the scope). *Be careful,
the ID must be unique on object level, otherwise you overwrite
routes!*
#+LATEX: \\\\
An example:
#+BEGIN_SRC lisp
(defvar *got-here-by-link* nil)
(defroute "/otherpage" ()
(if *got-here-by-link*
(progn
(setf *got-here-by-link* nil)
"<h1>Got here by pressing the link</h2>")
"<h1>Got here by yourself</h2>"))
(defroute "/link-test" ()
(concatenate ’string
(render-widget
(make-widget :global ’<link-widget>
:label "Github"
:callback #’(lambda (args)
(format t "LOG: Link clicked!")
"http://github.com/ritschmaster")
:target-foreign-p t ;; The link goes out of this domain
))
(render-widget
(make-widget :global ’<link-widget>
:label "Otherpage"
:id "otherpage" ;; href="/links/otherpage"
:callback #’(lambda (args)
(setf *got-here-by-link* t)
"/otherpage")
:target-foreign-p t ;; The link goes out of this domain
))
(render-widget
(make-widget :global ’<button-widget>
:label "Button"
:callback #’(lambda (args)
(format t
"LOG: Button clicked!"))))))
#+END_SRC
You can create your own callback widgets too. Just look at the
<CALLBACK-WIDGET>, <BUTTON-WIDGET> classes for that.
*** Use caveman2-widgets for your entire HTML document
To make your life really easy you can create an entire HTML
document. You can either tinker your own widgets or whatever with the
<HMTL-DOCUMENT-WIDGET> and the <HEADER-WIDGET> or you can use the
handy WITH-HTML-DOCUMENT macro.
#+BEGIN_SRC lisp
(defclass <root-widget> (<body-widget>)
())
(defmethod render-widget ((this <root-widget>))
"Hello world!")
(defclass <otherpage-widget> (<body-widget>)
())
(defmethod render-widget ((this <otherpage-widget>))
"Hello from the other page!")
(defvar *header-widget* (make-instance ’<header-widget>
;; the title when this header is used
:title "Widgets test"
;; the icon when this header is used
:icon-path "/images/icon.png"
;; the following lines will be rendered in the header:
:other-header-content
’("<meta name=\"author\" content=\"Richard Bäck\">"))
(defvar *root-widget* (make-widget :global ’<root-widget>))
(defvar *otherpage-widget* (make-widget :global ’<otherpage-widget>))
(defroute "/" ()
;; The *root-widget* can be accessed under:
;; /rest/root-widget?id=(caveman2-widgets.widget::id *root-widget*)
(render-widget
(make-instance ’<html-document-widget>
;; sets this specific header for this page
:header *header-widget*
:body *root-widget*)))
(defroute "/otherpage" ()
(with-html-document (doc
*header-widget*)
(setf (body doc)
*otherpage-widget*)))
#+END_SRC
*** Marking widgets dirty
You can mark specific widgets as dirty with the function
MARK-DIRTY. This means that they will be reloaded dynamically (if the
user has JavaScript is enabled). Please notice that you can mark *any*
widget as dirty. Therefore you can order JavaScript to reload global
widgets and sessioned widgets.
#+LATEX: \\\\
An example:
#+BEGIN_SRC lisp
(defclass <sessioned-widget> (<widget>)
((enabled
:initform nil
:accessor enabled)))
(defmethod render-widget ((this <sessioned-widget>))
(concatenate ’string
"<h2>Sessioned-widget:</h2>"
(if (enabled this)
"<h3>enabled!</h3>"
"<h3>not enabled</h3>")))
(defclass <my-body-widget> (<widget>)
())
(defmethod render-widget ((this <my-body-widget>))
(concatenate ’string
"<h1>MARK-DIRTY test</h1>"
(render-widget
(get-widget-for-session :sessioned-widget))
(render-widget
(make-widget
:global ’<button-widget>
:label "Enable"
:callback #’(lambda ()
(let ((sessioned-widget
(get-widget-for-session :sessioned-widget)))
(when sessioned-widget
(setf (enabled sessioned-widget) t)
(mark-dirty sessioned-widget))))))
(render-widget
(make-widget
:global ’<button-widget>
:label "Disable"
:callback #’(lambda ()
(let ((sessioned-widget
(get-widget-for-session :sessioned-widget)))
(when sessioned-widget
(setf (enabled sessioned-widget) nil)
(mark-dirty sessioned-widget))))))))
(defvar *header-widget* (make-instance ’<header-widget>
:title "Mark-dirty test"))
(defvar *my-body-widget* (make-widget :global ’<my-body-widget>))
(defroute "/mark-dirty-test" ()
(set-widget-for-session :sessioned-widget (make-widget :session ’<sessioned-widget>))
(render-widget
(make-instance ’<html-document-widget>
:header *header-widget*
:body *my-body-widget*)))
#+END_SRC
*** Navigation objects
You can create navigation objects too! The purpose of navigation
objects is that you don’t have to manage a navigation ever again!
Each navigation object contains another widget which displays the
currently selected path. If you click on a navigation link that object
is changed and refreshed (either via JavaScript or through the
link). Please keep in mind that navigation objects are *session
stateful widgets*.
#+LATEX: \\\\
Paths are only created automatically by the DEFNAV macro. The first
item in the list is the widget which will be displayed at the base
path of the navigation. You can use any string as path but be careful
to not interfere with the special paths of NINGLE
(e.g. "/:some-path"). Do not use those. The only special path you can
use is the wildcard (e.g "/*/").
#+LATEX: \\\\
A very basic example:
#+BEGIN_SRC lisp
(defvar *first-widget*
(make-widget :global ’<string-widget>
:text "<h1>Hello world from first</h1>"))
(defvar *second-widget*
(make-widget :global ’<string-widget>
:text "<h1>Hello world from second</h1>"))
(defclass <proxy-widget> (<widget>)
()
(:documentation "This class enables session based widgets for a
navigation."))
(defmethod render-widget ((this <proxy-widget>))
(set-widget-for-session :string-widget
(make-widget :session ’<string-widget>
:text "hello world"))
(render-widget (get-widget-for-session :string-widget)))
(defnav "/sophisticated/path"
((make-instance ’<header-widget>
:title "Navigation test")
(list
(list "First widget" "first" *first-widget*)
(list "Second widget" "second" *second-widget*)
(list "Third widget" "third" (make-widget :global
’<proxy-widget>))
(list "Hidden widget" "hidden"
(make-widget :global ’<string-widget>
:text "<h1>You have accessed a hidden widget!</h1>")
:hidden))
:kind ’<menu-navigation-widget>))
#+END_SRC
If the default navigation object doesn’t render as you wish, you can
subclass it and overwrite the RENDER-WIDGET method. Please notice that
you can actually very easily adjust the path where the navigation and
its widgets get rendered. The slot BASE-PATH is created for that.
#+LATEX: \\\\
There are two default navigation widgets:
- <MENU-NAVIGATION-WIDGET> :: A navigation with a menu. You can change
the menu appearance with CSS. With the :HIDDEN keyword you can
hide a path from the navigation list.
- <BLANK-NAVIGATION-WIDGET> :: A navigation without any menu. It is
controlled by the URL only - or by other widgets.
*** Table objects
You can create a table very simple. A <TABLE-WIDGET> displays *all*
items which are supplied through the PRODUCER function.
#+LATEX: \\\\
Important for the usage of tables is that you supply a PRODUCER
function. The function should return a list of <TABLE-ITEM>
objects. This function can be anything but it has to take the key
arguments:
- AMOUNT :: Tells how many items to get
- ALREADY :: Tells how many items already received
- LENGTH-P :: A flag which should tell the function to return the
available items if active.
AMOUNT and ALREADY can be seen as synonyms for FROM and TO.
#+LATEX: \\\\
A <TABLE-ITEM> object is needed for tables. The essence of those
objects is that they can be translated to lists through the generic
function GET-AS-LIST. Therefore you don’t have to subclass
<TABLE-ITEM> at all just to add an implementation of GET-AS-LIST for
your used class.
#+LATEX: \\\\
For the <TABLE-Widget> consider the following example:
#+BEGIN_SRC lisp
(defclass <my-item> (<table-item>)
((id
:initarg :id
:reader id)
(name
:initarg :name
:reader name)
(description
:initarg :description
:reader description)))
(defmethod get-as-list ((this <my-item>))
(list :id (id this)
:name (name this)
:description (description this)))
(defun producer (&key
amount
(already 0)
(length-p nil))
(if (null length-p)
(let ((all ’()))
(if (null amount)
(loop for x from 1 to 1000 do
(setf all
(append all
(list
(make-instance ’<my-item>
:id x
:name (format nil "~a" x)
:description (format nil "The ~a. item." x))))))
(loop for x from (+ already 1) to (+ already amount) do
(setf all
(append all
(list
(make-instance ’<my-item>
:id x
:name (format nil "~a" x)
:description (format nil "The ~a. item." x)))))))
all)
1000))
(defvar *table-widget*
(make-widget :global ’<table-widget>
:producer ’producer
:column-descriptions (list
(list :name "Name")
(list :description "Description"))))
(defroute "/table" ()
(with-html-document (doc
(make-instance ’<header-widget>))
(setf (body doc)
*table-widget*)))
#+END_SRC
*** Viewgrids
The <VIEWGRID-WIDGET> is used to display a bulk of heterogenous
items. The items must implement the RENDER-AS method. The
<VIEWGRID-WIDGET> calls RENDER-AS with its VIEW slot. Therefore you
have provide an implementation for the keyword supplied by VIEW in
your <VIEWGRID-WIDGET>.
#+LATEX: \\\\
You can limit the displayed items with the MAX-ITEMS-TO-DISPLAY
slot. If this slot is active the items are delivered on several pages
instead on only one. If you supply additionally the DISPLAY-SELECTOR
with the URI path on which the <VIEWGRID-WIDGET> object is rendered,
then selectable page numbers are displayed on the bottom too.
#+LATEX: \\\\
Each item can be accessed. When accessing the item a specific
given function is called with the item as parameter.
#+LATEX: \\\\
The following example covers all functionality:
#+BEGIN_SRC lisp
(defclass <my-viewgrid-item> (<viewgrid-item>)
((id
:initarg :id
:reader id)
(name
:initarg :name
:reader name)
(description
:initarg :description
:reader description)))
(defmethod render-as ((this <my-viewgrid-item>) (view (eql :short)))
(format nil "<div style=\"padding-bottom:30px\">id: ~a<br>name: ~a<br>desc: ~a<div>"
(id this) (name this) (description this)))
(defun producer (&key
(from 0)
(to nil)
(length-p nil))
(let ((all ’()))
(loop for x from 1 to 35 do
(setf all
(append all
(list
(make-instance ’<my-viewgrid-item>
:id x
:name (format nil "~a" x)
:description (format nil "The ~a. item." x))))))
(cond
(length-p
(length all))
((and from (not to))
(mapcan #’(lambda (item)
(if (>= (id item) from)
(list item)
nil))
all))
((and from to)
(mapcan #’(lambda (item)
(if (and (>= (id item) from) (< (id item) to))
(list item)
nil))
all)))))
(defroute "/viewgrid" ()
(with-html-document (doc
(make-instance ’<header-widget>))
(set-widget-for-session
:viewgrid
(make-widget :session ’<viewgrid-widget>
:producer #’producer
:view :short
:max-items-to-display 11
:display-selector "viewgrid"
:on-view #’(lambda (item)
(format t
(render-as item :short))
"viewgrid")))
(setf (body doc)
(get-widget-for-session :viewgrid))))
#+END_SRC
*** Forms
Forms can be pretty annoying but with the <FORM-WIDGET> you don’t have
to care for anything but for the naming of the inputs ever again. Each
<FORM-WIDGET> consists of 0 to n <FORM-FIELD> objects. If you have 0
<FORM-FIELD> objects it essentially only behaves like a
<BUTTON-WIDGET>.
#+LATEX: \\\\
<FORM-FIELD> is the base class for fields. Fields can be:
- <INPUT-FIELD> :: Is basically an abstraction of the HTML input-tag.
- <SELECT-FIELD> :: Consists of <OPTION-FIELD> objects.
Of course you can implement your own <FORM-FIELD> classes too! But
keep in mind that *the default <FORM-FIELD> already implements
constraints*.
#+LATEX: \\\\
To understand how constraints for forms work an examination of the
available slots for <FORM-FIELD> objects is necessary:
- REQUIRED :: A non-nil value indicates that this field has to have
some value.
- SUPPLIED :: Will be set NIL by SET-REQUIRED-PRESENT and set T by
RENDER-WIDGET. It is NIL if the field is not supplied
and is therefore not dependent on REQUIRED. It should
tell the server whether an parameter was passed or not.
- CHECK-FUNCTION :: Will be called by SET-REQUIRED-PRESENT and check
if the passed value by the client is "correct". It
is a lambda with one argument, which is the passed
string from the client. Should return NIL if the
passed string was not correct and a non-nil value
otherwise.
- ERROR-HAPPENED :: Will be set to T by SET-REQUIRED-PRESENT if the
CHECK-FUNCTION did not succeed. The rendering the
form will set it to NIL again.
- ERROR-MESSAGE :: The message that will be displayed if
ERROR-HAPPENED is T.
You don’t have to actually care for that procedure as the
<FORM-WIDGET> calls this the SET-REQUIRED-PRESENT by itself. But it
can be helpful to understand the entire process of checking the user
input. The only thing to really memorize here is that *the given
callback only gets called if all required fields where supplied and
those fields where supplied correctly*.
#+LATEX: \\\\
Consider the following example for additional help:
#+BEGIN_SRC lisp
(defvar *password-field*
(make-instance ’<input-field>
:input-type "password"
:check-function
#’(lambda (pass)
(if (<= (length pass)
2)
nil
t))
:error-message "Has to be longer than 2"
:name "password"
:value ""))
(defvar *form-widget*
(let ((text-field (make-instance ’<input-field>
:input-type "text"
:name "text"
:value ""
:required t))
(choice-field (make-instance
’<select-field>
:name "selection"
:options
(list (make-instance ’<option-field>
:value "first")
(make-instance ’<option-field>
:value "second"
:display-value "Other")))))
(make-widget :global ’<form-widget>
:input-fields (list
text-field
*password-field*
choice-field)
:label "Submit"
:callback
#’(lambda (args)
(format t "received correct values:
~a
————-"
args)))))
(defroute "/form" ()
(with-html-document (doc
(make-instance ’<header-widget>))
(setf (body doc)
*form-widget*)))
#+END_SRC
*** Protecting widgets
This library also enables you to protect widgets. Each widget has an
associated list of keywords which indicate the levels/circles of
authorization an requester needs.
#+LATEX: \\\\
By default the protection is an empty list (therefore NIL), which
means that everybody can access your widget. If the protection is
non-nil the non-nil value is a list of keywords which refers to a list
of keywords stored in the session. So if the session contains the
required keyword in its list the requester can access the
widget. Otherwise he is denied (throws a 403 code).
#+LATEX: \\\\
The <WIDGET> class holds the PROTECTED slot. This slots value
indicates the needed token in the session. But caveman2-widgets
supplies an additional, specific *PROTECT-WIDGET* method which should be
used. You can supply the following parameters:
- :LOGIN :: Protects the widget by the default login-widget
- A keyword in general :: Protects the widget with this keyword (adds
it)
- A list of keywords :: Protects the widget with this keywords (adds
them)
#+BEGIN_SRC lisp
(defvar *specific-protected-widget*
(protect-widget
(make-widget :global ’<string-widget>
:text "<h1>This is a protected text</h1>")
:myprotection))
;; Should throw 403
(defroute "/protected-widget" ()
(concatenate ’string
"<a href=\"/rest/string-widget?id="
(id *specific-protected-widget*)
"\">Will throw 403</a>"
(render-widget *specific-protected-widget*)))
(defmethod on-exception ((app <web>) (code (eql 403)))
(declare (ignore app))
"403 - The protection works.")
#+END_SRC
*** Login
Protecting certain widgets by a login is very easy. The <LOGIN-WIDGET>
organizes the following things:
1. It displays a login form and logs the client in if he passes the
challenge. The successful pass sets will result in an permanent
non-nil value if you call "(LOGGED-IN *SESSION*)". This means that
every widget that requires the authroization level :LOGIN through
the PROTECT-WIDGET method can now be accessed by the user.
2. It supplies a Logout button. This button can be access through the
LOGOUT-BUTTON reader. You therefore can render the button anywhere
you like. Pressing the button will result in a logout and therefore
in a permanent NIL for "(LOGGED-IN *SESSION*)".
3. It renders certain widgets if the login was successful. This can be
either used e.g. for a success message.
*The <LOGIN-WIDGET> has to run in :SESSION scope!*
#+LATEX: \\\\
Additionally you can specify different authentication challanges
(authentication functions) if you wish. But using the <LOGIN-WIDGET>
and passing the challenge will *only* set the authoriatzition level
to :LOGIN. This means that you need to create your own <LOGIN-WIDGET>
if you want some other level for different authentication functions!
#+BEGIN_SRC lisp
(defvar *protected-widget*
(protect-widget
(make-widget :global ’<string-widget>
:text "<h1>This is a protected text</h1>")
:login))
(defroute "/" ()
(with-html-document (doc
(make-instance ’<header-widget>))
(setf (body doc)
(make-widget
:global ’<function-widget>
:function
#’(lambda ()
(set-widget-for-session ;; running it in the session
:login-widget
(make-widget :session ’<login-widget>
:authenticator
#’(lambda (user password)
(if (and (string= user "ritschmaster")
(string= password "secret"))
t
nil))
:widgets
(list
*protected-widget*)))
(render-widget
(get-widget-for-session :login-widget)))))))
#+END_SRC
*** Language getting/setting
To store the accpeted languages in the session there is the
CHECK-AND-SET-LANGUAGE function. This function uses the value supplied
through the "Accept-languages" field in the HTTP request. It gets
called through the render method by any <HTML-DOCUMENT-WIDGET>
automatically. Which means that as soon as you use it you don’t have
to worry about getting the language. But on the other hand you have to
make sure that every subclass of <HTML-DOCUMENT-WIDGET> again uses
CHECK-AND-SET-LANGUAGE in its render-method.
#+LATEX: \\\\
You can access the currently accepted languages through the
ACCEPTED-LANGUAGES.
#+LATEX: \\\\
If you rather use a manual language chooser you can supply
AUTOMATICALLY-SET-LANGUAGES as NIL to the INIT-WIDGETS
function. Please then use the setf method for ACCEPTED-LANGUAGES to
set the language.
*** Translations
Most strings that are rendered human readable get translated through a
special function. You can specify your own translation function by
passing it to INIT-WIDGETS as :TRANSLATION-FUNCTION. The function
header should look like this:
#+BEGIN_SRC lisp
(defvar *my-translation-function*
#’(lambda (text
&key
plural-p
genitive-form-p
items-count
accusative-form-p
language
&allow-other-keys)
text))
#+END_SRC
Strings that are translated:
- The page names of a navigation
Strings that are definitely *not* translated:
- The TEXT of a <STRING-WIDGET>
- The return value of a <FUNCTION-WIDGET>
*** Development hooks
In case you want to do things at compile time (e.g. calling DEFROUTE)
whe INIT-WIDGETS is evaluated there is the variable
*INIT-WIDGETS-HOOKS*. Just append new functions as you wish.
#+BEGIN_SRC lisp
(setf *init-widgets-hooks*
(append
*init-widgets-hooks*
(list
#’(lambda ()
(defroute "/something" ()
;; Accessing the user supplied <APP> object:
(describe caveman2-widgets::*web*)
"something")))))
#+END_SRC
** Important notes/Things that happen automatically
The following things you should keep in mind when using
caveman2-widgets.
*** Automatically REST API creation
If you create a widget then routes for a REST API will be added
automatically. Suppose you subclass <WIDGET> with the class
<MY-WIDGET>, then you will get the path "/rest/my-widget" which you
can access.
#+BEGIN_SRC lisp
(defclass <my-widget> (<widget>)
())
(defmethod render-widget ((this <my-widget>))
"my-widget representation for the website")
(defmethod render-widget-rest ((this <my-widget>) (method (eql :get)) (args t))
"my-widget representation for the REST.")
(defmethod render-widget-rest ((this <my-widget>) (method (eql :post)) (args t))
(render-widget this))
#+END_SRC
Buttons and Links are *not* accessed through the REST path (see the
section above).
Widgets that are not accessible through the REST:
- <HTML-DOCUMENT-WIDGET>
- <HEADER-WIDGET>
*** Encapsulating widgets with divs
Each widget gets wrapped in a div automatically. Every widget will get
its entire class heritage included in the CSS class
attribute. Therefore you can access every widget (and derived widget)
very easily with CSS.
*** JavaScript dependencies
When <HEADER-WIDGET> is used all JavaScript dependencies are added
automatically. Please notice that these dependecies are needed to
ensure that the widgets work properly. If you don’t want to use
<HEADER-WIDGET> you have to manually add jQuery and all the JavaScript
Code supplied/needed by caveman2-widgets.
The routes for the JavaScript files (which have to be included in each
HTML file) are:
- /widgets/js/widgets.js
The jQuery-Version used is 2.2.2 minified. If you want another jQuery
file you can specify it with the variable \*jquery-cdn-link\* (should be
an URL).
*If you forget to use the JavaScript-files widgets might not work or
even break. Most likely all dynamic content just won’t work
(automatically fallback to non-JS)*
*** CSS dependencies
As with JavaScript, stylesheets are added in the <HEADER-WIDGET> automatically
too. The routes you need in your head tag are:
- /widgets/css/widgets.css
*** Session values
This section should inform you about keywords in the session variable
which you should absolutely not modify.
- :WIDGET-HOLDER :: <WIDGET-HOLDER> object. It holds all the session
scoped widgets.
- :DIRTY-OBJECT-IDS :: The name says it all.
- :JAVASCRIPT-AVAILABLE :: Holds a boolean value if JavaScript is
available or not.
- :ACCEPT-LANGUAGE :: Holds the languages accepted by the client.
** Author
+ Richard Paul Bäck (richard.baeck@free-your-pc.com)
** Copyright
Copyright (c) 2016 Richard Paul Bäck (richard.baeck@free-your-pc.com)
** License
Licensed under the LLGPL License.
0.5
trivial-garbage
(system).
moptilities
(system).
caveman2
(system).
src
(module).
Modules are listed depth-first from the system components tree.
caveman2-widgets/src
caveman2-widgets
(system).
util.lisp
(file).
widget.lisp
(file).
callback-widget.lisp
(file).
default-widgets.lisp
(file).
login.lisp
(file).
document.lisp
(file).
navigation.lisp
(file).
caveman2-widgets.lisp
(file).
Files are sorted by type and then listed depth-first from the systems components trees.
caveman2-widgets/caveman2-widgets.asd
caveman2-widgets/src/util.lisp
caveman2-widgets/src/widget.lisp
caveman2-widgets/src/callback-widget.lisp
caveman2-widgets/src/default-widgets.lisp
caveman2-widgets/src/login.lisp
caveman2-widgets/src/document.lisp
caveman2-widgets/src/navigation.lisp
caveman2-widgets/src/caveman2-widgets.lisp
caveman2-widgets/caveman2-widgets.asd
caveman2-widgets
(system).
caveman2-widgets/src/util.lisp
src
(module).
*application-root*
(special variable).
*automatically-set-languages*
(special variable).
*css-directory*
(special variable).
*js-directory*
(special variable).
*language-key-in-session*
(special variable).
*static-directory*
(special variable).
+translate+
(special variable).
accepted-languages
(generic function).
(setf accepted-languages)
(generic function).
append-item
(generic function).
check-and-set-language
(function).
clean-list-of-broken-links
(function).
defroute-static
(function).
delete-item
(generic function).
find-item
(generic function).
get-trimmed-class-name
(function).
get-value-for-cons-list
(function).
has-trailing-slash
(function).
javascript-available
(generic function).
(setf javascript-available)
(generic function).
string-case-insensitive=
(function).
caveman2-widgets/src/widget.lisp
src
(module).
*css-path*
(special variable).
*dirty-objects-uri-path*
(special variable).
*javascript-checker-path*
(special variable).
*javascript-path*
(special variable).
*protection-circles-session-key*
(special variable).
*rest-path*
(special variable).
*web*
(special variable).
*widgets-css-filename*
(special variable).
*widgets-js-filename*
(special variable).
<widget>
(class).
add-authorization
(function).
append-item
(method).
append-item
(method).
authorized
(function).
delete-item
(method).
delete-item
(method).
find-item
(method).
get-widget-for-session
(function).
id
(reader method).
init-mark-dirty
(function).
initialize-instance
(method).
make-widget
(macro).
mark-dirty
(function).
protect-widget
(generic function).
protected
(reader method).
remove-authorization
(function).
remove-widget-for-session
(function).
render-widget
(generic function).
render-widget-body
(generic function).
render-widget-header
(generic function).
render-widget-rest
(generic function).
set-widget-for-session
(function).
widget-scope
(reader method).
*dirty-objects-session-key*
(special variable).
*global-widget-holder*
(special variable).
*rest-methods*
(special variable).
<dirty-widget-holder>
(class).
<widget-holder>
(class).
demark-dirty
(function).
caveman2-widgets/src/callback-widget.lisp
src
(module).
*button-call-path*
(special variable).
*link-call-path*
(special variable).
<button-widget>
(class).
<callback-widget>
(class).
<form-field>
(class).
<form-widget>
(class).
<input-field>
(class).
<link-widget>
(class).
<option-field>
(class).
<radio-field>
(class).
<select-field>
(class).
append-item
(method).
append-item
(method).
append-item
(method).
callback
(reader method).
check-function
(reader method).
(setf check-function)
(writer method).
checked-option
(reader method).
(setf checked-option)
(writer method).
classes
(reader method).
(setf classes)
(writer method).
error-happened
(reader method).
(setf error-happened)
(writer method).
error-message
(reader method).
(setf error-message)
(writer method).
get-from-callback-args
(function).
http-method
(reader method).
initialize-instance
(method).
initialize-instance
(method).
initialize-instance
(method).
input-fields
(reader method).
input-type
(reader method).
label
(reader method).
label
(reader method).
(setf label)
(writer method).
multiple
(reader method).
(setf multiple)
(writer method).
name
(reader method).
options
(reader method).
options
(reader method).
(setf options)
(writer method).
(setf options)
(writer method).
render-widget
(method).
render-widget
(method).
render-widget
(method).
render-widget
(method).
render-widget
(method).
render-widget
(method).
render-widget
(method).
render-widget
(method).
render-widget
(method).
required
(reader method).
(setf required)
(writer method).
supplied
(reader method).
(setf supplied)
(writer method).
uri-path
(reader method).
value
(reader method).
value
(reader method).
*input-field-for-old-uri*
(special variable).
display-value
(reader method).
set-required-present
(generic function).
test-widget-if-session
(function).
caveman2-widgets/src/default-widgets.lisp
src
(module).
<border-widget>
(class).
<composite-widget>
(class).
<function-widget>
(class).
<hcomposite-widget>
(class).
<string-widget>
(class).
<table-item>
(class).
<table-widget>
(class).
<viewgrid-item>
(class).
<viewgrid-widget>
(class).
append-item
(method).
append-item
(method).
column-descriptions
(reader method).
east
(reader method).
(setf east)
(writer method).
fn
(reader method).
(setf fn)
(writer method).
get-as-list
(generic function).
max-items-to-display
(reader method).
(setf max-items-to-display)
(writer method).
north
(reader method).
(setf north)
(writer method).
on-view
(reader method).
(setf on-view)
(writer method).
on-view-label
(reader method).
(setf on-view-label)
(writer method).
render-as
(generic function).
render-widget
(method).
render-widget
(method).
render-widget
(method).
render-widget
(method).
render-widget
(method).
render-widget
(method).
render-widget
(method).
render-widget
(method).
render-widget-body
(method).
render-widget-header
(method).
south
(reader method).
(setf south)
(writer method).
text
(reader method).
(setf text)
(writer method).
view
(reader method).
(setf view)
(writer method).
west
(reader method).
(setf west)
(writer method).
widgets
(reader method).
(setf widgets)
(writer method).
center
(reader method).
(setf center)
(writer method).
display-selector
(reader method).
(setf display-selector)
(writer method).
producer
(reader method).
producer
(reader method).
caveman2-widgets/src/login.lisp
src
(module).
*login-authentication-keyword*
(special variable).
<login-widget>
(class).
initialize-instance
(method).
logged-in
(generic function).
(setf logged-in)
(generic function).
login-authenticator
(reader method).
login-form
(reader method).
logout-button
(reader method).
render-widget
(method).
signout-hook
(reader method).
(setf signout-hook)
(writer method).
login-failed
(reader method).
(setf login-failed)
(writer method).
caveman2-widgets/src/document.lisp
src
(module).
*jquery-cdn-link*
(special variable).
<css-file>
(class).
<header-widget>
(class).
<html-document-widget>
(class).
<js-file>
(class).
append-item
(method).
append-item
(method).
append-item
(method).
body
(reader method).
(setf body)
(writer method).
bottom
(reader method).
(setf bottom)
(writer method).
charset
(reader method).
(setf charset)
(writer method).
crossorigin
(reader method).
(setf crossorigin)
(writer method).
header
(reader method).
(setf header)
(writer method).
icon-path
(reader method).
(setf icon-path)
(writer method).
other-header-content
(reader method).
path
(reader method).
render-widget
(method).
render-widget
(method).
render-widget
(method).
render-widget
(method).
title
(reader method).
(setf title)
(writer method).
with-html-document
(macro).
<file>
(class).
css-files
(reader method).
integrity
(reader method).
(setf integrity)
(writer method).
js-files
(reader method).
caveman2-widgets/src/caveman2-widgets.lisp
src
(module).
*init-widgets-hooks*
(special variable).
init-widgets
(function).
Packages are listed by definition order.
caveman2-widgets.default-widgets
caveman2-widgets.document
caveman2-widgets.util
caveman2-widgets.navigation
caveman2-widgets.login
caveman2-widgets
caveman2-widgets.widget
caveman2-widgets.callback-widget
caveman2-widgets.default-widgets
caveman2
.
caveman2-widgets.callback-widget
.
caveman2-widgets.util
.
caveman2-widgets.widget
.
common-lisp
.
<border-widget>
(class).
<composite-widget>
(class).
<function-widget>
(class).
<hcomposite-widget>
(class).
<string-widget>
(class).
<table-item>
(class).
<table-widget>
(class).
<viewgrid-item>
(class).
<viewgrid-widget>
(class).
column-descriptions
(generic reader).
east
(generic reader).
(setf east)
(generic writer).
fn
(generic reader).
(setf fn)
(generic writer).
get-as-list
(generic function).
max-items-to-display
(generic reader).
(setf max-items-to-display)
(generic writer).
north
(generic reader).
(setf north)
(generic writer).
on-view
(generic reader).
(setf on-view)
(generic writer).
on-view-label
(generic reader).
(setf on-view-label)
(generic writer).
render-as
(generic function).
south
(generic reader).
(setf south)
(generic writer).
text
(generic reader).
(setf text)
(generic writer).
view
(generic reader).
(setf view)
(generic writer).
west
(generic reader).
(setf west)
(generic writer).
widgets
(generic reader).
(setf widgets)
(generic writer).
center
(generic reader).
(setf center)
(generic writer).
display-selector
(generic reader).
(setf display-selector)
(generic writer).
producer
(generic reader).
caveman2-widgets.document
caveman2
.
caveman2-widgets.util
.
caveman2-widgets.widget
.
common-lisp
.
*jquery-cdn-link*
(special variable).
<css-file>
(class).
<header-widget>
(class).
<html-document-widget>
(class).
<js-file>
(class).
body
(generic reader).
(setf body)
(generic writer).
bottom
(generic reader).
(setf bottom)
(generic writer).
charset
(generic reader).
(setf charset)
(generic writer).
crossorigin
(generic reader).
(setf crossorigin)
(generic writer).
header
(generic reader).
(setf header)
(generic writer).
icon-path
(generic reader).
(setf icon-path)
(generic writer).
other-header-content
(generic reader).
path
(generic reader).
title
(generic reader).
(setf title)
(generic writer).
with-html-document
(macro).
<file>
(class).
css-files
(generic reader).
integrity
(generic reader).
(setf integrity)
(generic writer).
js-files
(generic reader).
caveman2-widgets.util
caveman2
.
common-lisp
.
metabang.moptilities
.
*application-root*
(special variable).
*automatically-set-languages*
(special variable).
*css-directory*
(special variable).
*js-directory*
(special variable).
*language-key-in-session*
(special variable).
*static-directory*
(special variable).
+translate+
(special variable).
accepted-languages
(generic function).
(setf accepted-languages)
(generic function).
append-item
(generic function).
check-and-set-language
(function).
clean-list-of-broken-links
(function).
defroute-static
(function).
delete-item
(generic function).
find-item
(generic function).
get-trimmed-class-name
(function).
get-value-for-cons-list
(function).
has-trailing-slash
(function).
javascript-available
(generic function).
(setf javascript-available)
(generic function).
string-case-insensitive=
(function).
caveman2-widgets.login
caveman2
.
caveman2-widgets.callback-widget
.
caveman2-widgets.default-widgets
.
caveman2-widgets.util
.
caveman2-widgets.widget
.
common-lisp
.
*login-authentication-keyword*
(special variable).
<login-widget>
(class).
logged-in
(generic function).
(setf logged-in)
(generic function).
login-authenticator
(generic reader).
login-form
(generic reader).
logout-button
(generic reader).
signout-hook
(generic reader).
(setf signout-hook)
(generic writer).
login-failed
(generic reader).
(setf login-failed)
(generic writer).
caveman2-widgets
*init-widgets-hooks*
(special variable).
init-widgets
(function).
caveman2-widgets.widget
caveman2
.
caveman2-widgets.util
.
common-lisp
.
*css-path*
(special variable).
*dirty-objects-uri-path*
(special variable).
*javascript-checker-path*
(special variable).
*javascript-path*
(special variable).
*protection-circles-session-key*
(special variable).
*rest-path*
(special variable).
*web*
(special variable).
*widgets-css-filename*
(special variable).
*widgets-js-filename*
(special variable).
<widget>
(class).
add-authorization
(function).
authorized
(function).
get-widget-for-session
(function).
id
(generic reader).
init-mark-dirty
(function).
make-widget
(macro).
mark-dirty
(function).
protect-widget
(generic function).
protected
(generic reader).
remove-authorization
(function).
remove-widget-for-session
(function).
render-widget
(generic function).
render-widget-body
(generic function).
render-widget-header
(generic function).
render-widget-rest
(generic function).
set-widget-for-session
(function).
widget-scope
(generic reader).
*dirty-objects-session-key*
(special variable).
*global-widget-holder*
(special variable).
*rest-methods*
(special variable).
<dirty-widget-holder>
(class).
<widget-holder>
(class).
demark-dirty
(function).
caveman2-widgets.callback-widget
caveman2
.
caveman2-widgets.util
.
caveman2-widgets.widget
.
common-lisp
.
*button-call-path*
(special variable).
*link-call-path*
(special variable).
<button-widget>
(class).
<callback-widget>
(class).
<form-field>
(class).
<form-widget>
(class).
<input-field>
(class).
<link-widget>
(class).
<option-field>
(class).
<radio-field>
(class).
<select-field>
(class).
callback
(generic reader).
check-function
(generic reader).
(setf check-function)
(generic writer).
checked-option
(generic reader).
(setf checked-option)
(generic writer).
classes
(generic reader).
(setf classes)
(generic writer).
error-happened
(generic reader).
(setf error-happened)
(generic writer).
error-message
(generic reader).
(setf error-message)
(generic writer).
get-from-callback-args
(function).
http-method
(generic reader).
input-fields
(generic reader).
input-type
(generic reader).
label
(generic reader).
(setf label)
(generic writer).
multiple
(generic reader).
(setf multiple)
(generic writer).
name
(generic reader).
options
(generic reader).
(setf options)
(generic writer).
required
(generic reader).
(setf required)
(generic writer).
supplied
(generic reader).
(setf supplied)
(generic writer).
uri-path
(generic reader).
value
(generic reader).
*input-field-for-old-uri*
(special variable).
display-value
(generic reader).
set-required-present
(generic function).
test-widget-if-session
(function).
Definitions are sorted by export status, category, package, and then by lexicographic order.
An absolute route where caveman2-widgets’ CSS files can be accessed.
This variable holds a list of functions which will be called when INIT-WIDGETS is evaluated. You add any function you like but the main idea was to add functions from caveman2-widgets based libraries/applications that need those variables at compile time.
An absolute path where caveman2-widgets’ JavaScript files can be accessed.
The URL to access jQuery.
This variable holds the keyword which is used within the session to indicated that a session holder is logged in (or not).
An <app>-instance
The filename of the CSS file which manages all standard widget styles.
The filename of the JavaScript file which manages all standard widget functionality.
This should be a function which should translate a given text. You can modify
it to your needs. By default this function does nothing.
@param plural-p
@param genitive-form-p
@param items-count
@param accusative-form-p
@param language
@param base-path The path for the navigation. Should have a starting "/". @param header-widget A <HEADER-WIDGET> for the navigation and it’s children. @param pages A list of lists.
@param obj-args The parameter which are passed to the constructor for the new widget.
@param document-symbol The symbol name to access the document. @param doc-kind The class which is used as HTML document. @param header A <HEADER-WIDGET> for this document.
@param key A string which might be in the args
@param args The value passed by a <CALLBACK-WIDGET> in its callback
function.
@param obj The object of which the name is required @param get-all-self If non-nil returns the entire hierarchy.
Gets a previously saved widget from the session variable (e.g. to render it).
Marks a widget that it should be rendered ASAP.
Removes a saved widget from the session variable.
Saves a widget in the session variable. This should be considered ONLY for
session scoped widgets. Only adds WIDGET if there is no widget at SESSION-TAG
already.
@param force If non-nil overwrites the already stored value.
@return The current value in the SESSION at position SESSION-TAG.
hash-table
)) ¶hash-table
)) ¶<navigation-widget>
) (item list
)) ¶@param item This should be a list which should looke like that: (list "pagetitle" "uri-path" <widget-for-pagetitle>).
<header-widget>
) (item string
)) ¶The given item will be added to the <head> tag as given.
<header-widget>
) (item <css-file>
)) ¶<header-widget>
) (item <js-file>
)) ¶<table-widget>
) (item cons
)) ¶@param item Must not have more than two values. The first value is the keyword which should be displayed when a <TABLE-ITEM> object is accessed. The second value is the header text for the column.
<composite-widget>
) (item <widget>
)) ¶<form-widget>
) (item <form-field>
)) ¶<radio-field>
) (item string
)) ¶<select-field>
) (item <option-field>
)) ¶<dirty-widget-holder>
) (item <widget>
)) ¶<widget-holder>
) (item <widget>
)) ¶<navigation-widget>
)) ¶<navigation-widget>
)) ¶Determines the path for this navigation. It does not need an initial or trailing forward slash.
<html-document-widget>
)) ¶automatically generated reader method
body
.
<html-document-widget>
)) ¶automatically generated writer method
body
.
<html-document-widget>
)) ¶automatically generated reader method
<html-document-widget>
)) ¶automatically generated writer method
<callback-widget>
)) ¶<header-widget>
)) ¶automatically generated reader method
<header-widget>
)) ¶automatically generated writer method
<form-field>
)) ¶<form-field>
)) ¶Checks the user input for flaws. Takes one
argument - the string passed by the user. Should return non-nil if
everything is correct.
<radio-field>
)) ¶<radio-field>
)) ¶The option which is checked. Must be a number. Start with 0.
<callback-widget>
)) ¶automatically generated reader method
<callback-widget>
)) ¶automatically generated writer method
<table-widget>
)) ¶This is a list of cons which where the cons is one column. The first value of the cons is the keyword to display. The second value of the cons is the table header for that column. For the header (second value) you can use HTML code!
Example:
(list (list :firstcolumn "First column"))
<navigation-widget>
)) ¶automatically generated reader method
<navigation-widget>
)) ¶automatically generated writer method
<navigation-widget>
)) ¶The name for the current page to display.
<navigation-widget>
)) ¶@param value Must be an uri path string
<dirty-widget-holder>
) (item <widget>
)) ¶<widget-holder>
) (item <widget>
)) ¶<border-widget>
)) ¶automatically generated reader method
east
.
<border-widget>
)) ¶automatically generated writer method
east
.
<form-field>
)) ¶<form-field>
)) ¶A highly frequented slot. Non-nil indicates that an error occurred.
<form-field>
)) ¶<form-field>
)) ¶The error message that will be displayed if
ERROR-HAPPENED is non-nil. The error message will be translated
before rendered.
<navigation-widget>
) (item string
)) ¶@param item The URI path as string.
<widget-holder>
) (to-find string
)) ¶<function-widget>
)) ¶automatically generated reader method
fn
.
<function-widget>
)) ¶automatically generated writer method
fn
.
This generic method should return the entire object
as cons-list. If you want to hide certain slots, just keep them out of
the list!
<table-item>
)) ¶<html-document-widget>
)) ¶automatically generated reader method
<html-document-widget>
)) ¶automatically generated writer method
<callback-widget>
)) ¶This slot should be one of the HTTP methods as keyword (e.g. :post or :get
<header-widget>
)) ¶<header-widget>
)) ¶The path to a specific image to use as icon for page.
<form-widget>
)) ¶A list of <FORM-FIELD> objects.
<input-field>
)) ¶automatically generated reader method
hash-table
)) ¶hash-table
)) ¶<form-field>
)) ¶<form-field>
)) ¶The label which will be placed before the <input> tag.
<callback-widget>
)) ¶automatically generated reader method
hash-table
)) ¶hash-table
)) ¶<login-widget>
)) ¶Must be a function that takes two parameters. The first is the username and the second is the password.
<login-widget>
)) ¶automatically generated reader method
<login-widget>
)) ¶automatically generated reader method
<viewgrid-widget>
)) ¶<viewgrid-widget>
)) ¶Non-nil value must be a number which describes how many items will be displayed on each viewgrid page.
<select-field>
)) ¶<select-field>
)) ¶Non-nil allows multiple choices.
<form-field>
)) ¶automatically generated reader method
name
.
<border-widget>
)) ¶automatically generated reader method
<border-widget>
)) ¶automatically generated writer method
<viewgrid-widget>
)) ¶<viewgrid-widget>
)) ¶Must either be NIL or a function which takes one
argument. The passed argument is the item in the viewgrid which is
viewed. If the value is NIL the client can’t view a specific item.
<viewgrid-widget>
)) ¶<viewgrid-widget>
)) ¶The text which should be displayed on the button for the ON-VIEW callback.
<radio-field>
)) ¶automatically generated reader method
<select-field>
)) ¶automatically generated reader method
<radio-field>
)) ¶automatically generated writer method
<select-field>
)) ¶automatically generated writer method
<header-widget>
)) ¶A list of strings that will be directly put in the header tag.
<navigation-widget>
)) ¶A list of cons. This slot holds all possible pages
and it should look like: (list (list "pagetitle" "uri-path" <widget>))
@return The WIDGET object.
<widget>
)) ¶This is a list of protection circles. If NIL (or
an empty list) the widget is not procted. If non-nil it should be a
list of keywords. That list indicates which keywords (or authorized
circles) the requester has in his session. Use PROTECT-WIDGET to use
this slot.
<viewgrid-item>
) (view (eql :oneline)
)) ¶<viewgrid-item>
) (view (eql :short)
)) ¶<viewgrid-item>
) (view (eql :full)
)) ¶@return Returns the HTML representation of the
widget as string. It is intended to use this within a simple HTML
transfer or embedded in another page.
<blank-navigation-widget>
)) ¶<menu-navigation-widget>
)) ¶<html-document-widget>
)) ¶<header-widget>
)) ¶<css-file>
)) ¶<login-widget>
)) ¶<border-widget>
)) ¶<viewgrid-widget>
)) ¶<table-widget>
)) ¶<table-widget>
)) ¶<function-widget>
)) ¶<hcomposite-widget>
)) ¶<composite-widget>
)) ¶<string-widget>
)) ¶<form-widget>
)) ¶<radio-field>
)) ¶<select-field>
)) ¶<option-field>
)) ¶<input-field>
)) ¶<form-field>
)) ¶<form-field>
)) ¶<link-widget>
)) ¶<button-widget>
)) ¶<table-widget>
)) ¶<table-widget>
)) ¶@return Returns the HTML representation of the
widget as string. To generate a method for a specific HTTP method you
can do the following:
(defmethod render-widget-rest ((this <widget>) (method (eql :get)) (args t)) "HTML output for the REST when GET.")
<form-field>
)) ¶automatically generated reader method
<form-field>
)) ¶automatically generated writer method
<navigation-widget>
)) ¶automatically generated reader method
<navigation-widget>
)) ¶automatically generated writer method
<login-widget>
)) ¶<login-widget>
)) ¶A functions which will be called after signing out.
<border-widget>
)) ¶automatically generated reader method
<border-widget>
)) ¶automatically generated writer method
<form-field>
)) ¶<form-field>
)) ¶A highly frequented slot. It tells if the form field was filled by the client.
<string-widget>
)) ¶automatically generated reader method
text
.
<string-widget>
)) ¶automatically generated writer method
text
.
<header-widget>
)) ¶automatically generated reader method
<header-widget>
)) ¶automatically generated writer method
<callback-widget>
)) ¶This slot should give the exact path to access this widget.
<option-field>
)) ¶automatically generated reader method
<input-field>
)) ¶automatically generated reader method
<viewgrid-widget>
)) ¶<viewgrid-widget>
)) ¶The value of this slot is passed to the RENDER-AS
method. Therefore you can use an arbitary value but you have to
provide an according method for that value!
view
.
<border-widget>
)) ¶automatically generated reader method
west
.
<border-widget>
)) ¶automatically generated writer method
west
.
<composite-widget>
)) ¶automatically generated reader method
<composite-widget>
)) ¶automatically generated writer method
<login-widget>
) &key) ¶<widget>
) &key) ¶Generates a REST for the widget. It will automatically generate accessable URIs for the HTTP methods stored in *rest-methods*. The REST can be accessed by the URI /*rest-path*/widget-name
<button-widget>
) &key) ¶<link-widget>
) &key) ¶<form-widget>
) &key) ¶:north
:south
:center
The callback function will be called when the user presses the button.
Initarg | Value |
---|---|
:uri-path |
|
:http-method | post |
(function (lambda (caveman2-widgets.callback-widget::args) ""))
:callback
This slot is read-only.
This slot should give the exact path to access this widget.
(error "must supply an uri-path to access the widget.")
:uri-path
This slot is read-only.
This slot should be one of the HTTP methods as keyword (e.g. :post or :get
(error "must supply a method to access the http url.")
:http-method
This slot is read-only.
:classes
(quote nil)
:widgets
(error "must specify a name for the form field.")
:name
name
.
This slot is read-only.
The label which will be placed before the <input> tag.
""
:label
A highly frequented slot. It tells if the form field was filled by the client.
t
:required
Checks the user input for flaws. Takes one
argument - the string passed by the user. Should return non-nil if
everything is correct.
(function (lambda (caveman2-widgets.callback-widget::str) t))
:check-function
A highly frequented slot. Non-nil indicates that an error occurred.
The error message that will be displayed if
ERROR-HAPPENED is non-nil. The error message will be translated
before rendered.
""
:error-message
A list of <FORM-FIELD> objects.
(quote nil)
:input-fields
This slot is read-only.
Uses a fucntion for rendering. The given function should return a string which will then be rendered.
This is a Horizontal composite widget. Therefore it
is essentially the same as the <COMPOSITE-WIDGET> with the
difference that is displays its widgets horizontally.
(list (make-instance (quote caveman2-widgets.document:<css-file>) :path (concatenate (quote string) caveman2-widgets.widget:*css-path* "/" caveman2-widgets.widget:*widgets-css-filename*)))
This slot is read-only.
(list (make-instance (quote caveman2-widgets.document:<js-file>) :path caveman2-widgets.document:*jquery-cdn-link*) (make-instance (quote caveman2-widgets.document:<js-file>) :path (concatenate (quote string) caveman2-widgets.widget:*javascript-path* "/" caveman2-widgets.widget:*widgets-js-filename*)))
This slot is read-only.
:title
The path to a specific image to use as icon for page.
:icon-path
"utf-8"
:charset
A list of strings that will be directly put in the header tag.
(quote nil)
:other-header-content
This slot is read-only.
The body-widget will be wrapped in a div with the
id "body" automatically. Rendering this widget automatically sets
the language!
(error "must specify an input type.")
:input-type
This slot is read-only.
The callback function will be called when the user
clickes the link. The function must return a string. The returned
string should be an URL to which the server should redirect.
Initarg | Value |
---|---|
:uri-path |
|
:http-method | get |
When the given link redirects absolute (like http://...).
:target-foreign-p
Must be a function that takes two parameters. The first is the username and the second is the password.
(function (lambda (caveman2-widgets.login::user caveman2-widgets.login::password) nil))
:authenticator
This slot is read-only.
A functions which will be called after signing out.
:signout-hook
For internal use only. This slot is used to indicate that the login procedure did not work.
This slot is read-only.
This slot is read-only.
This class is used to display items in a widget. It essentially is only relevant for the GET-AS-LIST method which is used by the <TABLE-WIDGET>.
A function which supplies the table with
<TABLE-ITEM> objects. It is possible to use a heterogenous list of
<TABLE-ITEM> objects but it is strongly advised to watch out by doing
so (accessing not available slots might cause an error!). The producer
should be able to deliver a specific amount of items too (AMOUNT = m,
ALREADY = n, LENGTH-P = nil => gets items from (m) to (m + n)). To
know how many items are avaible please supply the key LENGTH-P which
returns a number when non-nil. Consider the following lambda as
producer:
(lambda (&key
amount
(already 0)
(length-p nil))
(list (make-instance ’<table-item>)))
(error "must supply a producer.")
:producer
This slot is read-only.
This is a list of cons which where the cons is one column. The first value of the cons is the keyword to display. The second value of the cons is the table header for that column. For the header (second value) you can use HTML code!
Example:
(list (list :firstcolumn "First column"))
(quote nil)
:column-descriptions
This slot is read-only.
A function which supplies the table with
<VIEWGRID-ITEM> objects. It is possible to use a heterogenous list of
<VIEWGRID-ITEM> objects. The producer should be able to deliver a
specific amount of items too (FROM = m, TO = n, LENGTH-P = nil => gets
items from (m) to (m + n); FROM = m, TO = NIL, LENGTH-P = nil => gets
items from (m) to LENGTH). To know how many items are avaible please
supply the key LENGTH-P which returns a number when non-nil. Consider
the following lambda as producer:
(lambda (&key
(from 0)
(to nil)
(length-p nil))
(list (make-instance ’<table-item>)))
(error "must supply a producer.")
:producer
This slot is read-only.
The value of this slot is passed to the RENDER-AS
method. Therefore you can use an arbitary value but you have to
provide an according method for that value!
(error "must supply which view should be used.")
:view
view
.
Must either be NIL or a function which takes one
argument. The passed argument is the item in the viewgrid which is
viewed. If the value is NIL the client can’t view a specific item.
:on-view
The text which should be displayed on the button for the ON-VIEW callback.
"view dataview item"
:on-view-label
Non-nil value must be a number which describes how many items will be displayed on each viewgrid page.
:max-items-to-display
A page selector are the page numbers which the
user can click to access the page. If NIL don’t display a page
selector. The non-nil value has to be the URI path in which the
viewgrid is used. E.g. display-selector = "view" if the viewgrid is
accessed on the page /view.
:display-selector
0
This slot is read-only.
This is a list of protection circles. If NIL (or
an empty list) the widget is not procted. If non-nil it should be a
list of keywords. That list indicates which keywords (or authorized
circles) the requester has in his session. Use PROTECT-WIDGET to use
this slot.
(quote nil)
:protected
This slot is read-only.
Marks a widget as rendered.
<border-widget>
)) ¶automatically generated reader method
<border-widget>
)) ¶automatically generated writer method
<navigation-widget>
)) ¶automatically generated reader method
<navigation-widget>
)) ¶automatically generated writer method
<header-widget>
)) ¶automatically generated reader method
<viewgrid-widget>
)) ¶<viewgrid-widget>
)) ¶A page selector are the page numbers which the
user can click to access the page. If NIL don’t display a page
selector. The non-nil value has to be the URI path in which the
viewgrid is used. E.g. display-selector = "view" if the viewgrid is
accessed on the page /view.
<option-field>
)) ¶If NIL then the displayed value will equal the used value.
<header-widget>
)) ¶automatically generated reader method
<login-widget>
)) ¶<login-widget>
)) ¶For internal use only. This slot is used to indicate that the login procedure did not work.
<viewgrid-widget>
)) ¶A function which supplies the table with
<VIEWGRID-ITEM> objects. It is possible to use a heterogenous list of
<VIEWGRID-ITEM> objects. The producer should be able to deliver a
specific amount of items too (FROM = m, TO = n, LENGTH-P = nil => gets
items from (m) to (m + n); FROM = m, TO = NIL, LENGTH-P = nil => gets
items from (m) to LENGTH). To know how many items are avaible please
supply the key LENGTH-P which returns a number when non-nil. Consider
the following lambda as producer:
(lambda (&key
(from 0)
(to nil)
(length-p nil))
(list (make-instance ’<table-item>)))
<table-widget>
)) ¶A function which supplies the table with
<TABLE-ITEM> objects. It is possible to use a heterogenous list of
<TABLE-ITEM> objects but it is strongly advised to watch out by doing
so (accessing not available slots might cause an error!). The producer
should be able to deliver a specific amount of items too (AMOUNT = m,
ALREADY = n, LENGTH-P = nil => gets items from (m) to (m + n)). To
know how many items are avaible please supply the key LENGTH-P which
returns a number when non-nil. Consider the following lambda as
producer:
(lambda (&key
amount
(already 0)
(length-p nil))
(list (make-instance ’<table-item>)))
<form-widget>
) (container list
)) ¶Sets the SUPPLIED slot of the INPUT-FIELDS based on a given list. Sets
also the ERROR-HAPPENED slot by running the check function.
@param container Should be the ARGS parameter of the the callback
which is an ALIST.
@return Returns NIL if any requirement is not met or any . Non-nil value if all requirements are met.
Holds the ids of all widgets that are marked as dirty.
(quote nil)
(error "must supply a path to access the file.")
:path
path
.
This slot is read-only.
:integrity
:crossorigin
This is an abstract widget which implements all
interactions with a navigation but not the RENDER-WIDGET. Please
subclass this class as you want (default implementations are
<MENU-NAVIGATION-WIDGET> and <BLANK-NAVIGATION-WIDGET>.
:class
(quote nil)
A list of cons. This slot holds all possible pages
and it should look like: (list (list "pagetitle" "uri-path" <widget>))
(quote nil)
:pages
This slot is read-only.
The name for the current page to display.
(quote string)
Determines the path for this navigation. It does not need an initial or trailing forward slash.
""
:base-path
(error "must supply a tag for the session.")
:session-tag
Holds all widgets and derived widgets of a specific session. If a widget is finalized it will be removed from this list automatically. This list is neccessary for the REST API to get exactly the given widget.
(quote nil)
Jump to: | (
A B C D E F G H I J L M N O P R S T U V W |
---|
Jump to: | (
A B C D E F G H I J L M N O P R S T U V W |
---|
Jump to: | *
+
B C D E F H I J L M N O P R S T U V W |
---|
Jump to: | *
+
B C D E F H I J L M N O P R S T U V W |
---|
Jump to: | <
C D F L M N P S U W |
---|
Jump to: | <
C D F L M N P S U W |
---|