Browse Source

docs: add documentation for gluon-web

Matthias Schiffer 7 years ago
parent
commit
22746a2a0d
6 changed files with 332 additions and 2 deletions
  1. 0 0
      docs/dev/web/config-mode.rst
  2. 117 0
      docs/dev/web/controller.rst
  3. 0 0
      docs/dev/web/i18n.rst
  4. 148 0
      docs/dev/web/model.rst
  5. 55 0
      docs/dev/web/view.rst
  6. 12 2
      docs/index.rst

+ 0 - 0
docs/dev/configmode.rst → docs/dev/web/config-mode.rst


+ 117 - 0
docs/dev/web/controller.rst

@@ -0,0 +1,117 @@
+Controllers
+===========
+
+Controllers live in ``/lib/gluon/web/controller``. They define which pages ("routes")
+exist under the ``/cgi-bin/gluon`` path, and what code is run when these pages are requested.
+
+Controller scripts mostly consist of calls of the `entry` function, which each define
+one route:
+
+.. code-block:: lua
+
+  entry({"admin"}, alias("admin", "info"), _("Advanced settings"), 10)
+  entry({"admin", "info"}, template("admin/info"), _("Information"), 1)
+
+The entry function expects 4 arguments:
+
+  - `path`: Components of the path to define a route for.
+
+    The above example defines routes for the paths ``admin`` and ``admin/info``.
+
+  - `target`: Dispatcher for the route. See the following section for details.
+  - `title`: Page title (also used in navigation). The underscore function is used
+
+  - `order`: Sort index in navigation (defaults to 100)
+
+Navigation indexes are automatically generated for each path level. Pages can be
+hidden from the navigation by setting the `hidden` property of the node object
+returned by `entry`:
+
+.. code-block:: lua
+
+  entry({"hidden"}, alias("foo"), _("I'm hidden!")).hidden = true
+
+
+Dispatchers
+-----------
+
+  - *alias* (*path*, ...): Redirects to a different page. The path components are
+    passed as individual arguments.
+  - *call* (*func*, ...): Runs a Lua function for custom request handling. The given
+    function is called with the HTTP object and the template renderer as first
+    two arguments, followed by all additional arguments passed to `call`.
+  - *template* (*view*): Renders the given view. See :doc:`view`.
+  - *model* (*name*): Displays and evaluates a form as defined by the given model. See the
+    :doc:`model` page for an explanation of gluon-web models.
+
+
+.. _web-controller-http:
+
+The HTTP object
+---------------
+
+The HTTP object provides information about the HTTP requests and allows to add
+data to the reply. Using it directly is rarely necessary when gluon-web
+models and views are used.
+
+Useful functions:
+
+  - *getenv* (*key*): Returns a value from the CGI environment passed by the webserver.
+  - *formvalue* (*key*): Returns a value passed in a query string or in the content
+    of a POST request. If multiple values with the same name have been passed, only
+    the first is returned.
+  - *formvaluetable* (*key*): Similar to *formvalue*, but returns a table of all
+    values for the given key.
+  - *status* (*code*, *message*): Writes the HTTP status to the reply. Has no effect
+    if a status has already been sent or non-header data has been written.
+  - *header* (*key*, *value*): Adds an HTTP header to the reply to be sent to to
+    the client. Has no effect when non-header data has already been written.
+  - *prepare_content* (*mime*): Sets the *Content-Type* header to the given MIME
+    type, potentially setting additional headers or modifying the MIME type to
+    accommodate browser quirks
+  - *write* (*data*, ...): Sends the given data to the client. If headers have not
+    been sent, it will be done before the data is written.
+
+
+HTTP functions are called in method syntax, for example:
+
+.. code-block:: lua
+
+  http:write('Output!')
+
+
+.. _web-controller-template-renderer:
+
+The template renderer
+---------------------
+
+The template renderer allows to render templates (views). The most useful functions
+are:
+
+  - *render* (*view*, *scope*): Renders the given view, optionally passing a table
+    with additional variables to make available in the template.
+  - *render_string* (*str*, *scope*): Same as *render*, but the template is passed
+    directly instead of being loaded from the view directory.
+
+The renderer functions are called in property syntax, for example:
+
+.. code-block:: lua
+
+  renderer.render('layout')
+
+
+Differences from LuCI
+---------------------
+
+  - Controllers must not use the *module* function to define a Lua module (*gluon-web*
+    will set up a proper environment for each controller itself)
+  - Entries are defined at top level, not inside an *index* function
+  - The *alias* dispatcher triggers an HTTP redirect instead of directly running
+    the dispatcher of the aliased route.
+  - The *call* dispatcher is passed a function instead of a string with a function
+    name.
+  - The *cbi* dispatcher of LuCI has been renamed to *model*.
+  - The HTTP POST handler support the multipart/form-data encoding only, so
+    ``enctype="multipart/form-data"`` must be included in all *<form>* HTML
+    elements.
+  - Other dispatchers like *form* are not provided.

