The CLOG manual

Table of Contents

[in package CLOG]

The Common Lisp Omnificient GUI, CLOG for short, uses web technology to produce graphical user interfaces for applications locally or remotely. CLOG can take the place, or work along side, most cross platform GUI frameworks and website frameworks. The CLOG package starts up the connectivity to the browser or other websocket client (often a browser embedded in a native template application.)

1 CLOG Getting Started

CLOG - The Common Lisp Omnificent GUI

David Botton mailto:david@botton.com

License BSD 3-Clause License

The Common Lisp Omnificent GUI, CLOG for short, uses web technology to produce graphical user interfaces for applications locally or remotely. CLOG can take the place, or work alongside, most cross-platform GUI frameworks and website frameworks. The CLOG package starts up the connectivity to the browser or other websocket client (often a browser embedded in a native template application.)

STATUS: CLOG is complete and all work is on higher order additions, such as full desktop over the web, database tools,etc. See below for some enhacements being worked on. CLOG is actually based on GNOGA, a framework I wrote for Ada in 2013 and used in commercial production code for the last 8+ years, i.e. the techiniques CLOG uses are solid and proven.

CLOG is being actively extended daily. Check the github discussion boards for the latest.

Some potential applications for CLOG:

The key to CLOG is the relationship it forms with a Browser window or Browser control compiled to native code. CLOG uses websockets for communications and the browser to render a GUI that maintains an active soft realtime connection. For most CLOG applications all programming logic, events and decisions are done on the server which can be local, or remote over the web.

CLOG is developed on an M1 MacBook with ECL and SBCL, it is tested fairly regulary with SBCL on Linux, Windows and Intel MacBook. It should in theory work on any system with Quicklisp and CLACK.

CLOG is in Quicklisp (ql:quickload :clog), but you may want to live on the bleeding edge and use Ultralisp or clone the github repo into your ~/common-lisp directory (or other quicklisp/asdf findable directory):

cd ~/common-lisp
git clone https://github.com/rabbibotton/clog.git

To load this package and work through tutorials (assuming you have Quicklisp configured.)

Note: If using portacle for Windows you will need to update Quicklisp use (ql:update-dist "quicklisp") You will also likely need to copy the sqlite3 dll from https://www.sqlite.org/download.html to portaclewinlib

  1. Start emacs then M-x slime

  2. In the REPL, run:

CL-USER> (ql:quickload :clog)
CL-USER> (clog:run-tutorial 1)

Tip for Windows WSL linux user. Install "sudo apt install xdg-utils" to install xdg-open so that run-tutorial uses the windows browser.

To see where the source, tutorial and demo files are:

CL-USER> (clog:clog-install-dir)

You can the run the demos with:

CL-USER> (ql:quickload :clog)
CL-USER> (clog:run-demo 1)

The clog-db-admin tool can be run with:

CL-USER> (ql:quickload :clog/tools)
CL-USER> (clog-tools:clog-db-admin)

The clog-builder GUI Builder tool can be run with:

CL-USER> (ql:quickload :clog/tools)
CL-USER> (clog-tools:clog-builder)

You can also open a "clog-repl" window in your browser to play from the common-lisp repl:

CL-USER> (in-package clog-user)
CLOG-USER> (clog-repl)
CLOG-USER> (setf (background-color *body*) "beige")
CLOG-USER> (create-div *body* :content "Hello World!")

The clog-repl URL is http://127.0.0.1:8080/repl body will always refer to the last access of that URL.

To open a browser with the CLOG manual:

CL-USER> (clog:open-manual)

Work your way through the tutorials. You will see how quick and easy it is to be a CLOGer. The next section also covers the basic programming concepts needed for mastering CLOG.

2 CLOG Programming Basics

We first need to load CLOG

CL-USER> (ql:quickload :clog)
To load "clog":
  Load 1 ASDF system:
    clog
; Loading "clog"
................................................
(:CLOG)

Next, we tell clog to start a clog-repl:

CL-USER> (clog:clog-repl)
Hunchentoot server is started.
Listening on 0.0.0.0:8080.
HTTP listening on    : 0.0.0.0:8080
HTML Root            : ~/common-lisp/clog/static-files/
Boot file for path / : /debug.html

