I think that separating out dispatch so we have clear semantics for
what URLs mean and what state exists at different points in the
pipeine is essential to cleaning up the conceptual model that users
need to internalize.
Much of the following discussion may overlap with recent features or
existing features, which is all to the good. I'm trying to create a
single coherent model that is easy to think about, addresses the
common confusions/complexities I've been encountering, and is not too
different from the existing system.
My pipeline upgrade proposal:
State: ORIGINAL TREE
1) Actions side effect DB and widget state on the current tree. This
includes invoking flows on specific widgets within the current
hierarchy.
State: ORIGINAL TREE MODIFIED BY FLOWS w/ DB and WIDGET SIDE EFFECTS
2) Dispatching updates the state of the widget tree from the URL
including navs, etc. Perhaps some hooks here for extracting
parameters and applying them to widgets in a transparent manner.
Dispatching is skipped during AJAX calls.
State: NEW TREE w/ WIDGET SIDE EFFECTS.
3) Rendering the tree. Should be a simple static operation based on
the state of the widget hierarchy.
State: NEW TREE (rendered)
Trees must have a fully connected parent/child hierarchy so we can
find the appropriate dispatchers. If we have multiple child
dispatchers, the dispatch routine will simply catch mapping failures
and try the other path. It's more flexible, but of course you can get
yourself into trouble if you have name conflicts at a given level of
the dispatcher hierarchy...
However, we can easily create a routine to dump the entire dispatching
tree/namespace to a text file or to graphviz!
===========================
Problem: Flows conflicting with URLs. Managing a mapping of URL to
tree state can easily conflict with flows invoked on a given state of
the tree. Flows that happen higher in the hierarchy fail due to
failing to handle tokens of a given URL.
Solution 1: Default flows insert a dispatcher widget around the root
of the flow. If there is an error in dispatch, it can, by a global or
local policy, simply consume the offending tokens.
Solution 2: Make it easy to do an action-link where you link to a URL
and also perform an action so after the flow is placed into the tree,
the result tokens line up with it. Further, the call/answer protocol
can remember the old URL, so you can redirect on an answer. This
would be an optional facility as it requires thinking carefully about
namespaces.
============================
Problem: Long distance connection of widgets in the tree. I have a
whole set of hacks I've been playing with that connect one widget to
another (build tree with slot reference, have a naming scheme that
searches the widget tree under some 'workspace' widget which resolves
names, etc. This is a general version of the navigation/menu
separation problem.
Solution 1: Explicit namespace, not unlike HTML (class = class, name =
id). Widgets can have a global name that is added to a lookup table
to get to that element (like IDs in HTML). You can simply say (get-
widget 'name) to get a reference to that widget. This allows us to be
agnostic to changes and avoid all the complex linking hacks I've been
using.
Solution 2: Support for searching the tree for paths, class instances,
etc. Probably too general...
Implications:
The new navigation element falls out of this model as two objects:
selector and dispatch-container. The selector object simply keeps a
reference to a dispatch-container which only renders one sub-widget at
a time based on the URL state. The selector object renders a menu
that computes URL links to the dispatch-container's state via method
described below. When the dispatch-container updates it's state in
response to the URL, it can call a callback (or you can have a
subclass with a slot) to update the menu object in the URL rendering
pipeline.
============================
Problem: Generating a URL link to a new configuration of the tree
(e.g. generating friendly URLs from one subtree that points to another
tree state).
Solution: This falls out nicely from the namespace solution. (link-to-
widget name/ref &rest params) => URL that links to that widget state +
arguments for sub-state. The arguments to this function are keywords
that are processed by the target widget which generates the rest of
the URL for you (mapping keywords to path tokens and/or uri
parameters). Only widgets implementing the dispatch interface can be
linked to.
=============================
Problem: Conflation of dispatching elements and structural elements
(like the dispatch-container above). The current navigation element
is simply a way of specifying sub-tree structure based on URLs. We
should be able to do this from the widget hierarchy or in the
traditional table-like fashion.
I thought about a separate 'controller-like' interface which separates
dispatchers out as instances with references to things like
containers, etc but I can't think of a big win that justifies the
increased complexity.
My opinion is that the dispatcher maintains a simple interface which
does the following:
- Turns URLs into widget state (basically what it does now)
- Generates URLs to widget state by calling 'generate' url on it's
parent dispatcher (recursively) and then adding its own tokens based
on the argument list
This enables a variety of models: you can have a global URL->state
model simply by having a master dispatcher at the root which maps all
URLs explicitly to widget state (user-designed, no significant support
from weblocks).
For example, I can have a dispatcher that kept a list of singleton
widgets (blog archive, blog view, blog cover). The dispatcher looks
at the url and returns one of the singletons with its internal state
appropriately updated to reflect the parameters of the URL. It's easy
to write a little regex dispatch routine that is django-like. widgets
= pages, URLs map to widgets + arguments. The current ephemeral
widget model basically support this, but we could create a wrapper
which makes this trivial to implement, giving people a comfortable
page-oriented metaphor to fall back on in when they don't need all the
ajax/application logic. Ephemeral widgets, of course, can't have
state so the linking happens at the level of the dispatcher for, in
this case, the blog app + args.
============================
Problem: Flow on generic 'places' and dispatchers
The flow-wrapper is implemented as a simple dispatcher that does
nothing except on an error condition (we should create an explicit
condition for invalid URL mapping). I think that the current model of
enabling flows in any 'place' that widgets can reside is fine This is
the reason for the funny API Leslie asked about the other day (make-
widget-place-writer). I sometimes have object that renders widgets
from slots rather than from containers so I don't have container
objects and the resulting divs everywhere. When I want to do a flow
on a slot, all that object has to do is implement make-widget-place-
writer which maps a (do-widget old new ) request to the old object
place and updates that place with the new widget and a continuation to
replace that state later.
(FYI - we should have a silent-container object which doesn't generate
a div, but just writes its objects inline...)
=============================
I think that captures most of the complexity/problems I've had with
flows, URLs, hierarchies, etc. Any other major areas people think I'm
missing? Any truly negative reactions to the above proposals (or
observations about holes?)
Getting this done:
- I will volunteer, given a clean -dev tree to fork from or sync to,
to rewrite the dispatching/URL logic and the flow wrapper. (I think/
hope it's only 2-3 days). However, my time is extremely tight
(ongoing PhD general exams on a horribly accelerated schedule), so
I'll need others to volunteer for some or all of the following before
I commit.
- Create the new navigation model (if necessary) including one that is
backward compatible with modern-dispatching. (Jan?)
- Help with some updating/expanding the tests (Leslie/Yarek - you're
already up to speed here)
- Utilities:
- Dump the complete URL static namespace along with parameters names
/ - blog - front
- detail <article>
- archive <year> <month> <day>
-
- news
- about
- Routine to dump/inspect the dispatch hierarchy (full tree, a
particular path)
for example, a graphviz output.
- Identify flows that are active in the hierarchy
- Easy debugging tools
- Get a reference to an object or a path/list of dispatcher objects
from *last-session* based on a URL or via a widget name
- Integration
- At least two people who volunteer to update their systems to the
new model to work out the bugs and document an upgrade procedure.
- Examples of the new model
- A URL mapping implementation of a blog (?)
- A simple workspace object where a sidebar element can easily update
a main widget using the naming mechanism. We can also do a flow+link
demo here if someone can think of a good example (Jan?)
- Documentation
I can hack up a conceptual introduction that builds from Slava's
original blog articles that tries to frame the model. I'll need help/
backup to expand and complete this.
I think we should attack this as a 'sprint' style effort where a core
group gets together on a roughly planned schedule over a weekend via
IM and e-mail and just gets the bulk of this done and a few others
upgrade their existing systems to integrate the new functionality. I
can dedicate a Friday/Saturday to the first pass on Dec. 19th/20th
with clean up on the 22nd. This presumes there exists a stable -dev
tree that I can update my current system to by mid next week. I'm
almost certain I will be unable to dedicate any time to this after the
end of December.
I'm very open to suggestions and revisions, but this is my 2^8 cents
on the matter.
Cheers,
Ian
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"weblocks" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at
http://groups.google.com/group/weblocks?hl=en
-~----------~----~----~----~------~----~------~--~---