+ 0 - 0
docs/dev/i18n.rst → docs/dev/web/i18n.rst


+ 148 - 0
docs/dev/web/model.rst

@@ -0,0 +1,148 @@
+Models
+======
+
+Models are defined in ``/lib/gluon/web/model``. Each model defines one or more
+forms to display on a page, and how the submitted form data is handled.
+
+Let's start with an example:
+
+.. code-block:: lua
+
+  local f = Form(translate('Hostname'))
+
+  local s = f:section(Section)
+
+  local o = s:option(Value, 'hostname', translate('Hostname'))
+  o.default = uci:get_first('system', 'system', 'hostname')
+  function o:write(data)
+    uci:set('system', uci:get_first('system', 'system'), 'hostname', data)
+    uci:commit('system')
+  end
+
+  return f
+
+The toplevel element of a model is always a *Form*, but it is also possible for
+a model to return multiple forms, which are displayed one below the other.
+
+A *Form* has one or more *Sections*, and each *Section* has different types
+of options.
+
+All of these elements have an *id*, which is used to identify them in the HTML
+form and handlers. If no ID is given, numerical IDs will be assigned automatically,
+but using explicitly named elements is often advisable (and it is required if a
+form does not always include the same elements, i.e., some forms, sections or
+options are added conditionally). IDs are hierarchical, so in the above example,
+the *Value* would get the ID ``1.1.hostname`` (value *hostname* in first section
+of first form).
+
+Classes and methods
+-------------------
+
+  - *Form* (*title*, *description*, *id*)
+
+    - *Form:section* (*type*, *title*, *description*, *id*)
+
+      Creates a new section of the given type (usually *Section*).
+
+    - *Form:write* ()
+
+      Is called after the form has beed submitted (but only if the data is valid). It
+      is called last (after all options' *write* methods) and is usually used
+      to commit changed UCI packages.
+
+      The default implementation of *write* doesn't to anything, but it can be
+      overridden.
+
+  - *Section* (usually instanciated through *Form:section*)
+
+    - *Section:option* (*type*, *id*, *title*, *description*)
+
+      Creates a new option of the given type. Option types:
+
+        - *Value*: simple text entry
+        - *TextValue*: multiline text field
+        - *ListValue*: radio buttons or dropdown selection
+        - *DynamicList*: variable number of text entry fields
+        - *Flag*: checkbox
+
+Most option types share the same properties and methods:
+
+  - *default*: default value
+  - *optional*: value may be empty
+  - *datatype*: one of the types described in :ref:`web-model-datatypes`
+
+    By default (when *datatype* is *nil*), all values are accepted.
+
+  - *state*: has one of the values *FORM_NODATA*, *FORM_VALID* and *FORM_INVALID*
+    when read in a form handler
+
+    An option that has not been submitted because of its dependencies will have
+    the state *FORM_NODATA*, *FORM_INVALID* if the submitted value is not valid
+    according to the set *datatype*, and *FORM_VALID* otherwise.
+
+  - *data*: can be read in form handlers to get the submitted value
+
+  - *depends* (*self*, *option*, *value*): adds a dependency on another option
+
+    The option will only be shown when the passed option has the given value. This
+    is mainly useful when the other value is a *Flag* or *ListValue*.
+
+  - *depends* (*self*, *deps*): adds a dependency on multiple other options
+
+    *deps* must be a table with options as keys and values as values. The option
+    will only be shown when all passed options have the corresponding values.
+
+    Multiple alternative dependencies can be added by calling *depends* repeatedly.
+
+  - *value* (*self*, *value*, *text*): adds a choice to a *ListValue*
+
+  - *write* (*self*, *data*): is called with the submitted value when all form data is valid.
+
+    Does not do anything by default, but can be overridden.
+
+The *default* value, the *value* argument to *depends* and the output *data* always have
+the same type, which is usually a string (or *nil* for optional values). Exceptions
+are:
+
+  - *Flag* uses boolean values
+  - *DynamicList* uses a table of strings
+
+Despite its name, the *datatype* setting does not affect the returned value type,
+but only defines a validator the check the submitted value with.
+
+For a more complete example that actually makes use of most of these features,
+have a look at the model of the *gluon-web-network* package.
+
+.. _web-model-datatypes:
+
+Data types
+----------
+
+  - *integer*: an integral number
+  - *uinteger*: an integral number greater than or equal to zero
+  - *float*: a number
+  - *ufloat*: a number greater than or equal to zero
+  - *ipaddr*: an IPv4 or IPv6 address
+  - *ip4addr*: an IPv4 address
+  - *ip6addr*: an IPv6 address
+  - *wpakey*: a string usable as a WPA key (either between 8 and 63 characters, or 64 hex digits)
+  - *range* (*min*, *max*): a number in the given range (inclusive)
+  - *min* (*min*): a number greater than or equal to the given minimum
+  - *max* (*max*): a number less than or equal to the given maximum
+  - *irange* (*min*, *max*): an integral number in the given range (inclusive)
+  - *imin* (*min*): an integral number greater than or equal to the given minimum
+  - *imax* (*max*): an integral number less than or equal to the given maximum
+  - *minlength* (*min*): a string with the given minimum length
+  - *maxlength* (*max*): a string with the given maximum length
+
+Differences from LuCI
+---------------------
+
+  - LuCI's *SimpleForm* and *SimpleSection* are called *Form* and *Section*, respectively
+  - Is it not possible to add options to a *Form* directly, a *Section* must always
+    be created explicitly
+  - Many of LuCI's CBI classes have been removed, most importantly the *Map*
+  - The *rmempty* option attribute does not exist, use *optional* instead
+  - Only the described data types are supported
+  - Form handlers work completely differently (in particular, a *Form*'s *handle*
+    method should usually not be overridden in *gluon-web*)

+ 55 - 0
docs/dev/web/view.rst

@@ -0,0 +1,55 @@
+Views
+=====
+
+The template parser reads views from ``/lib/gluon/web/view``. Writing own view
+should be avoided in favour of using :doc:`model` with their predefined views.
+
+Views are partial HTML pages, with additional template tags that allow
+to embed Lua code and translation strings. The following tags are defined:
+
+  - ``<%`` ... ``%>`` evaluates the enclosed Lua expression.
+  - ``<%=`` ... ``%>`` evaluates the enclosed Lua expression and prints its value.
+  - ``<%+`` ... ``%>`` includes another template.
+  - ``<%:`` ... ``%>`` translates the enclosed string using the loaded i18n catalog.
+  - ``<%_`` ... ``%>`` translates the enclosed string *without escaping HTML entities*
+    in the translation. This only makes sense when the i18n catalog contains HTML code.
+  - ``<%#`` ... ``%>`` is a comment.
+
+All of these also come in the whitespace-stripping variants ``<%-`` and ``-%>`` that
+remove all whitespace before or after the tag.
+
+Complex combinations of HTML and Lua code are possible, for example:
+
+.. code-block:: text
+
+  <div>
+    <% if foo then %>
+      Content
+    <% end %>
+  </div>
+
+
+Variables and functions
+-----------------------
+
+Many call sites define additional variables (for example, model templates can
+access the model as *self* and an unique element ID as *id*), but the following
+variables and functions should always be available for the embedded Lua code:
+
+  - *renderer*: :ref:`web-controller-template-renderer`
+  - *http*: :ref:`web-controller-http`
+  - *request*: Table containing the path components of the current page
+  - *url* (*path*): returns the URL for the given path, which is passed as a table of path components.
+  - *attr* (*key*, *value*): Returns a string of the form ``key="value"``
+    (with a leading space character before the key).
+
+    *value* is converted to a string (tables are serialized as JSON) and HTML entities
+    are escaped. Returns an empty string when *value* is *nil* or *false*.
+  - *include* (*template*): Includes another template.
+  - *node* (*path*, ...): Returns the controller node for the given page (passed as
+    one argument per path component).
+
+    Use ``node(unpack(request))`` to get the node for the current page.
+  - *pcdata* (*str*): Escapes HTML entities in the passed string.
+  - *urlencode* (*str*): Escapes the passed string for use in an URL.
+  - *translate* and *translatef*: see :doc:`i18n`

+ 12 - 2
docs/index.rst

@@ -41,11 +41,21 @@ Developer Documentation
    dev/basics
    dev/hardware
    dev/upgrade
-   dev/configmode
    dev/wan
-   dev/i18n
    dev/mac_addresses
 
+gluon-web Reference
+^^^^^^^^^^^^^^^^^^^
+
+.. toctree::
+   :maxdepth: 1
+
+   dev/web/controller
+   dev/web/model
+   dev/web/view
+   dev/web/i18n
+   dev/web/config-mode
+
 Packages
 --------