Use clog-user:*body* to access the clog-repl window.
NIL

At this point CLOG should open a browser window to http://127.0.0.1:8008/repl

We can now enter the clog-user package and hack a way.

CL-USER> (in-package clog-user)
#<"CLOG-USER" package>
CLOG-USER> (setf (background-color *body*) :red)

Something more than an empty lambda function is needed to do more. The tutorials are a good place to start with make CLOG apps in code, so here we are going to demonstrate the concepts using some REPL tricks to help developing CLOG apps in general.

(From here on, we will leave out the prompts and responses in our quotes of code.)

(create-div *body* :content "Hello World")

If you have the browser on the screen you will see the results immediately. Try this line and you can watch it happen:

(dotimes (n 10) (create-div *body* :content (format nil "Line ~A - Hello World" n)) (sleep .3))

We can also set and respond to events and set properties etc:

(let ((tmp (create-button *body* :content "Click Me")))
  (set-on-click tmp (lambda (obj)(setf (hiddenp tmp) t))))

Since we already initialized CLOG let's use SET-ON-NEW-WINDOW to change our on-new-window handler (handler is just a made up name for a function that will handle an event).

CLOG-USER> (set-on-new-window (lambda (body) (create-div body :content "Hello World!")))

Now any new window opened will not be using CLOG REPL but instead will execute our handler.

Important take aways to using CLOG from the REPL:

  1. You will need to pass to a global from the running system whatever you want to tinker with in the live system from the REPL.

  2. Any time you recompile the on-new-window handler or want to use a different one you will need to use SET-ON-NEW-WINDOW.

  3. Similarily with all events, any time an event handler is recompiled or want to change the even hander, set-on-* function will need to be called.

3 CLOG Event Data

Some events in CLOG return in addition to the target event, event data. The data is passed in the second argument to the event handler as a property list. To retrieve the data use (getf data :property) the available properties (to use for :property) are based on the event type.

Events in clog-base

 :event-type   :mouse
 :x            x relative to the target
 :y            y relative to the target
 :screen-x     x relative to the users screen
 :screen-y     y relative to the users screen
 :which-button which mouse button clicked
 :alt-key      t or nil if alt-key held down
 :ctrl-key     t or nil if ctrl-key held down
 :shift-key    t or nil if shift-key held down
 :meta-key     t or nil if meta-key held down

 :event-type   :pointer
 :x            x relative to the target
 :y            y relative to the target
 :screen-x     x relative to the users screen
 :screen-y     y relative to the users screen
 :which-button which mouse button clicked
 :alt-key      t or nil if alt-key held down
 :ctrl-key     t or nil if ctrl-key held down
 :shift-key    t or nil if shift-key held down
 :meta-key     t or nil if meta-key held down

 :event-type     :touch
 :x              x relative to the target
 :y              y relative to the target
 :screen-x       x relative to the users screen
 :screen-y       y relative to the users screen
 :number-fingers number of fingers being used
 :alt-key        t or nil if alt-key held down
 :ctrl-key       t or nil if ctrl-key held down
 :shift-key      t or nil if shift-key held down
 :meta-key       t or nil if meta-key held down

 :event-type :keyboard
 :key        String of key pressed, with out modifiers like ctrl characters
 :key-code   The utf-16 value of :key
 :char-code  UTF-8 representation for key pressed when possible - deprecated
 :alt-key    t or nil if alt-key held down
 :ctrl-key   t or nil if ctrl-key held down
 :shift-key  t or nil if shift-key held down
 :meta-key   t or nil if meta-key held down

Events in clog-window

 :event-type :storage
 :key        local storage key that was updated (even in another window)
 :old-value  old key value
 :value      new key value

4 CLOG System

CLOG Startup and Shutdown

5 CLOG Utilities

Concurrent Hash Tables

Declerative Syntax Support

CLOG-Group - Utility Class for CLOG-Obj storage

CLOG JS utilities

CLOG Color utilities

CLOG Unit utilities

6 CLOG Objects

CLOG-Obj - Base class for CLOG Objects

CLOG-Obj - General Properties

CLOG-Obj - General Methods

