1: ==========================
2: The kupu Templating System
3: ==========================
4:
5: Problem
6: =======
7:
8: kupu is an editor with many features, many of them optional or
9: specific to certain integration implementations. While it is fairly
10: easy to maintain the JavaScript side of features through separate
11: files, the HTML template has to be custom constructed for every
12: feature combination.
13:
14: Kupu 1.0 thus comes with five different templates. Zope-based
15: applications would just require one template because they could turn
16: certain parts of the template on and off by filling ZPT
17: slots. However, applications not using Zope Page Templates (ZPTs) have
18: to customize one of the provided templates. That not only means manual
19: editing of the templates in order to configure the feature set, it
20: also means the lack of an automatic update when a new kupu version is
21: released.
22:
23:
24: Goals
25: -----
26:
27: We want to...
28:
29: * involve as few files as possible when adding a new feature to
30: kupu. We preferrably only want to add a file for the JavaScript
31: part of the feature and a file for the template part of the
32: feature.
33:
34: * be able to disable a feature whenever we want under any
35: circumstance.
36:
37: * allow and encourage third party developers to develop plugins
38: (i.e. new features) for kupu that can be distributed outside the
39: main kupu integration and yet be included without manual
40: adjustments.
41:
42: * be able to include platform specific markup when necessary.
43:
44: * rely on templating standards (XML, XSLT, XInclude, etc.)
45:
46: It is clear, that a system-indepentend templating system is needed to
47: ease kupu's integration into other systems and any customization that
48: is required by such a process.
49:
50:
51: Definitions
52: -----------
53:
54: Slot
55:
56: A position in a template, at which markup can be inserted. Example:
57: the HTML header, the HTML body.
58:
59: Feature
60:
61: A bundle of code and markup providing a certain set of
62: functionality. Examples for basic features are: the editor frame,
63: toolbar with buttons, colorchooser, synchronous form-based or
64: asynchronous document-centric editing support. Examples for more
65: advanced and optional features are: save on part, autosave, context
66: menu, source editing, library drawer.
67:
68: Part
69:
70: A part of a Feature. While order usually does not matter when
71: writing JavaScript prototypes (or including them from a file), order
72: in a template *does* matter. Therefore, a Feature can consist of
73: different parts which are distributed throughout the template at the
74: appropriate places (Slots). Example: The parts of the source edit
75: feature are the button in the toolbar that enables source editing
76: and the function that is called when the button is clicked.
77:
78: Implementation
79:
80: Combination of target platform specific Features or Parts of
81: Features. The way Features are implemented might vary througout
82: different integration layers, due to the requirements of the target
83: platforms. Examples of Implementations are: Default (the default set
84: of Features), Zope (re-implementation of certain features for Zope
85: integration), Plone, Silva, Apache Lenya, MMBase, etc.
86:
87: Distribution
88:
89: Set of Feature definitions or Feature disablings in the context of a
90: certain Implementation or order of Implementations. Distributions
91: can not only differ from integration layer to integration layer, but
92: also be customized for every application or system Kupu is part
93: of. Kupu thus only provides *default* distributions, e.g.:
94: Distribution for default Features, Distribution for Plone,
95: Distribution for Silva, Distributon for Silva, etc. Web Developer
96: XYZ might choose to make a custom distribution for the application
97: (s)he's building for customer ABC.
98:
99:
100: Whenever the above defined words appear in the text below, their first
101: letter is capitalized. Otherwise, the term is used in its conventional
102: meaning.
103:
104:
105: Perceptions
106: -----------
107:
108: * An Implementation overrides one or more features defined by default
109: Implementations or defines new features
110:
111: * Wiring Parts to Slots is Distribution-specific.
112:
113: * Implementation Order is Distribution-specific.
114:
115: * Feature enabling/disabling is Distribution-specific, but usually
116: more specific to the target application than to the pre-packaged
117: Distribution.
118:
119:
120: Proposal
121: ========
122:
123:
124: File system structure
125: ---------------------
126:
127: kupu's former main template (kupumacros.html) is split into logical
128: chunks resembling Features and Parts as defined above. Each Feature
129: and all its parts resides in an XML file with the file ending '.kupu'.
130: All features of an Implementation reside in the same directory. The
131: main kupu distribution includes a directory named 'default'. It
132: contains a default set of Features in their default Implementation.
133: Platform specific markup resides in other Implementation directories.
134:
135: A Distribution is represented in an XML file typically named
136: 'dist.kupu'. It defines an order in which Features are looked up in
137: Implementations and can optionally disable Features.
138:
139: A system consisting of XSLT templates is used to parse a Distribution
140: configuration file and construct markup custom to that particular
141: Distribution. The XInclude standard is used to combine all .kupu XML
142: files to one large tree that can be fed to an XSLT processor.
143:
144: Overview:
145: ~~~~~~~~~
146:
147: =============================== ================================================
148: kupu/ (the root directory of the kupu distribution)
149: kupu/dist.kupu (kupu's default Distribution file)
150: kupu/default/ ('default' Implementation of Features)
151: kupu/default/feature1.kupu
152: kupu/default/feature2.kupu
153: kupu/default/wire.kupu (wires Parts to Slots)
154: kupu/default/include.kupu (imports all Features and the wiring from the
155: 'default' Implementation for convenience)
156: kupu/foo/ ('Foo' Implementation)
157: kupu/foo/feature1.kupu
158: kupu/foo/feature2.kupu
159: kupu/foo/wire.kupu ([re-]wires [additional] Parts to Slots)
160: kupu/foo/include.kupu (imports all Features and the wiring from the
161: 'default' Implementation for convenience)
162: kupu/foo/foo.py (some additional platform specific files)
163: kupu/foo/Foo.class
164: kupu/foo/fooicon.png
165: =============================== ================================================
166:
167: XML format
168: ----------
169:
170: ::
171:
172: <grammar xmlns="http://relaxng.org/ns/structure/1.0">
173:
174: <start>
175: <ref name="dist" />
176: </start>
177:
178: <define name="dist">
179: <element name="dist">
180: <interleave>
181: <ref name="featureOrInclude" />
182: <ref name="implementationOrder" />
183: <ref name="expand" />
184: </interleave>
185: </element>
186: </define>
187:
188: <define name="feature">
189: <element name="feature">
190: <attribute name="name">
191: <text />
192: </attribute>
193: <attribute name="implementation">
194: <text />
195: </attribute>
196: <element name="part">
197: <attribute name="name">
198: <text />
199: </attribute>
200: <ref name="partContents" />
201: <element>
202: </element>
203: </define>
204:
205: <define name="featureOrInclude">
206: <zeroOrMore>
207: <choice>
208: <!-- we can either include more features from elsewhere -->
209: <element name="include">
210: <ref name="featureOrInclude" />
211: </element>
212:
213: <!-- or provide actual features -->
214: <ref name="feature" />
215: </choice>
216: </zeroOrMore>
217: </define>
218:
219: <define name="wire">
220: <element name="wire">
221: <attribute name="implementation">
222: <text />
223: </attribute>
224: <zeroOrMore>
225: <ref name="fillSlot" />
226: </zeroOrMore>
227: </element>
228: </define>
229:
230: <define name="fillSlot">
231: <element name="fill-slot">
232: <attribute name="name">
233: <text />
234: </attribute>
235: <zeroOrMore>
236: <choice>
237: <ref name="arbitraryMarkup" />
238: <ref name="insertPart" />
239: </choice>
240: </zeroOrMore>
241: </element>
242: </define>
243:
244: <define name="expand">
245: <oneOrMore>
246: <element name="expand">
247: <zeroOrMore>
248: <ref name="defineSlot" />
249: </zeroOrMore>
250: </element>
251: </oneOrMore>
252: </define>
253:
254: <define name="defineSlot">
255: <element name="define-slot">
256: <attribute name="name">
257: <text />
258: </attribute>
259: </element>
260: </define>
261:
262: <define name="implementationOrder">
263: <element name="implementation-order>
264: <oneOrMore>
265: <element name="implementation">
266: <attribute name="name">
267: <text />
268: </attribute>
269: </element>
270: </oneOrMore>
271: </element>
272: </define>
273:
274: <define name="arbitraryMarkup">
275: <element name=""> <!-- XXX arbitrary markup -->
276: <ref name="partContents" />
277: </element>
278: </define>
279:
280: <define name="insertPart">
281: <element name="insert-part">
282: <attribute name="name">
283: <text />
284: </attribute>
285: <attribute name="part">
286: <text />
287: </attribute>
288: </element>
289: </define>
290:
291: <define name="partContents">
292: <zeroOrMore>
293: <choice>
294: <ref name="arbitraryMarkup" />
295: <ref name="defineSlot" />
296: </choice>
297: </zeroOrMore>
298: </define>
299:
300: </grammar>
301:
302:
303: Example markup:
304: ---------------
305:
306: dist.kupu
307: ~~~~~~~~~
308:
309: ::
310:
311: <kupu:dist
312: xmlns:kupu="http://kupu.oscom.org/namespaces/dist"
313: xmlns:xi="http://www.w3.org/2001/XInclude"
314: >
315:
316: <!-- Include implementations -->
317: <xi:include href="default/include.kupu" />
318: <xi:include href="zope2/include.kupu" />
319: <xi:include href="zope3/include.kupu" />
320: <xi:include href="silva/include.kupu" />
321: <xi:include href="plone/include.kupu" />
322: <xi:include href="apache-lenya/include.kupu" />
323: <xi:include href="roundup/include.kupu" />
324: <!-- ... -->
325:
326: <!-- Define the default slot to start with -->
327: <kupu:expand>
328: <kupu:define-slot name="start" />
329: </kupu:expand>
330:
331: <!-- Define an order for the implementations that are to be used. The
332: most specific one is located at the top, the last one should
333: always be 'default'. -->
334: <kupu:implementation-order>
335: <!-- most specific one at top -->
336: <kupu:implementation name="plone" />
337: <kupu:implementation name="default" />
338: </kupu:implementation-order>
339:
340: <!-- Plone does not want to use certain features -->
341: <kupu:disable-feature name="toolboxes" />
342: <kupu:disable-feature name="save" />
343: <kupu:disable-feature name="colorchooser" />
344:
345: </kupu:dist>
346:
347:
348: some_impl/include.kupu
349: ~~~~~~~~~~~~~~~~~~~~~~
350:
351: ::
352:
353: <kupu:include
354: xmlns:kupu="http://kupu.oscom.org/namespaces/dist"
355: xmlns:xi="http://www.w3.org/2001/XInclude"
356: >
357:
358: <!-- Include features -->
359: <xi:include href="feature1.kupu" />
360: <xi:include href="feature2.kupu" />
361:
362: </kupu:include>
363:
364: some_impl/feature1.kupu
365: ~~~~~~~~~~~~~~~~~~~~~~~
366:
367: ::
368:
369: <kupu:feature
370: name="feature1"
371: implementation="some_impl"
372: >
373:
374: <kupu:part name="part1">
375: <div>
376: <p>Part 1 of Feature 1</p>
377: </div>
378: </kupu:part>
379:
380: <kupu:part name="part2">
381: <p>
382:
383: This part defines a slot that can be filled with more markup by
384: other features:
385:
386: <div id="foobar">
387: <kupu:define-slot name="foobar" />
388: </div>
389:
390: </p>
391: </kupu:part>
392:
393: </kupu:feature>
394:
395: some_impl/wire.kupu
396: ~~~~~~~~~~~~~~~~~~~
397:
398: ::
399:
400: <kupu:wire
401: implementation="some_impl"
402: xmlns:kupu="http://kupu.oscom.org/namespaces/dist"
403: >
404:
405: <kupu:fill-slot name="foobar">
406: <kupu:insert-part feature="some_feature" part="some_part" />
407: <kupu:insert-part feature="another_feature" part="a_part" />
408: </kupu:fill-slot>
409:
410: </kupu:wire>
411:
412:
413: Questions/Problems
414: ==================
415:
416: - Yet to be solved: How to handle i18n in templates? Temporary
417: solution: use ZPT's i18n markup so that we have at least a declaration
418: of what is to be i18n'd.
419:
420:
421: Futures
422: =======
423:
424: - Feature/Part dependencies
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>