Annotation of kupuMPIWG/doc/LIBRARIES.txt, revision 1.1.1.1
1.1 dwinter 1: ================================
2: Image and Link Libraries in Kupu
3: ================================
4:
5: Abstract
6: --------
7:
8: This document describes the Library feature of the Kupu WYSIWYG
9: editor. It defines the behaviour on both the client and the server and
10: serves as a specification for the XML protocol that is used for their
11: interaction.
12:
13:
14: Motivation
15: ----------
16:
17: Kupu is a visual editor for content management systems, with a target
18: audience of regular users without a high technical profile. For this
19: audience, Word is the incumbent.
20:
21: In addition to text, Kupu users need a simple, usable, and
22: high-performance system for getting images and hyperlinks into their
23: pages. Sometimes they want to *browse* to find these assets.
24: Sometimes they want to *search*, particularly for large collections.
25:
26: Regarding usability, open source CMS projects don't have many
27: browser-side developers with good usability backgrounds. Since Kupu
28: is an oscom.org project, it is a goal to move the UI rendering from
29: the server (where talent would be dispersed among projects) to the
30: client (where one UI can work for many servers). Therefore, the Kupu
31: Library only requests XML from the CMS, not HTML.
32:
33: Note: Though Kupu will work with IE 5.5 sans service packs, Kupu
34: requires MS XML 3.0 or higher. Any IE 5.5 that is up-to-date on
35: security updates, and any IE 6 or Mozilla 1.3+ can use the Kupu
36: Library.
37:
38:
39: Definitions
40: -----------
41:
42: Library
43:
44: A static or dynamic collection of resources and collections defined
45: at a top level. Libraries have no parents from a UI perspective,
46: where as the collection they represent might have a parent
47: collection.
48:
49: Collection
50:
51: A static or dynamic collection of resources and collections,
52: modelled after WebDAV collections.
53:
54: Resource
55:
56: A named and URI-locatable object with associated metadata, such as
57: title, description, preview, size, etc.
58:
59:
60: Process overview
61: ----------------
62:
63: 1. The user opens a drawer in Kupu. Kupu requests a list of available
64: libraries. The server answers with a list of libraries possibly
65: containing URIs at which to get the content listing of each library.
66:
67: 2. Upon user request, Kupu loads the contents of a library and present
68: it to the user. Already opened libraries are not reloaded from the
69: server
70:
71: 3. A user selects a resource at which point Kupu presents the
72: associated metadata and may optionally load a preview image.
73:
74: 4. Double clicking on a collection or selecting a new library triggers
75: step 2 again.
76:
77: 5. Clicking on a resource and clicking "Insert" (for an image) or
78: "Link" (for links) updates the document and closes the drawer.
79:
80: 6. If the cursor is on a link or image, the drawer allows editing the
81: image/link attributes.
82:
83:
84: List of libraries
85: -----------------
86:
87: Kupu issues a simple HTTP GET request to a URL defined in the
88: 'libraries' attribute of the iframe. The server returns XML conforming
89: to the following schema::
90:
91: <grammar xmlns="http://relaxng.org/ns/structure/1.0">
92:
93: <start>
94: <ref name="librariesDocumentElement" />
95: </start>
96:
97: <define name="librariesDocumentElement">
98: <element name="libraries">
99: <zeroOrMore>
100: <ref name="library" />
101: </zeroOrMore>
102: </element>
103: </define>
104:
105: <define name="library"
106: <element name="library">
107: <interleave>
108: <ref name="commonToAllItems" />
109: <choice>
110: <ref name="collectionItems" />
111: <ref name="itemsSource" />
112: </choice>
113: </interleave>
114: </element>
115: </define>
116:
117: <define name="commonToAllItems">
118: <attribute name="id">
119: <!-- Must be unique among all libraries, resources and collections. -->
120: <text />
121: </attribute>
122:
123: <interleave>
124: <element name="uri">
125: <text />
126: </element>
127:
128: <optional>
129: <element name="label">
130: <text />
131: </element>
132: </optional>
133:
134: <element name="title">
135: <text />
136: </element>
137:
138: <optional>
139: <element name="icon">
140: <text />
141: </element>
142: </optional>
143: </interleave>
144: </define>
145:
146: <define name="collectionItems">
147: <element name="items">
148: <zeroOrMore>
149: <ref name="collectionItem" />
150: </zeroOrMore>
151: <optional>
152: <element name="uploadbutton" />
153: </optional>
154: </element>
155: </define>
156:
157: <define name="itemsSource">
158: <element name="src">
159: <text />
160: </element>
161: </define>
162:
163: <define name="collectionItem">
164: <choice>
165: <element name="resource">
166: <ref name="commonToAllItems" />
167: <ref name="extraResourceInfo" />
168: </element>
169: <element name="collection">
170: <ref name="commonToAllItems" />
171: <ref name="itemsSource" />
172: </element>
173: </choice>
174: <define>
175:
176: <define name="extraResourceInfo">
177: <interleave>
178: <optional>
179: <element name="preview">
180: <text />
181: </element>
182: </optional>
183:
184: <optional>
185: <element name="size">
186: <text />
187: </element>
188: </optional>
189:
190: <optional>
191: <element name="type">
192: <text />
193: </element>
194: </optional>
195: </interleave>
196: </define>
197:
198: </grammar>
199:
200:
201: For example::
202:
203: <libraries>
204:
205: <library id="http://path/to/folder">
206: <title>Current Folder</title>
207: <icon>http://path/to/icon.jpg</icon>
208: <src>http://server/current/folder/resources.kupu</src>
209: </library>
210:
211: <library id="http://path/to/other/someotherfolder">
212: <title>Some Other Folder</title>
213: <icon>http://path/to/icon.jpg</icon>
214: <src>http:/server/other/folder/resources.kupu</src>
215: </library>
216:
217: <library id="recentitems">
218: <title>Recent Items</title>
219: <icon>http://path/to/icon.jpg</icon>
220: <items />
221: </library>
222:
223: </libraries>
224:
225:
226: Kupu parses this XML to a DOM managed in JavaScript and displays it
227: using an XSLT stylesheet. The DOM tree is stored throughout the whole
228: Kupu session.
229:
230:
231: Browser-side architecture
232: ------------------------------------
233:
234: When the drawer is opened, Kupu loads the XML data about the libraries
235: into a JS property that holds an XML DOM. The Sarissa cross-browser
236: abstraction for XML (http://sarissa.sf.net) is used.
237:
238: As the user clicks, more XML data are loaded if that collection hasn't
239: been visited yet. The loaded XML is then appended into the XML DOM.
240: The node that was clicked on has an attribute set to mark it as
241: selected. Kupu then runs an XSLT on the XML DOM to re-generate the
242: drawer contents (as HTML), and updates the HTML node with the output.
243: The use of XSLT and XPath give increased performance, lower line
244: count, and better IE/Mozilla compatibility.
245:
246: As an implementation note, XML is extremely compressible. With
247: mod_deflate and other server-compression approaches, at least a
248: thousand entries can be encoded in 100 Kb.
249:
250: User opens on a library
251: -----------------------
252:
253: In case a collection or library has been active before, it is
254: deselected (by removing the 'selected' attribute on the DOM node). The
255: DOM node of the library the user has chosen is selected (by setting
256: the 'selected' attribute). Also, visually deselect the before selected
257: library (by unsetting a CSS class) and mark the newly selected library
258: (with a CSS class).
259:
260: In case its <library> element provides the <src> subelement, an HTTP
261: GET to that URI is made, the returned XML retrieved, turned into a DOM
262: tree and the resulting <items> node of the result appended to the
263: library DOM node. That step is not made in case the <library> node
264: directly provides the <items> node.
265:
266: Now, the XSLT is executed again, presenting the newly selected node
267: (by querying for the node with the 'selected' attribute) and its
268: contents.
269:
270: When a library's contents has to be retrieved with an extra request,
271: it is returned according to the following schema (using definitions
272: from above)::
273:
274: <grammar xmlns="http://relaxng.org/ns/structure/1.0">
275:
276: <start>
277: <ref name="libraryDocumentElement" />
278: </start>
279:
280: <define name="libraryDocumentElement">
281: <element name="library">
282: <ref name="commonToAllItems" />
283: <ref name="collectionItems" />
284: </element>
285: </define>
286:
287: </grammar>
288:
289:
290: For example::
291:
292: <library id="some_unique_id">
293: <title>Current folder</title>
294: <uri>http://server/current/folder</uri>
295: <icon>http://server/folder.ico</icon>
296: <items>
297: <resource id="another_unique_id">
298: <title>Foo img</title>
299: <uri>http://server/current/folder/foo.jpg</uri>
300: <icon>http://server/image.ico</icon>
301: </resource>
302: <collection id="a_collections_unique_id">
303: <title>Some collection</title>
304: <uri>http://server/current/folder/collection</uri>
305: <icon>http://server/folder.ico</icon>
306: </collection>
307: </items>
308: </library>
309:
310:
311: User opens a collection
312: -----------------------
313:
314: Unselect the previously selected collection and try to execute one of
315: three cases in order:
316:
317: * The node of selected collection is queried for an attribute
318: 'loadedInNode'. If it exists, it refers to an id of a node which
319: already contains that collection's items. Select that node and
320: execute the XSLT to present changes.
321:
322: * The selected collection node does not have a 'loadedInNode'
323: attribute. Therefore, the selected collection's URI is read and the
324: document element's children are queried with an XPath to check
325: whether the collection with that URI was already loaded before and
326: attached to the document element. If so, the selected collection
327: node receives an attribute 'loadedInNode' with the value of the
328: corresponding collection node below the document element, which is
329: selected (by setting the 'selected' attribute). The XSLT is executed
330: to present the changes.
331:
332: * The selected collection node has no 'loadedInNode' attribute and
333: there is no preloaded collection node of that URI. The selected
334: node's <src> subelement is read. An HTTP GET request is made to that
335: URI and the items XML data retrieved and turned into a DOM tree. The
336: <collection> node of that resulting tree is given a new unique ID,
337: appended to the document element of the library DOM tree and
338: selected (by setting the 'selected' attribute). The selected
339: collection node receives an attribute 'loadedInNode' with the value
340: that newly generated id. The XSLT is executed to present the
341: changes.
342:
343: When a collection's contents has to be retrieved with an extra
344: request, it is returned according to the following schema (using
345: definitions from above)::
346:
347: <grammar xmlns="http://relaxng.org/ns/structure/1.0">
348:
349: <start>
350: <ref name="collectionDocumentElement" />
351: </start>
352:
353: <define name="collectionDocumentElement">
354: <element name="collection">
355: <ref name="commonToAllItems" />
356: <ref name="collectionItems" />
357: </element>
358: </define>
359:
360: </grammar>
361:
362: This grammar is modeled after the WebDAV response grammar, without
363: using the namespace parts of WebDAV. For example::
364:
365: <collection id="some_unique_id">
366: <title>Some folder</title>
367: <uri>http://server/some/folder</uri>
368: <icon>http://server/folder.ico</icon>
369:
370: <items>
371: <resource id="another_unique_id">
372: <title>Foo img</title>
373: <uri>http://server/some/folder/foo.jpg</uri>
374: <icon>http://server/image.ico</icon>
375: </resource>
376:
377: <collection id="a_subfolders_unique_id">
378: <title>Some subfolder</title>
379: <uri>http://server/some/folder/subfolder</uri>
380: <icon>http://server/folder.ico</icon>
381: <src>http://server/some/folder/resources.kupu</src>
382: </collection>
383: </items>
384:
385: </library>
386:
387:
388: If a collection's parent collection shall be accessible, then the
389: server has to return an entry for it explicitly.
390:
391:
392: Searching
393: ---------
394:
395: For searching, Kupu sends an HTTP POST request to the server (to a
396: configurable URI). The server does the search based on the POST form
397: values and return the results as if they were the contents of a
398: library. The document element of the returned XML, <library>, does not
399: have to have a unique id nor an icon subelement.
400:
401: The POST request can contain an optional parameter for the size of the
402: result set. The server can enforce an upper limit itself, and if the
403: request parameter is higher, ignore it. By default, this value is 500.
404:
405: Kupu treats the search result as a library, with the exception of
406: generating a unique id and icon for it. The search result library is
407: attached to the root node of the DOM tree and thus visible and later
408: accessible via the library list.
409:
410:
411: Implementation on the Plone side
412: --------------------------------
413:
414: On the Plone side, a set of Page Templates is responsible for
415: generating the XML. They are aided by a special tool, KupuLibraryTool.
416:
417: In order to use the XML generation for inclusion of media objects,
418: such as images and photos, as well as for searching documents that one
419: can link to from Kupu, the library tool keeps a mapping from resource
420: types to portal types. It provides a management interface in which the
421: site administrator can define, which portal types are to be treated as
422: collections, as linkable documents, as insertable media objects, etc.
423:
424: The library tool also keeps a list of available libraries on the
425: site. The site administrator can add, modify, delete and reorder
426: libraries in the tool's management interface. The searching aspect of
427: Kupu Libraries is handled by the portal catalog.
428:
429: Permissions used by the library tool:
430:
431: - Kupu: Query libraries
432:
433: This permission is required for all users who want to query
434: libraries from the library tool.
435:
436: - Kupu: Manage libraries
437:
438: This permissions is required for all administrators who need to add,
439: edit and delete existing libraries.
440:
441: In order to be able to present special previews for resources without
442: having to load the resource itself in Kupu, a portal type can provide
443: an action called 'kupupreview', pointing to the URL where the object's
444: preview can be retrieved. If a portal_type does not provide that
445: action, preview is disabled for it.
446:
447: Example: Preview action for CMFPhoto showing each photo's thumbnail
448: version:
449:
450: - Go to the portal_types tool and click on the 'Photo' portal
451: type. Then click on its 'Actions' tab.
452:
453: - Down below enter information for a new action:
454:
455: Name: Kupu Preview
456: Id: kupupreview
457: Action: string:${object_url}/variant/thumbnail
458: Condition: [empty]
459: Permission: View
460: Category: object
461: Visible? False
462:
463: - Hit the 'Add' button.
464:
465:
466: Futures
467: -------
468:
469: * Cached XSLT (need Sarissa support for this)
470:
471: * Deeper standards support (WebDAV/DASL)
472:
473:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>