CLOG-Obj - Low Level

CLOG-Obj - Internals for Extensions and Plugins

CLOG-Obj - Event Handling

7 CLOG Elements

CLOG-Element - Class for CLOG Elements

CLOG-Element - Low Level Creation

CLOG-Element - DOM Placement

CLOG-Element - General Properties

CLOG-Element - Properties

CLOG-Element - Styles

CLOG-Element - Methods

CLOG-Element - DOM Traversal Methods

8 Common CLOG Elements

CLOG-A - Class for CLOG Anchors

CLOG-BR - Class for CLOG Line Breaks

CLOG-BUTTON - Class for CLOG Buttons

CLOG-IMG - Class for CLOG Images

CLOG-Div - Class for CLOG Div Blocks

CLOG-Dialog - Class for CLOG Dialog Blocks

CLOG-Details - Class for CLOG Detail Blocks

CLOG-Summary - Class for CLOG Summary Blocks

CLOG-HR - Class for CLOG Hortizontal Rules

CLOG-Meter - Class for CLOG Meters

CLOG-Progress-Bar - Class for CLOG Progress Bars

CLOG-P - Class for CLOG Paragraphs

CLOG-Span - Class for CLOG Inline Spans

CLOG-Section - Class for CLOG Inline Sections

CLOG-Phrase - Class for CLOG Inline Phrases

CLOG-Ordered-List - Class for CLOG Ordered-Lists

CLOG-Unordered-List - Class for CLOG Unordered-Lists

CLOG-List-Item - Class for CLOG List-Items

CLOG-Definition-List - Class for CLOG Definition-Lists

CLOG-Term - Class for CLOG Terms

CLOG-Description - Class for CLOG Descriptions

CLOG-Table - Class for CLOG Tables

CLOG-Table-Row - Class for CLOG Table-Rows

CLOG-Table-Column - Class for CLOG Table-Columns

CLOG-Table-Heading - Class for CLOG Table-Headings

CLOG-Table-Head - Class for CLOG Table-Heads

CLOG-Table-Body - Class for CLOG Table-Bodys

CLOG-Table-Caption - Class for CLOG Table-Captions

CLOG-Table-Footer - Class for CLOG Table-Footers

CLOG-Table-Column-Group - Class for CLOG Table-Column-Groups

CLOG-Table-Column-Group-Item - Class for CLOG Table-Column-Group-Items

9 CLOG Presentations

CLOG-Presentations - CLOG bindings to Lisp Objects

10 CLOG Data

Load and Write to objects and CLOG-Elements

SQL Timestamp by Engine

SQL Writing Helpers

11 CLOG DBI

CLOG-Database - CLOG Database Connection

12 CLOG Panels

CLOG-Panel - CLOG Panels

CLOG-Panel-Box - CLOG Panel Box

CLOG-Panel-Box-Layout

13 CLOG Style Blocks

CLOG-Style-Block - CLOG Style Blocks

14 CLOG Form Objects

CLOG-Form-Data

CLOG-Form - Class for organizing Form Elements in to a From

CLOG-Fieldset - Class for CLOG Fieldsets

CLOG-Legend - Class for CLOG Legends

CLOG-Form-Element - Class for form elements

CLOG-Label - Class for CLOG Labels

CLOG-Select - Class for CLOG Selects

CLOG-Data-List - Class for CLOG Option Data Lists

CLOG-Text-Area - Class for CLOG Text Areas

15 CLOG Canvas Objects

CLOG-Canvas - Class for CLOG canvas objects

16 CLOG Multimedia Objects

CLOG-Multimedia - Base Class for CLOG multimedia objects

CLOG-Multimedia - Event Handlers

The standard event order for a normal file load is: On_Load_Start On_Duration_Change On_Loaded_Meta_Data On_Loaded_Data On_Progress On_Can_Play On_Can_Play_Though

Clog-Audio - Class for CLOG Audio Control

Clog-Video - Class for CLOG Video Control

17 CLOG Auth Objects

[in package CLOG-AUTH]

CLOG-AUTH - Authentication

CLOG-AUTH - Authorization

18 CLOG GUI Objects

[in package CLOG-GUI]

