425 lines
12 KiB
Plaintext
425 lines
12 KiB
Plaintext
==========================
|
|
The kupu Templating System
|
|
==========================
|
|
|
|
Problem
|
|
=======
|
|
|
|
kupu is an editor with many features, many of them optional or
|
|
specific to certain integration implementations. While it is fairly
|
|
easy to maintain the JavaScript side of features through separate
|
|
files, the HTML template has to be custom constructed for every
|
|
feature combination.
|
|
|
|
Kupu 1.0 thus comes with five different templates. Zope-based
|
|
applications would just require one template because they could turn
|
|
certain parts of the template on and off by filling ZPT
|
|
slots. However, applications not using Zope Page Templates (ZPTs) have
|
|
to customize one of the provided templates. That not only means manual
|
|
editing of the templates in order to configure the feature set, it
|
|
also means the lack of an automatic update when a new kupu version is
|
|
released.
|
|
|
|
|
|
Goals
|
|
-----
|
|
|
|
We want to...
|
|
|
|
* involve as few files as possible when adding a new feature to
|
|
kupu. We preferrably only want to add a file for the JavaScript
|
|
part of the feature and a file for the template part of the
|
|
feature.
|
|
|
|
* be able to disable a feature whenever we want under any
|
|
circumstance.
|
|
|
|
* allow and encourage third party developers to develop plugins
|
|
(i.e. new features) for kupu that can be distributed outside the
|
|
main kupu integration and yet be included without manual
|
|
adjustments.
|
|
|
|
* be able to include platform specific markup when necessary.
|
|
|
|
* rely on templating standards (XML, XSLT, XInclude, etc.)
|
|
|
|
It is clear, that a system-indepentend templating system is needed to
|
|
ease kupu's integration into other systems and any customization that
|
|
is required by such a process.
|
|
|
|
|
|
Definitions
|
|
-----------
|
|
|
|
Slot
|
|
|
|
A position in a template, at which markup can be inserted. Example:
|
|
the HTML header, the HTML body.
|
|
|
|
Feature
|
|
|
|
A bundle of code and markup providing a certain set of
|
|
functionality. Examples for basic features are: the editor frame,
|
|
toolbar with buttons, colorchooser, synchronous form-based or
|
|
asynchronous document-centric editing support. Examples for more
|
|
advanced and optional features are: save on part, autosave, context
|
|
menu, source editing, library drawer.
|
|
|
|
Part
|
|
|
|
A part of a Feature. While order usually does not matter when
|
|
writing JavaScript prototypes (or including them from a file), order
|
|
in a template *does* matter. Therefore, a Feature can consist of
|
|
different parts which are distributed throughout the template at the
|
|
appropriate places (Slots). Example: The parts of the source edit
|
|
feature are the button in the toolbar that enables source editing
|
|
and the function that is called when the button is clicked.
|
|
|
|
Implementation
|
|
|
|
Combination of target platform specific Features or Parts of
|
|
Features. The way Features are implemented might vary througout
|
|
different integration layers, due to the requirements of the target
|
|
platforms. Examples of Implementations are: Default (the default set
|
|
of Features), Zope (re-implementation of certain features for Zope
|
|
integration), Plone, Silva, Apache Lenya, MMBase, etc.
|
|
|
|
Distribution
|
|
|
|
Set of Feature definitions or Feature disablings in the context of a
|
|
certain Implementation or order of Implementations. Distributions
|
|
can not only differ from integration layer to integration layer, but
|
|
also be customized for every application or system Kupu is part
|
|
of. Kupu thus only provides *default* distributions, e.g.:
|
|
Distribution for default Features, Distribution for Plone,
|
|
Distribution for Silva, Distributon for Silva, etc. Web Developer
|
|
XYZ might choose to make a custom distribution for the application
|
|
(s)he's building for customer ABC.
|
|
|
|
|
|
Whenever the above defined words appear in the text below, their first
|
|
letter is capitalized. Otherwise, the term is used in its conventional
|
|
meaning.
|
|
|
|
|
|
Perceptions
|
|
-----------
|
|
|
|
* An Implementation overrides one or more features defined by default
|
|
Implementations or defines new features
|
|
|
|
* Wiring Parts to Slots is Distribution-specific.
|
|
|
|
* Implementation Order is Distribution-specific.
|
|
|
|
* Feature enabling/disabling is Distribution-specific, but usually
|
|
more specific to the target application than to the pre-packaged
|
|
Distribution.
|
|
|
|
|
|
Proposal
|
|
========
|
|
|
|
|
|
File system structure
|
|
---------------------
|
|
|
|
kupu's former main template (kupumacros.html) is split into logical
|
|
chunks resembling Features and Parts as defined above. Each Feature
|
|
and all its parts resides in an XML file with the file ending '.kupu'.
|
|
All features of an Implementation reside in the same directory. The
|
|
main kupu distribution includes a directory named 'default'. It
|
|
contains a default set of Features in their default Implementation.
|
|
Platform specific markup resides in other Implementation directories.
|
|
|
|
A Distribution is represented in an XML file typically named
|
|
'dist.kupu'. It defines an order in which Features are looked up in
|
|
Implementations and can optionally disable Features.
|
|
|
|
A system consisting of XSLT templates is used to parse a Distribution
|
|
configuration file and construct markup custom to that particular
|
|
Distribution. The XInclude standard is used to combine all .kupu XML
|
|
files to one large tree that can be fed to an XSLT processor.
|
|
|
|
Overview:
|
|
~~~~~~~~~
|
|
|
|
=============================== ================================================
|
|
kupu/ (the root directory of the kupu distribution)
|
|
kupu/dist.kupu (kupu's default Distribution file)
|
|
kupu/default/ ('default' Implementation of Features)
|
|
kupu/default/feature1.kupu
|
|
kupu/default/feature2.kupu
|
|
kupu/default/wire.kupu (wires Parts to Slots)
|
|
kupu/default/include.kupu (imports all Features and the wiring from the
|
|
'default' Implementation for convenience)
|
|
kupu/foo/ ('Foo' Implementation)
|
|
kupu/foo/feature1.kupu
|
|
kupu/foo/feature2.kupu
|
|
kupu/foo/wire.kupu ([re-]wires [additional] Parts to Slots)
|
|
kupu/foo/include.kupu (imports all Features and the wiring from the
|
|
'default' Implementation for convenience)
|
|
kupu/foo/foo.py (some additional platform specific files)
|
|
kupu/foo/Foo.class
|
|
kupu/foo/fooicon.png
|
|
=============================== ================================================
|
|
|
|
XML format
|
|
----------
|
|
|
|
::
|
|
|
|
<grammar xmlns="http://relaxng.org/ns/structure/1.0">
|
|
|
|
<start>
|
|
<ref name="dist" />
|
|
</start>
|
|
|
|
<define name="dist">
|
|
<element name="dist">
|
|
<interleave>
|
|
<ref name="featureOrInclude" />
|
|
<ref name="implementationOrder" />
|
|
<ref name="expand" />
|
|
</interleave>
|
|
</element>
|
|
</define>
|
|
|
|
<define name="feature">
|
|
<element name="feature">
|
|
<attribute name="name">
|
|
<text />
|
|
</attribute>
|
|
<attribute name="implementation">
|
|
<text />
|
|
</attribute>
|
|
<element name="part">
|
|
<attribute name="name">
|
|
<text />
|
|
</attribute>
|
|
<ref name="partContents" />
|
|
<element>
|
|
</element>
|
|
</define>
|
|
|
|
<define name="featureOrInclude">
|
|
<zeroOrMore>
|
|
<choice>
|
|
<!-- we can either include more features from elsewhere -->
|
|
<element name="include">
|
|
<ref name="featureOrInclude" />
|
|
</element>
|
|
|
|
<!-- or provide actual features -->
|
|
<ref name="feature" />
|
|
</choice>
|
|
</zeroOrMore>
|
|
</define>
|
|
|
|
<define name="wire">
|
|
<element name="wire">
|
|
<attribute name="implementation">
|
|
<text />
|
|
</attribute>
|
|
<zeroOrMore>
|
|
<ref name="fillSlot" />
|
|
</zeroOrMore>
|
|
</element>
|
|
</define>
|
|
|
|
<define name="fillSlot">
|
|
<element name="fill-slot">
|
|
<attribute name="name">
|
|
<text />
|
|
</attribute>
|
|
<zeroOrMore>
|
|
<choice>
|
|
<ref name="arbitraryMarkup" />
|
|
<ref name="insertPart" />
|
|
</choice>
|
|
</zeroOrMore>
|
|
</element>
|
|
</define>
|
|
|
|
<define name="expand">
|
|
<oneOrMore>
|
|
<element name="expand">
|
|
<zeroOrMore>
|
|
<ref name="defineSlot" />
|
|
</zeroOrMore>
|
|
</element>
|
|
</oneOrMore>
|
|
</define>
|
|
|
|
<define name="defineSlot">
|
|
<element name="define-slot">
|
|
<attribute name="name">
|
|
<text />
|
|
</attribute>
|
|
</element>
|
|
</define>
|
|
|
|
<define name="implementationOrder">
|
|
<element name="implementation-order>
|
|
<oneOrMore>
|
|
<element name="implementation">
|
|
<attribute name="name">
|
|
<text />
|
|
</attribute>
|
|
</element>
|
|
</oneOrMore>
|
|
</element>
|
|
</define>
|
|
|
|
<define name="arbitraryMarkup">
|
|
<element name=""> <!-- XXX arbitrary markup -->
|
|
<ref name="partContents" />
|
|
</element>
|
|
</define>
|
|
|
|
<define name="insertPart">
|
|
<element name="insert-part">
|
|
<attribute name="name">
|
|
<text />
|
|
</attribute>
|
|
<attribute name="part">
|
|
<text />
|
|
</attribute>
|
|
</element>
|
|
</define>
|
|
|
|
<define name="partContents">
|
|
<zeroOrMore>
|
|
<choice>
|
|
<ref name="arbitraryMarkup" />
|
|
<ref name="defineSlot" />
|
|
</choice>
|
|
</zeroOrMore>
|
|
</define>
|
|
|
|
</grammar>
|
|
|
|
|
|
Example markup:
|
|
---------------
|
|
|
|
dist.kupu
|
|
~~~~~~~~~
|
|
|
|
::
|
|
|
|
<kupu:dist
|
|
xmlns:kupu="http://kupu.oscom.org/namespaces/dist"
|
|
xmlns:xi="http://www.w3.org/2001/XInclude"
|
|
>
|
|
|
|
<!-- Include implementations -->
|
|
<xi:include href="default/include.kupu" />
|
|
<xi:include href="zope2/include.kupu" />
|
|
<xi:include href="zope3/include.kupu" />
|
|
<xi:include href="silva/include.kupu" />
|
|
<xi:include href="plone/include.kupu" />
|
|
<xi:include href="apache-lenya/include.kupu" />
|
|
<xi:include href="roundup/include.kupu" />
|
|
<!-- ... -->
|
|
|
|
<!-- Define the default slot to start with -->
|
|
<kupu:expand>
|
|
<kupu:define-slot name="start" />
|
|
</kupu:expand>
|
|
|
|
<!-- Define an order for the implementations that are to be used. The
|
|
most specific one is located at the top, the last one should
|
|
always be 'default'. -->
|
|
<kupu:implementation-order>
|
|
<!-- most specific one at top -->
|
|
<kupu:implementation name="plone" />
|
|
<kupu:implementation name="default" />
|
|
</kupu:implementation-order>
|
|
|
|
<!-- Plone does not want to use certain features -->
|
|
<kupu:disable-feature name="toolboxes" />
|
|
<kupu:disable-feature name="save" />
|
|
<kupu:disable-feature name="colorchooser" />
|
|
|
|
</kupu:dist>
|
|
|
|
|
|
some_impl/include.kupu
|
|
~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
::
|
|
|
|
<kupu:include
|
|
xmlns:kupu="http://kupu.oscom.org/namespaces/dist"
|
|
xmlns:xi="http://www.w3.org/2001/XInclude"
|
|
>
|
|
|
|
<!-- Include features -->
|
|
<xi:include href="feature1.kupu" />
|
|
<xi:include href="feature2.kupu" />
|
|
|
|
</kupu:include>
|
|
|
|
some_impl/feature1.kupu
|
|
~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
::
|
|
|
|
<kupu:feature
|
|
name="feature1"
|
|
implementation="some_impl"
|
|
>
|
|
|
|
<kupu:part name="part1">
|
|
<div>
|
|
<p>Part 1 of Feature 1</p>
|
|
</div>
|
|
</kupu:part>
|
|
|
|
<kupu:part name="part2">
|
|
<p>
|
|
|
|
This part defines a slot that can be filled with more markup by
|
|
other features:
|
|
|
|
<div id="foobar">
|
|
<kupu:define-slot name="foobar" />
|
|
</div>
|
|
|
|
</p>
|
|
</kupu:part>
|
|
|
|
</kupu:feature>
|
|
|
|
some_impl/wire.kupu
|
|
~~~~~~~~~~~~~~~~~~~
|
|
|
|
::
|
|
|
|
<kupu:wire
|
|
implementation="some_impl"
|
|
xmlns:kupu="http://kupu.oscom.org/namespaces/dist"
|
|
>
|
|
|
|
<kupu:fill-slot name="foobar">
|
|
<kupu:insert-part feature="some_feature" part="some_part" />
|
|
<kupu:insert-part feature="another_feature" part="a_part" />
|
|
</kupu:fill-slot>
|
|
|
|
</kupu:wire>
|
|
|
|
|
|
Questions/Problems
|
|
==================
|
|
|
|
- Yet to be solved: How to handle i18n in templates? Temporary
|
|
solution: use ZPT's i18n markup so that we have at least a declaration
|
|
of what is to be i18n'd.
|
|
|
|
|
|
Futures
|
|
=======
|
|
|
|
- Feature/Part dependencies
|