Hello, all,
Last night i started jotting down ideas about what a "custom page" feature
might look like, and found out very quickly that "the devil is in the
details."
There are several different approaches to consider, not necessarily
mutually exclusive:
1) The pages/commands are added via client-supplied C files. The build
process could be extended to pick up these files (they would go into a
special subdir) and include them. This would actually be pretty easy to do
(at least on platforms with GNU Make) and would require (i think) no
changes to the fossil sources. The client sources would simply be treated
as normal fossil sources. (This would make a nice mini-project for the
weekend.) Such extensions could be pages or CLI commands. Downside: such
pages could easily circumvent any security conventions used by the built-in
commands. e.g. a custom page which accepts arbitrary SQL as input from
arbitrary users is obviously a bad idea. Speaking of input: such pages
would be much more useful if they could communicate via an AJAX mechanism,
so we would need a way of POSTing requests via such pages. Some such pages,
e.g. a custom user editor, could be implemented using the JSON API, but it
would "be really cool" if we could support wholly custom APIs this way,
e.g. by POSTing form data to /MyQueryPage to execute arbitrary SQL.
2) Custom pages serve output in one of the following forms:
a) a "raw" page (stored in the db) with a client-specified mime-type. This
could be a complete HTML page in and of itself (including DOCTYPE, HEAD,
etc.) or it could be a "stub" which just loads JS code, and the JS code
then gets triggered via onLoad() (or equivalent, e.g.
jQuery(function(){...})). (The latter is essentially what my JSON app
prototypes all do.)
b) the page is intended to be embedded as the content part of the standard
fossil page, and would be wrapped up by fossil in that part of the page.
This is the most code-invasive approach of the three, i think, but
shouldn't be too bad.
Whether or not a page is served in modes (a) or (b) would be a
configuration option for that page. In the case of (a), a mime-type
specified by the page's creator would be used for the response. e.g. this
could be used to serve raw JS files, CSS files, and _theoretically_ even
binary data.
Ideally option (b) would be split into "layout template" and "snippets"
which can get embedded in that template, but i have put aside the templates
for the time being because there are a whole slew of other problems
associated with them. So let's turn to that for a moment...
Creating APIs for simple template/macro substitution is easy to do, such
that the following simple case could be used:
snippet = <span class="${{cssClass}}">${{value}}</span>
we could then feed that to a processor which would replace cssClass and
value with whatever we like. However useful that might be, templates are
only really useful if we can support flow control/looping constructs. That
means either a custom grammar or upgrading to a scripting language. TH1 is
of course the obvious choice, but i have no idea what it's limitations are
vis-a-vis flow control structures like if/else and loops. We would also
need the formatting capabilities of printf and friends so that clients can
have some reasonable level of control over numeric output and such. We have
the code for this, so that is not a problem it and of itself, but how to
get access to it from template code is the immediate problem. Note that we
don't really need looping constructs if we embed functions which provide
loop-like behaviour for us, e.g. for_loop( 1, 10, "some code to eval() or a
function ref to call" ).
As an example, let's say we want a custom timeline page which lists the
checkin and branch timelines separately. For such a page we have at least 2
loops: the result set of the checkin timeline and the one for the branches
timeline. At the very least, we'd need a client-customizable way of
rendering the timestamps, which implies at least a basic scripting
interface.
If TH1 is not powerful enough for this case (i don't know if it is or
isn't, or if it is easy enough to extend), the next obvious choice would be
the TCL support (which is, AFAIK, still living in its own branch?).
Without full script support, the only flexible way to do pages like the
above timeline example would be to create the page on the client side. This
is easy enough to do (i've got several prototypes) but it limits the page
to contain only info/structures which the user opening the page has access
to see via the JSON API (which would need to be used to fetch the data to
be rendered). If the page is rendered server-side (TH1 or TCL) the
rendering code can have access to data which pure client-side code might
not have. One example does come to mind: the admin might like to have a
public page which requires running a custom SELECT query or two against the
db (the /stat page is a good example). Such queries cannot be executed by
non-admin users via the JSON API (it restricts SQL queries to admins), so
the such a page would need to run on the server side using only SQL code
the admin has specified for that page (as opposed to allowing arbitrary SQL
from the client).
Another detail to consider is the path(s) we want for custom pages. Do we
want:
a) /MyPage
b) /custom/MyPage
or something else? Option (a) would require adding a "fallback" handler to
the page/command lookup code which looks in the db for a matching name if
the provided path/page is not found. Option (b) would move such logic into
a command/page of its own (named "custom" in this example). My gut says
that (b) would be cleaner, but (a) is arguably prettier and could
(depending on the order of page/command lookups) be used to _override_
built-in pages with custom ones, which might be really cool or just cause
trouble, depending on too many variables to consider.
Anyway...
if only all of life's problems were as harmless yet interesting...
Ideas? Concerns? Epiphanies?
--
----- stephan beal
http://wanderinghorse.net/home/stephan/
http://gplus.to/sgbeal
_______________________________________________
fossil-users mailing list
[email protected]
http://lists.fossil-scm.org:8080/cgi-bin/mailman/listinfo/fossil-users