CLOG-GUI - Desktop GUI abstraction for CLOG

CLOG-GUI - Menus

CLOG-GUI - Window System

CLOG-GUI - Individual Windows

CLOG-GUI - Individual Window Events

CLOG-GUI - Dialog Boxes

19 CLOG Web Objects

[in package CLOG-WEB]

CLOG-WEB - Web page abstraction for CLOG

CLOG-WEB - General Containers

CLOG-WEB - Auto Layout System

CLOG-WEB - 12 Column Grid Layout System

CLOG-WEB - Look and Feel

CLOG-WEB - Mobile

CLOG-WEB - Menus

CLOG-WEB - Interactions

CLOG-WEB - Websites

CLOG-WEB-SITE - Accessors

CLOG-WEB - Utilities

20 CLOG Web DBI

[in package CLOG-WEB-DBI]

Authentication

21 CLOG Web Site Themes

[in package CLOG-WEB]

Theme helpers

Built in themes

22 CLOG Body Objects

CLOG-Body - CLOG Body Objects

CLOG-Body - Properties

23 CLOG Window Objects

CLOG-Window - CLOG Window Objects

CLOG-Window - Properties

CLOG-Window - Methods

CLOG-Window - Events

24 CLOG Document Objects

CLOG-Document - CLOG Document Objects

CLOG-Document - Events

25 CLOG Location Objects

Clog-Location - CLOG Location Objects

CLOG-Location - Properties

CLOG-Location - Methods

26 CLOG Navigator Objects

CLOG-Navigator - CLOG Navigator Objects

CLOG-Navigator - Properties

27 CLOG jQuery Objects

CLOG-jQuery - Base class for CLOG jQuery Objects

CLOG-jQuery creation

CLOG-jQuery methods

28 CLOG Helper Functions

Tutorial and demo helpers

Functions for Compilation and Documentation

29 CLOG Framework internals and extensions

* Introduction to Internals *

This section on internals is not intended for general use of CLOG. It is for those looking to maint or extend CLOG, or those creating plugins.

* The Client Side and the Server Side *

All objects created in CLOG have a server side and a client side representation, at least at the time of their creation. The server side representation is a CLOG-obj or one of its descendants that is returned by one of the many create-* functions. The client side representation is the DOM element (or other JavaScript object) itself stored in the clog array keyed by the html-id cloghtml-id.

* Client Side Scripting *

Executing code on the client side is done in one of three ways:

  1. The connection - Using the clog-connection package execute or query

  2. The DOM object - Using the clog-obj execute or query

  3. The jQuery wrapper - Using the clog-obj jquery-execute or jquery-query

Query time outs are set in clog-connect:query-time-out by default 3 seconds.

* Responding to new JavaScript DOM events *

If there is no data for the event just changing the name of the event is sufficient in this example:

(defmethod set-on-click ((obj clog-obj) handler)
  (set-event obj "click"
         (when handler
           (lambda (data)
         (declare (ignore data))
         (funcall handler obj)))))

If there is data for the event an additional string containing the needed JavaScript to return the even data and a function to parse out the data.

Replace the event name with the correct name, parse-keyboard-even with the parse function and the string containing the needed JavaScript replaces keyboard-event-script:

(defmethod set-on-key-down ((obj clog-obj) handler)
  (set-event obj "keydown"
         (when handler
           (lambda (data)
         (funcall handler obj (parse-keyboard-event data))))
         :call-back-script keyboard-event-script))   
(defparameter keyboard-event-script
  "+ e.keyCode + ':' + e.charCode + ':' + e.altKey + ':' + e.ctrlKey + ':' +
     e.shiftKey + ':' + e.metaKey")
(defun parse-keyboard-event (data)
  (let ((f (ppcre:split ":" data)))
    (list
     :event-type :keyboard
     :key-code   (parse-integer (nth 0 f) :junk-allowed t)
     :char-code  (parse-integer (nth 1 f) :junk-allowed t)
     :alt-key    (js-true-p (nth 2 f))
     :ctrl-key   (js-true-p (nth 3 f))
     :shift-key  (js-true-p (nth 4 f))
     :meta-key   (js-true-p (nth 5 f)))))