Merge lp:~exarkun/divmod.org/remove-nevow into lp:divmod.org

Proposed by Jean-Paul Calderone
Status: Merged
Approved by: Tristan Seligmann
Approved revision: 2749
Merged at revision: 2749
Proposed branch: lp:~exarkun/divmod.org/remove-nevow
Merge into: lp:divmod.org
Diff against target: 70998 lines
To merge this branch: bzr merge lp:~exarkun/divmod.org/remove-nevow
Reviewer Review Type Date Requested Status
Tristan Seligmann Approve
Review via email: mp+222457@code.launchpad.net

Description of the change

To post a comment you must log in.
Revision history for this message
Tristan Seligmann (mithrandi) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'Divmod.pth'
--- Divmod.pth 2014-05-18 17:48:04 +0000
+++ Divmod.pth 2014-06-08 12:16:37 +0000
@@ -1,9 +1,8 @@
1# -*- test-case-name: axiom,combinator,epsilon,xmantissa,nevow,formless,xquotient,reverend,sine,hyperbola -*-1# -*- test-case-name: axiom,combinator,epsilon,xmantissa,xquotient,reverend,sine,hyperbola -*-
2Axiom2Axiom
3Combinator3Combinator
4Epsilon4Epsilon
5Mantissa5Mantissa
6Nevow
7Quotient6Quotient
8Reverend7Reverend
9Sine8Sine
109
=== removed directory 'Nevow'
=== removed file 'Nevow/ChangeLog'
--- Nevow/ChangeLog 2006-06-14 11:54:41 +0000
+++ Nevow/ChangeLog 1970-01-01 00:00:00 +0000
@@ -1,743 +0,0 @@
12006-06-12 Glyph Lefkowitz <glyph@divmod.com>
2
3 * Nevow 0.9.0: see NEWS.txt for details.
4
52006-04-07 Jp Calderone <exarkun@divmod.com>
6
7 * Nevow 0.8.0 released
8
92006-03-30 Tommi Virtanen <tv@twistedmatrix.com>
10
11 * nevow/static.py: Fix handling of range requests on static files.
12
132006-03-30 Jp Calderone <exarkun@divmod.com>
14
15 * formless/freeform-defaults.css, formless/annotate.py: Style and
16 feedback improvements.
17
182006-03-29 Jp Calderone <exarkun@divmod.com>
19
20 * examples/formbuilder/: Apply Cory Dodt's patch to make this
21 example work again.
22
232006-03-27 Jp Calderone <exarkun@divmod.com>
24
25 * nevow/athena.py: Add getInitialArguments method which will be
26 invoked during rendering and may return a list or tuple of objects
27 which will be be passed to the client-side Widget's __init__ method.
28
292006-03-24 Allen Short <washort@divmod.com>
30
31 * Upgrade MochiKit to 1.2
32
332006-03-17 Tristan Seligmann <mithrandi@mithrandi.za.net>
34
35 * Remove usage of twisted.python.components.Interface from formless.
36 Convert TypedInterface to zope.interface.
37
382006-03-17 Jp Calderone <exarkun@divmod.com>
39
40 * nevow/json.py: Improve (hopefully correct this time ;) unicode
41 support.
42
432006-03-08 Valentino Volonghi <dialtone@divmod.com>
44
45 * Remove usage of twisted.python.components.Interface from nevow.
46 Remove compyCompat.
47
482006-02-28 Jp Calderone <exarkun@divmod.com>
49
50 * nevow/athena.py: Make the "Connection: Close" header of Athena
51 transport responses optional (toggleable by a flag on LivePage) to
52 allow TCP connection setup overhead to be avoided.
53
542006-02-15 Tristan Seligmann <mithrandi@mithrandi.za.net>
55
56 * nevow/athena.js, nevow/athena.py: Pass JavaScript call-stack
57 information back to the server and include it in logged tracebacks
58 (Firefox only).
59
602006-02-14 Jp Calderone <exarkun@divmod.com>
61
62 * nevow/util.py: Delete a bunch of code duplicated from Twisted.
63
642006-02-06 Glyph Lefkowitz <glyph@twistedmatrix.com>
65
66 * nevow/athena.py, nevow/athena.js: Pop up an obnoxious widget when
67 an Athena connection is lost.
68
692006-02-06 Jp Calderone <exarkun@divmod.com>
70
71 * nevow/runtime.js: Add Platform.getPage, a wrapper around the
72 browser-provided HTTP request function.
73
742006-02-01 Tristan Seligmann <mithrandi@mithrandi.za.net>
75
76 * nevow/athena.js: Add support for <athena:handler> element, a
77 declarative mechanism for attaching event handlers to nodes.
78
792006-02-01 Tristan Seligmann <mithrandi@mithrandi.za.net>
80
81 * bin/nit: Test collector/runner for Athena widgets.
82
832006-02-01 Jp Calderone <exarkun@divmod.com>
84
85 * nevow/defer.js: Deferred implementation to replace MochiKit
86 Deferreds.
87
882006-01-21 Valentino Volonghi <dialtone@divmod.com>
89
90 * nevow/rend.py, formless/webform.py: Support Deferreds returned
91 from bind_ methods.
92
932006-01-21 Valentino Volonghi <dialtone@divmod.com>
94
95 * nevow/flat/flatstan.py: Fix macros inside of other specials.
96
972006-01-19 Jp Calderone <exarkun@divmod.com>
98
99 * nevow/athena.js: Added Divmod.Class.methods() for defining
100 multiple methods at once.
101
1022006-01-19 Jp Calderone <exarkun@divmod.com>
103
104 * nevow/athena.py, nevow/athena.js: Support the addition of
105 LiveFragment instances to a page after the initial render pass.
106
1072006-01-15 Jp Calderone <exarkun@divmod.com>
108
109 * nevow/athena.js: Introduced new form of Divmod.Class.method() for
110 adding methods to JavaScript classes. Added a child-window based
111 log viewer.
112
1132006-01-08 Valentino Volonghi <dialtone@divmod.com>
114
115 * examples/hello/hellohtml.py: Removed htmlfile usage
116 * nevow/loaders.py: Deprecated htmlfile/htmlstr
117
1182006-01-08 Glyph Lefkowitz <glyph@twistedmatrix.com>
119
120 * nevow/test/, formless/test/: Removed all usage of trial's
121 deferredResult() and util.wait() functions.
122
1232006-01-04 Glyph Lefkowitz <glyph@twistedmatrix.com>
124
125 * nevow/athena.py: Added fragment and widget nesting. On the
126 server side, this documents and provides a supported way of
127 setting the magical required "page" attribute. On the client
128 side, this provides a convenient hook for multiple widgets within
129 a page to communicate with each other.
130
1312005-12-26 Jp Calderone <exarkun@divmod.com>
132
133 * nevow/athena.py: Added athena.js and MochiKit.js to the dictionary
134 returned by allJavascriptModules(), allowing them to be referenced
135 using the JS import mechanism, in turn allowing them both to be
136 served from a single site-wide URL, rather than once per page.
137
1382005-12-22 Jp Calderone <exarkun@divmod.com>
139
140 * nevow/athena.py: Remove Python 2.4 dependencies.
141
1422005-12-21 Jp Calderone <exarkun@divmod.com>
143
144 * Nevow 0.7.0 released
145
1462005-12-18 Jp Calderone <exarkun@divmod.com>
147
148 * nevow/athena.py: Server-side processing of .js files to allow for
149 an import directive. Imported JavaScript modules are inserted into
150 the page during the render process in dependency order.
151
152 * nevow/widget.js: Athena Widgets class and support code definitions
153 moved here.
154
1552005-12-13 Matt Goodall <matt@pollenation.net>
156
157 * nevow/athena.js: Improved IE compatibility.
158
1592005-12-05 Jp Calderone <exarkun@divmod.com>
160
161 * nevow/athena.js: Added Divmod.Class object which provides a
162 class-based object model for JavaScript programs. Added
163 Nevow.Athena.Widget, a base class for "Live Widgets" - JavaScript
164 classes which can control a particular section of a LivePage and can
165 communicate with corresponding LiveFragment instances on the server.
166
167 * nevow/athena.py: Added a callRemote method to LiveFragment - this
168 allows the server to invoke methods on particular Widgets on the
169 client.
170
1712005-12-03 Jp Calderone <exarkun@divmod.com>
172
173 * nevow/rend.py: Fixed a bug in xmlfile caching which could lead to
174 a corrupt loader cache.
175
1762005-11-29 Jp Calderone <exarkun@divmod.com>
177
178 * nevow/appserver.py: Removed "support" (which consisted of logging
179 an error message and continuing) for returning objects which do not
180 provide IResource.
181
1822005-11-26 Jp Calderone <exarkun@divmod.com>
183
184 * nevow/athena.py, nevow/athena.js: Use POST for the LivePage
185 transport, rather than GET.
186
187 * nevow/json.py: Fix a bug in JSON support for floating points.
188
1892005-11-25 Jp Calderone <exarkun@divmod.com>
190
191 * nevow/athena.js: Go live by default.
192
1932005-11-22 Glyph Lefkowitz <glyph@divmod.com>
194
195 * nevow/guard.py: Removed __session_just_startd__.
196
1972005-11-15 Jp Calderone <exarkun@divmod.com>
198
199 * nevow/athena.py: Added LiveFragment - base class for Fragments
200 which may cooperatively share a single LivePage connection.
201
202
2032005-11-09 Jp Calderone <exarkun@divmod.com>
204
205 * Athena JavaScript API unified into a pseudo-namespace hierarchy.
206
2072005-11-07 Jp Calderone <exarkun@divmod.com>
208
209 * JSON serializer now quotes dict/object keys.
210
2112005-11-02 Jp Calderone <exarkun@divmod.com>
212
213 * Nevow 0.6.0 released
214
2152005-09-21 Jp Calderone <exarkun@divmod.com>
216
217 * nevow/athena.py: New implementation of LivePage with a
218 data-centric API: generation of JavaScript on the server is highly
219 discouraged, instead an API for passing around simple or complex
220 data structures is provided.
221
2222005-08-01 Matt Goodall <matt@pollenation.net>
223
224 egg-ify the distribution. "python setup.py bdist_egg" will now build
225 a .egg in dist for Python 2.3 and Python 2.4.
226
2272005-07-14 Donovan Preston <dp@divmod.org>
228
229 * It's no longer necessary to specify addSlash = True on
230 the root resource. nevow.appserver.NevowSite automatically
231 sets it on the first argument you pass to it (the root
232 resource).
233
2342005-07-12 Donovan Preston <dp@divmod.org>
235
236 * Usability improvements for formless at the expense of
237 purity of abstraction. Since the only thing anybody uses
238 formless for is rendering web forms, make it a little easier
239 to do common things. For example:
240
241 - _nevow_carryover_ does not get appended to URLs unless absolutely
242 necessary (because you return a value from an autocallable)
243
244 - TypedInterface is being deprecated in favor of using
245 IConfigurable directly, and an IConfigurable implementation
246 on Fragment/Page that is easy to use. To expose a "foo" method
247 on a page which takes a "bar" string and a "baz" integer, do this:
248
249 def bind_foo(self, ctx):
250 return [('bar', String()), ('baz', Integer())]
251
252 Previously, you would have had to create a TypedInterface,
253 declare foo and the types of the arguments in the class body,
254 declare that foo is autocallable, and declare that your Page
255 class __implements__ the interface. Now, just implement
256 bind_foo to return an IBinding or a list which can be munged
257 into one.
258
259 - It is possible to return a Page from an autocallable to have
260 that page displayed directly after posting the autocallable.
261 The URL that is used is freeform_hand, which means that the
262 Page goes into your "hand" in the session. The hand can only
263 hold one value, the most recent return result of an autocallable.
264 This isn't very back-button friendly but it makes it super
265 easy to put together a multi-step wizard interface.
266
267 See examples/tests/testformless.py and the /testformless on
268 the example server to see how to do this.
269
270 - It is possible to return a URL instance from an autocallable
271 to have the user redirected to that page after posting the
272 form successfully. This replaces and deprecates the old,
273 whacko method of setting IRedirectAfterPost on the Request.
274
275 See examples/tests/testformless.py and the /formless_redirector
276 on the example server to see how to do this.
277
278 * There is now livetest coverage of the formless examples,
279 including posting forms and checking erroneous conditions.
280
2812005-07-06 Donovan Preston <dp@divmod.org>
282
283 * Major non-backwards-compatible improvements to livepage. Changes
284 are designed to avoid an uncollectable garbage problem which was
285 inherent in the previous design.
286
287 The livepage javascript glue now includes a global object named
288 "server". This object has a "handle" method which takes at least
289 one argument, a string indicating the name of the handler to
290 invoke on the server. When called by client-side javascript,
291 LivePage.locateHandler is invoked. locateHandler should return
292 a callable which will be called with a context indicating
293 which client is invoking the method, and any additional arguments
294 which were passed to server.handle, as strings.
295
296 The default implementation of LivePage.locateHandler looks for
297 a correspondingly named "handle_*" method. Using livepage is
298 now as simple as subclassing LivePage and providing handle_*
299 methods:
300
301 class Foo(LivePage):
302 def handle_bar(self, ctx, something):
303 print "something!", something
304
305 And calling server.handle in javascript:
306
307 <a onclick="server.handle('bar', 'here is something')">Click me</a>
308
309 The previous behavior of registering closures or other callables
310 as event handlers and then embedding them in the page is still
311 available using the IClientHandle.transient method. These one-
312 shot handlers are only invokable by the client once before being
313 garbage collected on the server. This makes it possible to
314 implement temporary dialog boxes and the like.
315
3162005-04-09 Tommi Virtanen <tv@twistedmatrix.com>
317
318 * Allow remembering ILogger to specify an alternate access logging
319 method.
320
3212005-04-06 Matt Goodall <matt@pollenation.net>
322
323 * Added optional context argument to Page's renderString and
324 renderSynchronously methods. This provides a site-like context that is
325 useful when rendering multiple pages that need common remembered data.
326
3272005-3-23 Donovan Preston <dp@divmod.org>
328
329 * Releasing 0.4.1
330
3312005-3-22 Donovan Preston <dp@divmod.org>
332
333 * Releasing 0.4
334
3352005-02-22 Matt Goodall <matt@pollenation.net>
336
337 * Added a "data" renderer (rend.data) that replaces the tag's content
338 with the current data. i.e. <p n:data="name" n:render="data">Foo Bar</p>.
339
3402005-02-17 Matt Goodall <matt@pollenation.net>
341
342 * Added i18n - a gettext-like mechanism for marking translatable content
343 in an application's Python modules by wrapping a string in _(). Standard
344 Python gettext tools can be used to generate translation files.
345
346 Translation happens during rendering and depends on a list of languages
347 found in the context. By default, the browser's preferred languages are
348 used. The default behaviour can be overridden by remembering the languages
349 as inevow.ILanguages in the context; allowing the language to be selected
350 from user preferences, for example.
351
3522005-02-08 Matt Goodall <matt@pollenation.net>
353
354 * Extended the IDocFactory interface's load method to accept an optional
355 context.
356
357 The current loaders do not use the context but future loaders may, i.e. one
358 that loads a localised template based on some language in the context.
359
3602005-01-01 Donovan Preston <dp@divmod.org>
361
362 * Rewrote LivePage quoting code to be much more correct; added many unit
363 tests. Some older livepage code must be changed to use the
364 livepage.literal object instead of passing normal strings to handler or
365 the LivePage client APIs.
366
367 * Added nevow.livepage module, LivePage, and ILivePage. The name liveevil
368 is deprecated.
369
3702004-12-23 Phil Frost <indigo@bitglue.com>
371
372 * Added support for formless to return unicode objects. annotate.String
373 and subclasses (Text, Password, etc.) take a 'unicode' parameter to
374 enable unicode, like so:
375
376 | annotate.String(unicode=True)
377
378 The coerced value will then be a unicode object.
379
3802004-12-16 Matt Goodall <matt@pollenation.net>
381
382 * Added ObjectContainer - a data directive accessor for retrieving an
383 attribute of an object. If the current data in the context (the IData) is an
384 object you can register ObjectContainer as the IContainer adapter for the
385 object's class and Nevow will automatically look inside the object to fetch
386 the attribute.
387
388 Note: ObjectContainer is *not* registered as the adapter for all object
389 types. You must explicitly register the adapter for application classes as
390 needed.
391
3922004-12-08 Matt Goodall <matt@pollenation.net>
393
394 * Applied the foom/mesozoic patch to make Page.remember work correctly and
395 without the hack. You can now use the method reliably to remember objects at
396 Page construction time or any other time before the PageContext is created.
397 The remembered objects can be found from the context in the usual way.
398
399 class MyPage(rend.Page):
400
401 def __init__(self, original):
402 # Make original available as ISomething(ctx) for later.
403 self.remember(original, ISomething)
404 rend.Page.__init__(self, original)
405
406 * Added a similar remember method for NevowSite (and made a SiteContext
407 object the ultimate parent). You can know remember objects on the site and
408 have them available anywhere there's a context. A typical use case is making
409 some object store available to the site. This was often achieved using a
410 wrapper resource but now it's as easy as:
411
412 store = makeStore()
413 site = NevowSite(rootResource)
414 site.remember(store, IStore)
415
4162004-12-08 Matt Goodall <matt@pollenation.net>
417
418 * Renamed URL.fromRequest to URL.fromContext. URL.fromRequest was a little
419 confusing - the URL it returned only included the segments that had been
420 consumed so far by the locateChild process and not the whole URL as the name
421 might suggest. Eventually, fromRequest will change to return a full URL but,
422 for now, its use is deprecated.
423
424 * Renamed URL.parent to URL.parentdir. URL.parent() was logically equivalent
425 to '..' and so removed more segments than expected. URL.parent's use is now
426 deprecated and in a future release will be changed to remove exactly one
427 segment.
428
429 * Improve URL.click to normalise any segments of '.' or '..'. Browsers
430 normalise the URL so, according to the docstring, click should too.
431
4322004-12-04 Donovan Preston <dp@divmod.org>
433
434 * Added macros! This is the same patch as the one I attached to my
435 "Macros in Nevow" mail, with the addition of an IMacroFactory,
436 a MacroFactory implementation on rend.Page, and macro directive
437 support. Macros are like render functions that take only the
438 context (no data parameter) and run only once during the lifetime
439 of a template loader. Here is an example of the difference between
440 a macro and a renderer:
441
442 >>> class Bumper(object):
443 ... num = 0
444 ... def bump(self):
445 ... self.num += 1
446 ... return self.num
447 ...
448 >>> staysTheSame = Bumper()
449 >>> changes = Bumper()
450 >>> from nevow import flat, tags, loaders
451 >>> document = loaders.stan([tags.invisible(macro=lambda ctx: staysTheSame.bump()), tags.invisible(render=lambda ctx, data: changes.bump())])
452 >>> flat.flatten(document)
453 '11'
454 >>> flat.flatten(document)
455 '12'
456 >>> flat.flatten(document)
457 '13'
458
4592004-12-01 Donovan Preston <dp@divmod.org>
460
461 * Added __iter__ to nevow.stan.slot to prevent infinite loops by
462 trying to do "for x in slot('foo'): print x".
463
464 * Added an IGettable adapter for nevow.stan.slot. It is now possible
465 to specify a slot as the data for a node, so the following example
466 would work:
467
468 from nevow import rend, tags
469
470 def fillEm(ctx, data):
471 ctx.fillSlots('value', [1, 2])
472 return ctx.tag
473
474 tags.html(render=fillEm)[
475 tags.ul(data=tags.slot('value'), render=rend.sequence)[
476 tags.li(pattern='item')[
477 str ]]]
478
4792004-09-26 Donovan Preston <dp@divmod.org>
480
481 * Added nevow.inevow.IQ interface, an interface for querying the
482 stan DOM. Eventually, this interface will contain APIs for doing
483 traditional DOM introspection, such as iterating children,
484 examining tag names, and examining attributes. For now, it contains
485 only the patternGenerator, onePattern, and allPatterns APIs. These
486 APIs have been deprecated from Context.
487
488 The main benefit of this is the ability to do:
489
490 IQ(loaders.xmlfile(...)).patternGenerator(...)
491
492 which would be nice for creating "pattern library" files containing
493 common skin idioms which can then be copied and used throughout
494 the app.
495
4962004-09-25 Donovan Preston <dp@divmod.org>
497
498 * Chatola received a major facelift, bringing it from cool demo
499 up to almost a full fledged web-based chat server. The helper API
500 LiveEvil.call(...) was added, which deprecates
501 LiveEvil.sendScript(callJS(...))
502
5032004-09-23 Tommi Virtanen <tv@twistedmatrix.com>
504
505 * Make guard.SessionWrapper store its URL location in all requests it
506 passes to its children. This allows the children know where to post
507 the __login__ and __logout__ forms, even deep inside the resource
508 tree (fixes issue59).
509
510 * Guard now works as a non-root resource, with help from the above
511 change. Semantics of __login__ clarified in unit tests; if your guard
512 is at /foo, posting to /foo/__login__ redirects to /foo, and posting
513 to /foo/__login__/ redirects to /foo/. The two unit tests that failed
514 earlier now pass (with that change in their __login__ URLs).
515
516 * If URL-based sessions are used, login no longer loses session
517 information due to redirect to / (fixes issue56).
518
5192004-09-20 Matt Goodall <matt@pollenation.net>
520
521 * Added URL.secure() method to make switching between http and
522 https easier.
523
5242004-09-08 Donovan Preston <dp@divmod.org>
525
526 * Nevow now includes a very simple proof-of-concept WSGI Application
527 implementation, and can be used with no Twisted dependency. Nevow can
528 also be used to write CGIs, either using a simple CGI WSGI gateway
529 (which supports URL traversal), or by using Page.renderString (which does not).
530
531 * Two new context interfaces, ICurrentSegments and IRemainingSegments,
532 replace the need to examine the Request prepath and postpath attributes
533 directly.
534
535 * ISerializable is deprecated, and has been replaced with a simple
536 Flattener registry. nevow.flat.registerFlattener and
537 nevow.flat.getFlattener have been added to support this.
538
5392004-09-06 Donovan Preston <dp@divmod.org>
540
541 * BACKWARDS INCOMPATIBLE CHANGE. Page.configurable_ *always* returns
542 self, and a new Page.configurable_original *always* returns
543 self.original. If you were relying on Page.configurable_'s
544 introspection behavior and are now getting errors about adapting
545 to IConfigurable, change your renderForms() calls to:
546
547 renderForms('original')
548
549 This causes Page.configurable_original to be invoked and
550 introspected for form rendering.
551
5522004-08-23 Donovan Preston <dp@divmod.org>
553
554 * LivePage uses a simpler implementation strategy which requires
555 the browser to make one request per output event. As a result,
556 LivePage now works on Mozilla, Safari, and Internet Explorer Windows.
557
5582004-08-05 Donovan Preston <dp@divmod.org>
559
560 * Implemented support for IFoo(ctx) synonym syntax. It does the
561 same thing as ctx.locate(IFoo)
562
563 * Removed Resource Generators, a feature of NevowSite that nobody
564 used and wasn't really useful.
565
566 * Changed all inevow.IResource apis to take a Context object
567 where they used to take the request. Remembering objects in
568 PageContexts is now much easier, and fewer hacks are required to
569 build the context chain. The context chain now looks like:
570
571 SiteContext->RequestContext->PageContext(s)->WovenContext(s)
572
5732004-7-28 Donovan Preston <dp@divmod.org>
574
575 * Parameterize data_* methods in the same way as render_* methods.
576 Patch by k3mper.
577
578 For example, <div nevow:data="foo bar,baz" /> will cause
579 data_foo(self, bar, baz) to be called with the strings "bar" and
580 "baz". This data method should return a callable taking ctx, data.
581 The return value of this callable will be remembered as IData at
582 this point in the context stack.
583
584 * Added list-slicing support to ListContainer. You may now use
585 list slicing syntax in a data directive in addition to a simple
586 index. For example:
587
588 def data_aList(self, ctx, data):
589 return ["Buckle", "My", "Shoe"]
590
591 <div nevow:data="aList">
592 <span nevow:data="1:-1" nevow:render="string" />
593 </div>
594
595 Will render as <div><span>My</span></div>
596
5972004-7-20 Matt Goodall <matt@pollenation.net>
598
599 * Modified sax loader to retain doctypes, comments and xmlns attributes.
600 It's now possible to build XHTML valid pages :).
601
602 xmlns attributes are always kept but there are options to ignore the doctype
603 and comment (at the request of foom, not sure why yet). Right now, the default
604 is to retain doctypes and comments but you can use the ignoreDocType and
605 ignoreComment args to the xml loaders and flatsax parse functions. This bit
606 may change.
607
608 * Add a URL -> IResource adapter that performs a HTTP redirect. URLs can then
609 be returned from locateChild().
610
6112004-06-07 Donovan Preston <dp@divmod.org>
612
613 * Added nevow.canvas, an experimental module similar to LivePage
614 which provides a Python server-side API for drawing arbitrary lines,
615 curves, and text in the browser. The implementation is socket-based
616 and asynchronous, so the server can issue drawing commands to the
617 client at any time.
618
619 The idea is to provide a server-side API to the Python programmer
620 and shield them from implementation details, but the current
621 implementation uses a pre-compiled Flash movie (which never changes;
622 we are not generating Flash bytecodes). An implementation using SVG
623 or Safari's Canvas (nevow.canvas was written before the Safari Canvas
624 announcement) would be possible.
625
6262004-05-26 Donovan Preston <dp@divmod.org>
627
628 * Add URLOverlay.keep, an API which lets you specify which query args
629 will be carried on from the current page render into the new URL.
630
6312004-05-24 Matt Goodall <matt@pollenation.net>
632
633 * Extracted Fragment from Page. Hopefully, it will make it more obvious
634 that embedding an object with data_ and render_ methods in a stan tree is
635 possible without using something as "heavy" as Page which is really meant
636 to be a web resource.
637
6382004-05-23 Donovan Preston <dp@divmod.org>
639
640 * Added some useful APIs to LiveEvil for manipulating the client-side
641 page:
642
643 - flt(stan): Flatten some stan, quoting apostrophes as
644 as appropriate for embedding in javascript
645
646 - set(what, to): Set the contents of the client-side node
647 with the id 'what' to the stan 'to'.
648
649 - append(where, what): Append the stan 'what' to the client-
650 side node with the id 'where'
651
652 - alert(what): Show an alert to the user with the text "what"
653
6542004-05-19 Jonathan Simms <slyphon@divmod.com>
655
656 * 0.2 released.
657
6582004-05-14 Donovan Preston <dp@divmod.org>
659
660 * nevow.url.URLPath is renamed nevow.url.URL
661
662 * URL objects are now lazier about casting things to strings; they will
663 keep track of path segments in a list and defer to the nevow rendering
664 machinery to do the conversion; This means you can do things like
665 here.child(deferred) or here.child(function)
666
667 * URL objects have a better api for manipulating query arguments
668 - add(key, value=None) adds a new query arg at the end; the value may
669 be None if only a query key needs to be added
670 - replace(key, value) removes all occurrences of 'key' and inserts a
671 new (key, value) at the same location as the previous first
672 occurrence of key
673 - clear() clears all args
674
6752004-05-06 Donovan Preston <dp@divmod.org>
676
677 * Merged freeform-patterned branch, a large formless/freeform refactor.
678 It is now possible to influence the rendering of forms by providing
679 "patterns" to renderForms.
680
681 * Formless is now a top-level package. Freeform has been renamed
682 formless.webform. It should be possible to use formless outside
683 the context of nevow for doing things such as validating network
684 input based on method argument type annotations.
685
686 * TypedInterface, autocallable, and all the Typed subclasses are now
687 in the formless.annotate module.
688
6892004-04-30 Donovan Preston <dp@divmod.org>
690
691 * Created nevow.blocks, a module containing helpful code for working
692 around display: inline-block bugs in Mozilla.
693
6942004-04-27 Donovan Preston <dp@divmod.org>
695
696 * IRenderer.__call__ was renamed IRenderer.rend to be more explicit.
697
6982004-04-21 Donovan Preston <dp@divmod.org>
699
700 * Implemented nevow.flat.flatten and nevow.flat.precompile, functions
701 useful for using stan outside of the context of Page classes. Useful
702 for generating some XML or even raw text; use it any time you want
703 to convert a tree data structure into a contiguous string!
704
705 import random
706 import string
707
708 from nevow import flat
709
710 def letters(howMany):
711 for i in range(howMany):
712 yield ' ', string.letters[i], '\n'
713
714 def outline():
715 for i in range(5):
716 yield i, '\n'
717 yield letters(random.choice(range(7)))
718 yield '\n'
719
720 print flat.flatten(outline())
721
7222004-04-20 Donovan Preston <dp@divmod.org>
723
724 * guard sessions are no longer required to use formless.
725
7262004-04-19 Donovan Preston <dp@divmod.org>
727
728 * Implemented lazy context factories. It is now possible to register
729 an adapter against various *Context classes and an interface. They
730 will be invoked if *Context.locate(interface) is called.
731
732 Implemented a lazy ISession adapter against RequestContext, making
733 it possible to do ctx.locate(ISession), which is nice.
734
7352004-04-16 Donovan Preston <dp@divmod.org>
736
737 * Added nevow.entities module, a module containing literals for all of
738 the valid XHTML entities. For example:
739
740 def render_nbsp(self, ctx, data):
741 from nevow import entities
742 return entities.nbsp
743
7440
=== removed file 'Nevow/LICENSE'
--- Nevow/LICENSE 2005-10-14 17:36:24 +0000
+++ Nevow/LICENSE 1970-01-01 00:00:00 +0000
@@ -1,35 +0,0 @@
1Copyright (c) 2004
2Donovan Preston
3Matt Goodall
4James Y. Knight
5Glyph Lefkowitz
6JP Calderone
7Allen Short
8Alex Levy
9Justin Johnson
10Christopher Armstrong
11Jonathan Simms
12Phil Frost
13Tommi Virtanen
14Michal Pasternak
15Valentino Volonghi
16
17
18Permission is hereby granted, free of charge, to any person obtaining
19a copy of this software and associated documentation files (the
20"Software"), to deal in the Software without restriction, including
21without limitation the rights to use, copy, modify, merge, publish,
22distribute, sublicense, and/or sell copies of the Software, and to
23permit persons to whom the Software is furnished to do so, subject to
24the following conditions:
25
26The above copyright notice and this permission notice shall be
27included in all copies or substantial portions of the Software.
28
29THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
33LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
34OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
35WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
360
=== removed file 'Nevow/MANIFEST.in'
--- Nevow/MANIFEST.in 2010-04-06 11:05:45 +0000
+++ Nevow/MANIFEST.in 1970-01-01 00:00:00 +0000
@@ -1,24 +0,0 @@
1include ChangeLog
2include LICENSE
3include zomne.c
4include formless/freeform-default.css
5include nevow/Canvas.swf
6include nevow/athena_private/*.png
7include debian/*
8recursive-include twisted *.py
9recursive-include nevow *.css *.js
10include bin/nevow-xmlgettext
11graft doc
12recursive-include examples *.css *.gif *.html *.jpg *.js *.py *.png *.tac *.mo *.po *.pot *.xml *.sql *.xul
13include examples/i18n/update-l10n
14include examples/files/words
15include examples/pastebin/data
16include examples/pastebin/static/robots.txt
17include examples/pastebin/TODO
18include examples/wsgi/README
19include extras/xhtml-nevow.rnc
20include nevow/Canvas.fla
21include nevow/canvas.as
22include win32/*
23prune */.svn
24prune doc/html/*.html
250
=== removed file 'Nevow/NEWS.txt'
--- Nevow/NEWS.txt 2009-11-30 01:08:55 +0000
+++ Nevow/NEWS.txt 1970-01-01 00:00:00 +0000
@@ -1,244 +0,0 @@
10.10.0 (2009-11-25):
2 - Added a system for CSS dependency declarations similar to the one in
3 Athena for JavaScript.
4 - Fix Athena's transport cleanup on page unload in Internet Explorer.
5 - Fix nit's results coloring in Internet Explorer.
6 - Added an API for declaring JavaScript classes which involves less
7 repetition than the existing Divmod.Class.subclass API.
8 - Added human-readable formatting for the new flattener's error reporting;
9 rendering error stacks will now display lines from Python code as well
10 as stan and XML templates.
11 - Override the setuptools sdist command with the original distutils sdist
12 command to avoid setuptools' version number transformation.
13 - Added support for default values for slots in XML templates.
14 - Fixed a problem with setup.py which led to css files not being
15 installed.
16 - Removed the old Chatola example and replaced it with a link to the new
17 chat example.
18 - Sped up some of the JavaScript dependency calculations.
19
200.9.33 (2008-12-09):
21 - Add error handling to the integration between the old flattener
22 and the new flattener so that if the new flattener fails with an
23 exception or a Failure the error is propagated properly to the old
24 flattener which invoked it.
25 - Changed nit so that it doesn't use private `twistd` APIs and
26 instead just sets up a server and runs the reactor. This makes
27 nit work with all versions of Twisted supported by Nevow.
28 - Changed Nevow's setup.py to use setuptools if setuptools is
29 available. This has the user-facing consequence of installing
30 Nevow as an egg if setuptools is available at installation time
31 and of making Nevow installable using the `easy_install´ tool.
32 - TabbedPane naively set DOM attributes, making it unusable in
33 Internet Explorer 6 and 7. Introduced a reliable method for
34 setting DOM node attributes, with name mangling, to address the
35 issue.
36
370.9.32 (2008-08-12):
38 - A resource wrapper for on-the-fly gzip compression has been added.
39 - A twistd plugin, 'athena-widget', is now available for serving
40 single Athena widgets.
41 - Basic Athena support for Safari added.
42 - Added file name, line number, and column number information to
43 slots and tags parsed from XML files in order to make debugging
44 template/renderer interactions simpler.
45 - A context-free flattener has been added. Fragment and its
46 subclasses are now deprecated in favor of Element.
47 - Javascript classes derived from the tabbedpane class can now
48 override how tab selection is handled.
49
500.9.31 (2008-02-06):
51 - Fixed Guard's request parameter save/restore feature to not
52 clobber request state after login succeeds when a session has
53 already been negotiated.
54 - Added a hook to nevow.guard.SessionWrapper which allows the
55 domain parameter of the session cookie to be specified.
56
570.9.30 (2008-01-16):
58 - Change DeferredSerializer so that it passes failures from the
59 Deferred being serialized on to the Deferred returned by the
60 flattening function. Without this behavior, the Deferred
61 returned by the flattening function is never fired when a
62 Deferred which fails is serialized.
63
640.9.29 (2008-01-02):
65 - Prevent NevowSite.handleSegment from raising IndexError in certain
66 situations.
67 - Deprecated wsgi and zomne modules.
68
690.9.28 (2007-12-10):
70 - Added two APIs to Athena, one for creating the string used as the id
71 attribute of the top node of a widget and one for creating the string
72 used as the id attribute of a node which had an id attribute in the
73 widget's template document.
74
750.9.27 (2007-11-27):
76 - Unicode URLs now supported.
77
780.9.26 (2007-11-02):
79 - url.URL.path now correctly escapes segments in the string it
80 evaluates to.
81 - inevow.IAthenaTransportable added, along with support for
82 serialization of custom types for server-to-client Athena
83 messages.
84 - Global client-side behaviour is now customizable via a client
85 PageWidget class.
86
870.9.25 (2007-10-16):
88 - The Athena message queue implementation has been improved, fixing problems
89 masked by bugs in Firebug/YSlow.
90
910.9.24 (2007-09-05):
92 - ESC key no longer disconnects Athena connections.
93 - Fixed a bug where URLs with quote characters will cause the Athena
94 connection to be lost.
95 - Fixed 'twistd athena-widget' to create a fresh widget instance for each
96 hit.
97
980.9.23 (2007-08-01):
99 - Fixed install script to include all JavaScript files.
100
1010.9.22 (2007-07-06):
102 - Mock DOM implementation for easier browser testing added.
103 - JavaScript source files are now read using universal newlines mode.
104 - athena.AutoJSPackage now excludes dotfiles.
105 - url.URL now properly subclassable.
106 - User-agent parsing added to Athena, to detect known-unsupported browsers.
107
1080.9.21 (2007-06-06):
109 - Debug logging messages from the reliable message delivery queue
110 disabled.
111
1120.9.20 (2007-05-24):
113 - Athena now no longer holds more than one idle transport open to
114 the browser.
115
1160.9.19 (2007-04-27):
117 - Changed the styling of the progressbar to work on IE6.
118 - Athena.Widget.detach added, to allow widgets to cleanly be removed
119 from a page.
120 - Athena.Widget.callLater added, a wrapper around setTimeout and
121 clearTimeout.
122 - 'athena-widget' twistd command added, for starting a server which
123 serves a single LiveFragment or LiveElement.
124
1250.9.18 (2007-02-23):
126 - Athena 'connection lost' notification now styleable via the
127 'nevow-connection-lost' CSS class.
128 - The 'runjstests' script has been removed, now that JS tests can be
129 run with trial.
130
1310.9.17 (2006-12-08):
132 - More efficient JSON string parsing.
133 - Give FakeRequests a default status code of OK. Accept all of
134 FakeRequest.__init__'s arguments in the __init__ of
135 AccumulatingFakeRequest.
136
1370.9.16 (2006-11-17):
138 - Updated nit to work with Twisted trunk.
139 - Athena module import caching has been fixed.
140
1410.9.15 (2006-11-08):
142 - Changed _LiveMixin rendering to be idempotent to support the case
143 where a transport hiccup causes a LiveFragment or LiveElement to
144 be sent to the browser multiple times.
145 - Improvements to the tests.
146
1470.9.14 (2006-10-31):
148 - Support code for running non-browser javascript tests has been added.
149 - Added a workaround for nodeById on widgets not yet added to the document in
150 IE.
151 - Athena will now invoke the nodeInserted method (if it exists) on a widget
152 that it instantiates statically.
153 - ID rewriting, similar to existing rewriting support for 'id' attributes,
154 has been added in 'for' and 'headers' attributes of 'label' and 'td'/'th'
155 elements, respectively.
156
1570.9.13 (2006-10-21):
158 - Adjust non-selected panes in tabbedpane to be further out of the viewport.
159 - Convert to using the Javascript module plugin system for Nevow-provided
160 modules.
161
1620.9.12 (2006-10-17):
163 - Added id rewriting for LiveElement and LiveFragment, such that id
164 attributes in a widget template are rewritten so that they are unique to
165 the widget instance. A client-side API, Nevow.Athena.Widget.nodeById(),
166 is provided to allow location of these nodes.
167
1680.9.11 (2006-10-10):
169 - Fixed dynamic widget instantiation in IE.
170 - Added support for correctly quoting the values of slots which are used as
171 attributes.
172
1730.9.10 (2006-10-05):
174 - Minor update to nevow.testutil.
175
1760.9.9 (2006-09-26):
177 - Several nit changes, including the addition of the "check" method to
178 Failure, and the addition of an "assertFailure" method.
179 - The ability to pass Python exceptions to Javascript has been added to
180 Athena.
181 - Dynamic module import has been added for the cases where it is necessary
182 to dynamically add a widget to an existing page.
183
1840.9.8 (2009-09-20):
185 - A bug in nit that caused it to fail if there were too many tests in a
186 test case, and swallow failures in some cases, has been fixed.
187 - Widgets can no longer be added to a page after render time using
188 Divmod.Runtime.Platform.{set,append}NodeContent. Instead, they must be
189 added using Nevow.Athena.Widget.addChildWidgetFromWidgetInfo.
190
1910.9.7 (2009-09-12):
192 - Automatic Athena event handler registration is fixed for all supported browsers
193 and is no longer document-sensitive (ie, it works inside tables now).
194 - Nit has gained a new assertion method, assertIn.
195
1960.9.6 (2008-08-30):
197 - Fixed a bug in the IE implementation of the runtime.js node fetching
198 functions.
199
2000.9.5 (2006-08-22):
201 - Instance attributes can now be exposed to Athena with nevow.utils.Expose
202 and Expose.exposedMethodNames() no longer returns unexposed names.
203
2040.9.4 (2006-08-14):
205 - Added test method discovery to nit test cases, so multiple test methods
206 may be put in a single test case.
207 - use XPath for certain DOM traversals when available. This yields
208 significant speedups on Opera.
209 - Made Divmod.Runtime.Platform.getAttribute deal with IE attribute
210 name-mangling properly.
211 - Javascript logging is now done in Firebug 0.4 style rather than 0.3.
212 - Some cases where Deferred-returning render methods raised
213 exceptions or buried failures were fixed.
214 - Removed MochiKit. The pieces Nevow depends on have been moved to
215 Divmod.Base in nevow/base.js.
216 - Various doc fixes.
217
2180.9.3 (2006-07-17):
219 - Page rendering now supports preprocessors.
220
2210.9.2 (2006-07-08):
222 - Fixes to the typeahead demo.
223 - Elements are now automatically serialized by json, just like Fragments.
224
2250.9.1 (2006-07-05):
226 - Made nevow.athena.expose the mandatory means of publishing a method to
227 the browser. The allowedMethods dictionary will no longer be respected.
228 - Added nevow.page.Element and nevow.athena.LiveElement: these are
229 preferred over nevow.rend.Fragment and nevow.athena.LiveFragment for all
230 new development.
231
2320.9.0 (2006-06-12):
233 - Fixed a bug where nested fragment sending rarely worked.
234 - Sending large strings in Athena arguments and results is now faster due to
235 less unnecessary unicode character quoting.
236 - Module objects are now automatically created for all Athena imports.
237 - Better error reporting for fragments which are rendered without a parent.
238 - Disconnect notifiers in Athena pages will no longer clobber each other.
239 - Many optimizations to javascript initialization.
240 - Javascript packages are now defined with less boilerplate: a filesystem
241 convention similar to Python's for module naming, plus one declaration in a
242 Nevow plugin which indicates the directory, rather than a declaration for
243 each module.
244 - Updated README to refer to Athena rather than LivePage
2450
=== removed file 'Nevow/README'
--- Nevow/README 2006-06-14 11:54:41 +0000
+++ Nevow/README 1970-01-01 00:00:00 +0000
@@ -1,69 +0,0 @@
1
2Divmod Nevow
3============
4
5Divmod Nevow is a web application construction kit written in Python. It is
6designed to allow the programmer to express as much of the view logic as
7desired in Python, and includes a pure Python XML expression syntax named stan
8to facilitate this. However it also provides rich support for designer-edited
9templates, using a very small XML attribute language to provide bi-directional
10template manipulation capability.
11
12Nevow also includes Divmod Athena, a "two way web" or "`COMET`_"
13implementation, providing a two-way bridge between Python code on the server
14and JavaScript code on the client. Modular portions of a page, known as
15"athena fragments" in the server python and "athena widgets" in the client
16javascript, can be individually developed and placed on any Nevow-rendered page
17with a small template renderer. Athena abstracts the intricacies of HTTP
18communication, session security, and browser-specific bugs behind a simple
19remote-method-call interface, where individual widgets or fragments can call
20remote methods on their client or server peer with one method: "callRemote".
21
22Installation
23------------
24
25Before installing Nevow, you should install `Twisted`_, unless you are going to
26write very simple CGI applications. Nevow integrates fully with the twisted.web
27server providing easy deployment.
28
29Nevow uses the standard distutils method of installation::
30
31 python setup.py install
32
33If you do not have Twisted installed, you can run a subset of the tests using
34the test.py script. If you have twisted installed, the test.py script will
35issue the following trial command::
36
37 trial -v nevow.test formless.test
38
39.. _`Twisted`: http://twistedmatrix.com/
40
41Documentation
42-------------
43
44More detailed introductory documentation is available in the doc/ directory,
45along with the beginnings of a reference manual. A large number of examples are
46available in the examples/ directory. These examples require Twisted to run. A
47tac file (twisted application configuration) can be started by invoking twistd,
48the twisted daemon::
49
50 twistd -noy foo.tac
51
52More Information
53----------------
54
55Nevow is an active project, and many new bugfixes and features are committed to
56the Nevow SVN repository. Information about Nevow commits is available by
57subscribing to the `Nevow commits`_ mailing list. The Nevow SVN repository can
58be checked out using::
59
60 svn co http://divmod.org/svn/Divmod/trunk/Nevow Nevow
61
62Discussion of Nevow occurs on the `twisted.web mailing list`_. The Nevow
63developers are also often available for real-time help on the `#twisted.web
64channel`_ on irc.freenode.net.
65
66.. _`Nevow commits`: http://divmod.org/users/mailman.twistd/listinfo/nevow-commits
67.. _`twisted.web mailing list`: http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-web
68.. _`#twisted.web channel`: irc://irc.freenode.net/#twisted.web
69.. _`COMET`: http://alex.dojotoolkit.org/?p=545
700
=== removed directory 'Nevow/benchmarks'
=== removed file 'Nevow/benchmarks/fragmentvselement.py'
--- Nevow/benchmarks/fragmentvselement.py 2008-05-22 18:46:50 +0000
+++ Nevow/benchmarks/fragmentvselement.py 1970-01-01 00:00:00 +0000
@@ -1,147 +0,0 @@
1
2from twisted.internet import reactor
3from twisted.internet.defer import succeed
4
5from nevow.appserver import NevowSite
6
7from nevow.rend import Page, Fragment
8from nevow.page import Element, renderer
9from nevow.loaders import stan
10from nevow.tags import directive, div, span
11
12
13class Static:
14 docFactory = stan("Hello, world. " * 100)
15
16
17
18class StaticFragment(Static, Fragment):
19 pass
20
21
22
23class StaticElement(Static, Element):
24 pass
25
26
27
28class Tiny:
29 docFactory = stan(div(render=directive("foo")))
30
31
32
33class TinyFragment(Tiny, Fragment):
34 def render_foo(self, ctx, data):
35 return ctx.tag[span["result"]]
36
37
38
39class TinyElement(Tiny, Element):
40 def foo(self, request, tag):
41 return tag[span["result"]]
42 renderer(foo)
43
44
45
46class Huge:
47 docFactory = stan(div[[
48 div(render=directive("foo"))
49 for x in range(100)]])
50
51
52
53class HugeFragment(Huge, Fragment):
54 def render_foo(self, ctx, data):
55 return ctx.tag[span["Hello, ", "world", "!"]]
56
57
58
59class HugeElement(Huge, Element):
60 def foo(self, request, tag):
61 return tag[span["Hello, ", "world", "!"]]
62 renderer(foo)
63
64
65
66class Nested:
67 docFactory = stan(div(render=directive("foo")))
68
69 def __init__(self, count=6):
70 self.count = count
71
72
73
74class NestedFragment(Nested, Fragment):
75 def render_foo(self, ctx, data):
76 if self.count:
77 return span[NestedFragment(self.count - 1)]
78 return ctx.tag["Hello"]
79
80
81
82class NestedElement(Nested, Element):
83 def foo(self, request, tag):
84 if self.count:
85 return span[NestedFragment(self.count - 1)]
86 return tag["Hello"]
87 renderer(foo)
88
89
90
91class Deferred:
92 docFactory = stan(div(render=directive('foo')))
93
94
95
96class DeferredFragment(Deferred, Fragment):
97 def render_foo(self, ctx, data):
98 return ctx.tag[succeed("foo")]
99
100
101
102class DeferredElement(Deferred, Element):
103 def foo(self, request, tag):
104 return tag[succeed("foo")]
105 renderer(foo)
106
107
108
109class Compare(Page):
110 def __init__(self, fragment, element):
111 self.fragment = fragment
112 self.element = element
113
114 def child_fragment(self, ctx):
115 return Page(docFactory=stan(self.fragment))
116
117
118 def child_element(self, ctx):
119 return Page(docFactory=stan(self.element))
120
121
122
123class Root(Page):
124 def child_static(self, ctx):
125 return Compare(StaticFragment(), StaticElement())
126
127
128 def child_tiny(self, ctx):
129 return Compare(TinyFragment(), TinyElement())
130
131
132 def child_huge(self, ctx):
133 return Compare(HugeFragment(), HugeElement())
134
135
136 def child_nested(self, ctx):
137 return Compare(NestedFragment(), NestedElement())
138
139
140 def child_deferred(self, ctx):
141 return Compare(DeferredFragment(), DeferredElement())
142
143
144
145if __name__ == '__main__':
146 reactor.listenTCP(8080, NevowSite(Root()))
147 reactor.run()
1480
=== removed file 'Nevow/benchmarks/json_string_tokenizer.py'
--- Nevow/benchmarks/json_string_tokenizer.py 2006-11-24 23:15:26 +0000
+++ Nevow/benchmarks/json_string_tokenizer.py 1970-01-01 00:00:00 +0000
@@ -1,48 +0,0 @@
1
2from time import time
3
4from twisted.python.usage import Options
5
6from nevow.json import serialize, parse
7
8if __name__ == '__main__':
9 from json_string_tokenizer import main
10 raise SystemExit(main())
11
12
13
14class StringTokenizer(Options):
15 optParameters = [
16 ('iterations', 'i', '1000', 'Number of iterations for which to run the benchmark.'),
17 ('scale', 's', '100', 'Factor determining the overall input size.')]
18
19
20 def postOptions(self):
21 self['iterations'] = int(self['iterations'])
22 self['scale'] = int(self['scale'])
23
24
25BASE = u'Hello, world. "Quotes".'
26def benchmark(iterations, scale):
27 """
28 Deserialize a string C{iterations} times. Make the string longer based
29 on C{scale}.
30
31 Prints the mean time per parse call.
32 """
33 s = serialize(BASE * scale)
34 before = time()
35 for i in xrange(iterations):
36 parse(s)
37 after = time()
38 print (after - before) / iterations, 'per call'
39
40
41
42def main(args=None):
43 """
44 Benchmark nevow.json string parsing, maybe with some parameters.
45 """
46 options = StringTokenizer()
47 options.parseOptions(args)
48 benchmark(options['iterations'], options['scale'])
490
=== removed directory 'Nevow/bin'
=== removed file 'Nevow/bin/nevow-xmlgettext'
--- Nevow/bin/nevow-xmlgettext 2005-10-14 17:36:24 +0000
+++ Nevow/bin/nevow-xmlgettext 1970-01-01 00:00:00 +0000
@@ -1,3 +0,0 @@
1#!/usr/bin/env python
2from nevow.scripts.xmlgettext import run
3run()
40
=== removed file 'Nevow/bin/nit'
--- Nevow/bin/nit 2006-11-17 00:50:34 +0000
+++ Nevow/bin/nit 1970-01-01 00:00:00 +0000
@@ -1,3 +0,0 @@
1#!/usr/bin/python
2from nevow.scripts.nit import run
3run()
40
=== removed directory 'Nevow/debian'
=== removed file 'Nevow/debian/changelog'
--- Nevow/debian/changelog 2005-11-06 18:46:50 +0000
+++ Nevow/debian/changelog 1970-01-01 00:00:00 +0000
@@ -1,56 +0,0 @@
1nevow (0.6.0-1.snapshot) unstable; urgency=low
2
3 * SVN snapshot.
4
5 -- Tommi Virtanen <tv@debian.org> Sun, 6 Nov 2005 20:45:27 +0200
6
7nevow (0.6.0-1) unstable; urgency=low
8
9 * New upstream version. (Closes: #336027)
10 * Acknowledge NMU (Closes: #319230), but please be more careful in the
11 future; no NMU patch was sent to BTS
12 * Remove setupcommon.pyc when cleaning, or dpkg-source will see a binary
13 file content change.
14 * Run unit tests when building.
15 * Clean build tree, distutils fails to remove all of it.
16 * Change priority to extra, as twisted is extra and nevow depends on it.
17
18 -- Tommi Virtanen <tv@debian.org> Sun, 6 Nov 2005 20:26:39 +0200
19
20nevow (0.4.1-1.1) unstable; urgency=low
21
22 * NMU
23 * Add missing build depends in python2.4-dev (Closes: #319230)
24 * lintian error: fix package description indent for list items.
25
26 -- Bastian Kleineidam <calvin@debian.org> Sat, 13 Aug 2005 18:48:20 +0200
27
28nevow (0.4.1-1) unstable; urgency=low
29
30 * New upstream version.
31 * Python 2.4 support.
32 * Not using upstream tarball as it is too broken compared to
33 SVN tag; specifically it is missing nevow/Canvas.fla, which
34 is considered source code.
35
36 -- Tommi Virtanen <tv@debian.org> Mon, 27 Jun 2005 15:35:57 +0200
37
38nevow (0.3.0-1) unstable; urgency=low
39
40 * New upstream version.
41
42 -- Tommi Virtanen <tv@debian.org> Thu, 30 Sep 2004 12:12:44 +0300
43
44nevow (0.2.0-2) unstable; urgency=low
45
46 * Build-depend on both python2.3-dev and python-dev, it seems that is
47 what cdbs wants. (Closes: #257911)
48
49 -- Tommi Virtanen <tv@debian.org> Tue, 13 Jul 2004 16:39:17 +0300
50
51nevow (0.2.0-1) unstable; urgency=low
52
53 * Initial Release.
54
55 -- Tommi Virtanen <tv@debian.org> Tue, 29 Jun 2004 10:26:36 +0300
56
570
=== removed file 'Nevow/debian/compat'
--- Nevow/debian/compat 2005-10-14 17:36:24 +0000
+++ Nevow/debian/compat 1970-01-01 00:00:00 +0000
@@ -1,1 +0,0 @@
14
20
=== removed file 'Nevow/debian/control'
--- Nevow/debian/control 2005-11-06 18:46:50 +0000
+++ Nevow/debian/control 1970-01-01 00:00:00 +0000
@@ -1,64 +0,0 @@
1Source: nevow
2Section: devel
3Priority: extra
4Maintainer: Tommi Virtanen <tv@debian.org>
5Standards-Version: 3.6.2
6Build-Depends-Indep: python-dev, python2.3-dev, python2.4-dev, cdbs, debhelper (>= 4.1.68)
7
8Package: python-nevow
9Architecture: all
10Depends: python (>= 2.3), python (<< 2.4), python2.3-nevow
11Description: Web application templating system for Python and Twisted
12 This is a dummy package that only depends on python2.3-nevow.
13
14Package: python2.3-nevow
15Architecture: all
16Depends: python2.3, python2.3-twisted
17Description: Web application templating system for Python and Twisted
18 Nevow's main focus is on separating the HTML template from both the
19 business logic and the display logic, while allowing the programmer
20 to write pure Python code as much as possible. It separates your code
21 into 'data' and 'render' functions, a simplified implementation of
22 traditional MVC. It has various parts which can be used individually
23 or as a whole, integrated web solution:
24 .
25 - XHTML templates: contain no programming logic, only nodes tagged
26 with nevow attributes
27 - data/render methods: simplified MVC
28 - stan: An s-expression-like syntax for expressing xml in pure python
29 - formless: For describing the types of objects which may be passed
30 to methods of your classes, validating and coercing string input from
31 either web or command-line sources, and calling your methods
32 automatically once validation passes
33 - freeform: For rendering web forms based on formless type
34 descriptions, accepting form posts and passing them to formless
35 validators, and rendering error forms in the event validation fails
36 - livepage: Cross-browser JavaScript glue for sending client side
37 events to the server and server side events to the client after the
38 page has loaded, without causing the entire page to refresh
39
40Package: python2.4-nevow
41Architecture: all
42Depends: python2.4, python2.4-twisted
43Description: Web application templating system for Python and Twisted
44 Nevow's main focus is on separating the HTML template from both the
45 business logic and the display logic, while allowing the programmer
46 to write pure Python code as much as possible. It separates your code
47 into 'data' and 'render' functions, a simplified implementation of
48 traditional MVC. It has various parts which can be used individually
49 or as a whole, integrated web solution:
50 .
51 - XHTML templates: contain no programming logic, only nodes tagged
52 with nevow attributes
53 - data/render methods: simplified MVC
54 - stan: An s-expression-like syntax for expressing xml in pure python
55 - formless: For describing the types of objects which may be passed
56 to methods of your classes, validating and coercing string input from
57 either web or command-line sources, and calling your methods
58 automatically once validation passes
59 - freeform: For rendering web forms based on formless type
60 descriptions, accepting form posts and passing them to formless
61 validators, and rendering error forms in the event validation fails
62 - livepage: Cross-browser JavaScript glue for sending client side
63 events to the server and server side events to the client after the
64 page has loaded, without causing the entire page to refresh
650
=== removed file 'Nevow/debian/copyright'
--- Nevow/debian/copyright 2005-10-14 17:36:24 +0000
+++ Nevow/debian/copyright 1970-01-01 00:00:00 +0000
@@ -1,10 +0,0 @@
1This package was debianized by Tommi Virtanen tv@debian.org on
2Sun, 28 Mar 2004 16:44:10 +0300.
3
4It was originally downloaded from http://www.divmod.org/Home/Projects/Nevow/
5
6Upstream Author: Donovan Preston et al <dp@divmod.org>
7
8Copyright:
9
10# See the file LICENSE at the top of the source tree.
110
=== removed file 'Nevow/debian/python2.3-nevow.manpages'
--- Nevow/debian/python2.3-nevow.manpages 2005-10-14 17:36:24 +0000
+++ Nevow/debian/python2.3-nevow.manpages 1970-01-01 00:00:00 +0000
@@ -1,1 +0,0 @@
1doc/man/nevow-xmlgettext.1
20
=== removed file 'Nevow/debian/python2.4-nevow.manpages'
--- Nevow/debian/python2.4-nevow.manpages 2005-10-14 17:36:24 +0000
+++ Nevow/debian/python2.4-nevow.manpages 1970-01-01 00:00:00 +0000
@@ -1,1 +0,0 @@
1doc/man/nevow-xmlgettext.1
20
=== removed file 'Nevow/debian/rules'
--- Nevow/debian/rules 2005-11-06 18:46:50 +0000
+++ Nevow/debian/rules 1970-01-01 00:00:00 +0000
@@ -1,71 +0,0 @@
1#!/usr/bin/make -f
2# -*- mode: makefile; coding: utf-8 -*-
3# Copyright © 2002,2003 Colin Walters <walters@debian.org>
4
5include /usr/share/cdbs/1/rules/debhelper.mk
6include /usr/share/cdbs/1/class/python-distutils.mk
7
8DEB_INSTALL_DOCS_python2.3-nevow := doc/*
9DEB_INSTALL_EXAMPLES_python2.3-nevow := examples/*
10DEB_INSTALL_DOCS_python2.4-nevow := doc/*
11DEB_INSTALL_EXAMPLES_python2.4-nevow := examples/*
12DEB_DH_ALWAYS_EXCLUDE := .svn
13
14docdir = debian/$(1)/usr/share/doc/$(1)
15binary-post-install/%::
16 grep -v '^# See the file LICENSE' \
17 '$(call docdir,$*)/copyright' \
18 >'$(call docdir,$*)/copyright.tmp'
19 cat LICENSE \
20 >>'$(call docdir,$*)/copyright.tmp'
21 mv \
22 '$(call docdir,$*)/copyright.tmp' \
23 '$(call docdir,$*)/copyright'
24
25# see http://bugs.debian.org/295906
26cdbs_python_ver = $(filter-out -%,$(subst -, -,$(patsubst python%,%,$(cdbs_curpkg))))
27
28$(patsubst %,binary-post-install/%,$(DEB_PYTHON_REAL_LIB_PACKAGES)):: binary-post-install/%:
29 set -e; for file in debian/$(cdbs_curpkg)/usr/bin/*; do \
30 sed '1s|.*|#!/usr/bin/python$(cdbs_python_ver)|' $$file >\
31 "$${file}$(cdbs_python_ver)";\
32 rm -- "$$file";\
33 chmod 755 "$${file}$(cdbs_python_ver)";\
34 mv "debian/$(cdbs_curpkg)/usr/share/man/man1/$$(basename "$$file").1" \
35 "debian/$(cdbs_curpkg)/usr/share/man/man1/$$(basename "$$file")$(cdbs_python_ver).1";\
36 done
37
38binary-post-install/python2.3-nevow::
39 set -e; for file in debian/$(cdbs_curpkg)/usr/bin/*;\
40 do target="$$(echo "$$file" | sed 's/$(cdbs_python_ver)$$//')";\
41 ln -s "$$(basename "$$file")" "$$target";\
42 manname="$$(basename "$$target").1.gz";\
43 ln -s "$$(basename "$$file").1.gz" \
44 "debian/$(cdbs_curpkg)/usr/share/man/man1/$$manname";\
45 done
46
47clean::
48 rm -f setupcommon.pyc
49
50
51ifeq (,$(findstring nocheck,$(DEB_BUILD_OPTIONS)))
52TRIAL=trial$(cdbs_python_ver)
53TOPMODULES:=nevow formless
54$(patsubst %,binary-post-install/%,$(DEB_PYTHON_REAL_LIB_PACKAGES)):: binary-post-install/%:
55 PYTHONPATH='debian/$(cdbs_curpkg)/usr/lib/python$(cdbs_python_ver)/site-packages/' \
56 '$(TRIAL)' --bwverbose -R $(TOPMODULES)
57
58 # Importing the modules generates .pyc files, and dh_python (which
59 # normally cleans them) has already been run. Remove them manually.
60 find 'debian/$(cdbs_curpkg)' -name '*.py[co]' -print0 \
61 | xargs -0 rm -f --
62endif
63
64clean::
65 rm -rf _trial_temp
66
67
68# distutils is sloppy and only cleans with the default python version,
69# leaving all the other stuff still in build
70clean::
71 rm -rf build
720
=== removed directory 'Nevow/doc'
=== removed file 'Nevow/doc/README'
--- Nevow/doc/README 2010-04-06 11:05:45 +0000
+++ Nevow/doc/README 1970-01-01 00:00:00 +0000
@@ -1,5 +0,0 @@
1This is Nevow's documentation. The preferred format is Lore XHTML. You can
2generate the pretty version of the documentation with by running the
3following command in the howto directory:
4
5 lore
60
=== removed directory 'Nevow/doc/howto'
=== removed directory 'Nevow/doc/howto/chattutorial'
=== removed file 'Nevow/doc/howto/chattutorial/concepts.xhtml'
--- Nevow/doc/howto/chattutorial/concepts.xhtml 2008-09-03 20:03:47 +0000
+++ Nevow/doc/howto/chattutorial/concepts.xhtml 1970-01-01 00:00:00 +0000
@@ -1,136 +0,0 @@
1<?xml version="1.0"?>
2<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
3 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
4<html xmlns="http://www.w3.org/1999/xhtml">
5 <head>
6 <title>Concepts</title>
7 </head>
8<body>
9
10<h1>Concepts</h1>
11
12<h2>Servers and Clients</h2>
13
14<p>COMET applications can seem an almost impenetrable mess when one is first
15learning about them, much like when writing event-based desktop
16applications. However, there are some basic concepts that we can emphasize now
17to circumvent or alleviate most of the confusion.</p>
18
19<p>In principle, the problem is very simple:</p>
20<ul>
21<li>We want out users to interact with a <q>web page</q> with out having to refresh
22the page, and we want new data and/or views to be rendered in response to our
23users' actions;</li>
24<li>We want the ability to push updates to user pages from the server to the
25browser, when the server has new data or views that are ready.</li>
26</ul>
27
28<p>As usual, the implementation of the solution is much more complicated than
29the statement of the problem, but hopefully the way that we have designed
30Athena will hide those implementation details while providing powerful tools to
31build the applications you envision. So, let's take a look at what you need to
32know about servers and clients when building Athena web applications.</p>
33
34<p>It is crucial that one understands that when we write Athena applications,
35we are doing a few different things:</p>
36<ul>
37<li>Writing server code in Python that performs server actions</li>
38<li>Writing server code in Python that makes remote calls to the browser</li>
39<li>Writing browser code in JavaScript that performs browser actions</li>
40<li>Writing browser code in JavaScript that makes remote calls to the server</li>
41</ul>
42
43<p>Since server-on-server and client-on-client are rather common place and
44generally well understood, we will ignore those for now. As the other two
45are the focus of AJAX/COMET and thus also the primary domain of Athena, that is
46what we will discuss below.</p>
47
48<p>Browser-to-server calls are made by Athena via the now-famous
49 XMLHttpRequest. Server-to-browser calls are opened by the browser ahead of
50time, and when the server is ready, the data is sent to the browser via that
51connection.</p>
52
53<h2>JavaScript: Making Calls to the Server</h2>
54
55<p>When creating the JavaScript portion of our applications, we subclass
56an Athena JavaScript widget, which has a method named
57<code>callRemote()</code>. By utilizing this method, we can send messages from
58our JavaScript client to the server (as long as the method we call exists in
59the server code).</p>
60
61<p>For example, in the chat application we will be building in this series
62of tutorials, we will have a JavaScript class called <code>ChatterBox</code> with a
63<code>say()</code> method, like the following:</p>
64<pre>
65function say(self, msg) {
66 self.callRemote("say", msg);
67 // Now show the text to the user somehow...
68}
69</pre>
70<p>This will make a remote call to the Python server code, executing the
71<code>say()</code> method and passing the <code>msg</code> variable as a
72parameter.</p>
73
74<p>In Athena, the relationship between the browser code and the server code is
75established by declaring the JavaScript module in the Python server code, in
76the following manner:</p>
77<pre class="python">
78class ChatterBox(LiveElement):
79 jsClass = u'ChatThing.ChatterBox'
80</pre>
81<p>Additionally, in order for the JS to be able to make a call to remote Python
82code, the Python method has to be exposed. This is a security feature,
83implemented to ensure the JavaScript code can only call Python methods that
84have been specifically marked as safe. Appropriately enough, this is done in
85your Python class with the <code>expose</code> decorator:</p>
86
87<pre class="python">
88def say(self, text):
89 for chatter in chatRoom:
90 chatter.youHeardSomething(text)
91say = expose(say)
92</pre>
93
94<h2>Python: Making Calls to the Browser</h2>
95
96<p>Now what about the COMET side of the equation? If we want our server to
97update data in the browser, we need to be able to call JavaScript code from our
98Python server. We use a similar Python method as the JavaScript one (when
99making calls from the browser to the server), acquired when our Python class
100inherited from <code>nevow.athena.LiveElement</code>:</p>
101
102<pre class="python">
103def hear(self, sayer, text):
104 self.callRemote("hear", sayer, text)
105</pre>
106
107<p>In order for this call to work, we need to have the <code>hear()</code>
108method defined in our <code>ChatterBox</code> JavaScript class, and that will
109look like this:</p>
110<pre>
111function hear(self, avatarName, text) {
112 // Here, you'd show the user some text.
113}
114</pre>
115
116<p>Unlike on our Python classes, no special annotations need to be made on the
117JavaScript side: all JavaScript methods on browser-side Widget objects are
118allowed to be called by the server. If you've sent code to the browser, you've
119already forfeited the ability to control when it's called. There wouldn't be a
120point to limiting the server's rights to run its code when the user can freely
121run it herself.</p>
122
123<h2>Summary</h2>
124
125<p>With the samples above, you should have a growing sense of how Python and
126JavaScript interact as servers and clients in the world of Athena. In
127particular, you should be getting a sense of how JavaScript and Python will be
128interacting in your Athena applications.</p>
129
130<p>This has just been a taste of Athena with a few peeks into the code we
131will be writing. We will cover these topics in greater detail in the following
132pages, within the context of creating a functional Athena application,
133complete with step-by-step instructions and rationale.</p>
134
135</body>
136</html>
1370
=== removed file 'Nevow/doc/howto/chattutorial/env.xhtml'
--- Nevow/doc/howto/chattutorial/env.xhtml 2008-09-03 20:03:47 +0000
+++ Nevow/doc/howto/chattutorial/env.xhtml 1970-01-01 00:00:00 +0000
@@ -1,122 +0,0 @@
1<?xml version="1.0"?>
2<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
3"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
4<html xmlns="http://www.w3.org/1999/xhtml">
5 <head>
6 <title>Setting up an Environment</title>
7 </head>
8<body>
9
10<h1>Setting up an Environment</h1>
11
12<h2>Install</h2>
13
14To run this tutorial, you need to have nevow available to python and
15you'll need the files in the doc/howto tree. You don't even have to
16install nevow; the examples will run within the source tree.
17
18
19<h3>Combinator: The Divmod Way</h3>
20
21<p>Using SVN
22with <a href="http://divmod.org/trac/wiki/DivmodCombinator">Combinator</a>
23is the best way to try out the example code in-place (and hop between
24other SVN branches in the future). This is how we develop and test our
25applications at Divmod. If you have a system installation of Twisted
26that you don't want to update or interfere with, you can use this
27method without installing anything.
28</p>
29
30<ol>
31
32<li>Create a projects directory or change to some other test directory
33of your choice:
34<pre class="shell">
35$ mkdir ~/Projects
36$ cd ~/Projects
37</pre>
38</li>
39
40
41<li>If you don't have the
42<a href="http://twistedmatrix.com/trac/">twisted library</a>, check it out now:
43<pre class="shell">
44$ svn co svn://svn.twistedmatrix.com/svn/Twisted/trunk Twisted/trunk
45</pre>
46</li>
47
48<li>Then get Combinator and Nevow (and the rest of Divmod). See the
49<a href="http://divmod.org/trac/wiki/CombinatorTutorial">Combinator
50Tutorial</a> for more about these special checkout paths.
51<pre class="shell">
52$ svn co http://divmod.org/svn/Divmod/trunk Divmod/trunk
53</pre>
54</li>
55
56<li>Set up the Combinator environment in this shell. You'll need this
57step in any future test shells since it adjusts PATH and PYTHONPATH:
58<pre class="shell">
59$ eval `python Divmod/trunk/Combinator/environment.py`
60(some "link:" lines are normal)
61</pre>
62</li>
63
64<li>Register both the Twisted and Divmod (and thus Nevow+Athena) codebases with
65Combinator:
66<pre class="shell">
67$ chbranch Twisted trunk
68$ chbranch Divmod trunk
69</pre>
70</li>
71
72<li>You can check to see if your environment is ready to go by running the
73tutorial tests (from any directory, after executing the previous command):
74<pre class="shell">
75$ trial nevow.test.test_howtolistings
76</pre>
77If they all pass, you're ready to begin the tutorial.
78</li>
79</ol>
80
81
82
83<h3>Standard distutils Installation</h3>
84
85<p>If you don't want to manage branches and environments with
86Combinator, you can install our code in the
87standard <code>site-packages</code> directory. You'll still need the
88source tree so you can use the files in doc/howto.</p>
89
90<p>For those that would prefer the <q>old way,</q> here's how you do it:</p>
91
92<ol>
93
94<li>Create a projects directory:
95<pre class="shell">
96$ mkdir ~/Projects
97$ cd ~/Projects
98</pre>
99</li>
100
101<li>Checkout and install the latest Twisted:
102<pre class="shell">
103$ svn co svn://svn.twistedmatrix.com/svn/Twisted/trunk Twisted
104$ cd Twisted
105$ sudo python setup.py install
106$ cd ../
107</pre>
108</li>
109
110<li>Checkout and install Nevow:
111<pre class="shell">
112$ svn co http://divmod.org/svn/Divmod/trunk/Nevow Nevow
113$ cd Nevow
114$ sudo python setup.py install
115$ cd ../
116</pre>
117</li>
118
119</ol>
120
121</body>
122</html>
1230
=== removed file 'Nevow/doc/howto/chattutorial/index.xhtml'
--- Nevow/doc/howto/chattutorial/index.xhtml 2008-09-03 20:03:47 +0000
+++ Nevow/doc/howto/chattutorial/index.xhtml 1970-01-01 00:00:00 +0000
@@ -1,56 +0,0 @@
1<?xml version="1.0"?>
2<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
3"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
4<html xmlns="http://www.w3.org/1999/xhtml">
5 <head>
6 <title>Nevow Athena from Scratch, or The Evolution of a Chat Application</title>
7 </head>
8<body>
9
10 <h1>Nevow Athena from Scratch, or The Evolution of a Chat Application</h1>
11
12<h2>The <q>Chat Tutorial</q> Series</h2>
13
14<p>
15Athena is the JavaScript engine behind Nevow, providing a great deal of
16resources and power to the developer of asynchronous web applications. To
17demonstrate this, we are using a web chat application as our primary example
18in this tutorial. The tutorial is split into several parts: a few introductory
19pages and then independent (but related) tutorials of increasing complexity.
20</p>
21
22<ol>
23 <li>Basics
24 <ul>
25 <li><a href="intro.xhtml">Introduction</a></li>
26 <li><a href="concepts.xhtml">Concepts of Athena: AJAX, COMET, and Python</a></li>
27 <li><a href="env.xhtml">Setting Up the Tutorial Environment and Running Tutorial Source Code</a></li>
28 </ul>
29 </li>
30 <li><a href="part00/index.xhtml">Toy <q>Echo</q> Application </a></li>
31 <li><a href="part01/index.xhtml">Simple Chat and Two-Way Communications</a></li>
32</ol>
33
34<h2>History</h2>
35<p>
36Nevow's predecessor was Woven (and prior to that, WebMVC). Woven had something
37called <code>LivePage</code> that was doing DOM manipulation as far back as
382002. In early 2003, Woven event handlers supported sending JavaScript back to
39the user's browser, allowing pages to be updated in response to user-generated
40events. The earliest publicly visible revisions of Nevow made use of XHR
41(XMLHttpRequest) in early 2004. These facts are notable because Nevow was using
42AJAX a year before the term was coined in 2005 and had working code in 2002 and
432003 that predated Netscape publishing articles on what they called <q>Inner
44Browsing</q> where all navigation takes place withing a single page.
45</p>
46
47<p>
48Again taking the lead, Athena offers features which developers cannot find
49elsewhere. In this series, we attempt to expose these excellent qualities
50to the world of application
51developers.
52</p>
53
54</body>
55</html>
56
570
=== removed file 'Nevow/doc/howto/chattutorial/intro.xhtml'
--- Nevow/doc/howto/chattutorial/intro.xhtml 2008-09-03 20:03:47 +0000
+++ Nevow/doc/howto/chattutorial/intro.xhtml 1970-01-01 00:00:00 +0000
@@ -1,106 +0,0 @@
1<?xml version="1.0"?>
2<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3<html xmlns="http://www.w3.org/1999/xhtml">
4 <head>
5 <title>Introduction</title>
6 </head>
7<body>
8
9<h1>Introduction</h1>
10
11<h2>Who is this tutorial for?</h2>
12
13<p>This tutorial is for people who want to build interactive client-server
14functionality where a web-browser is the client. It will show you how to build
15a live, interactive chat application that requires nothing more than a web
16browser that supports JavaScript.</p>
17
18<p>The interesting thing about a chat application, which shows why Nevow Athena
19is special, is that it involves two-way communication. In other words, it
20involves not only the recently-popular AJAX (the web browser sending commands
21to the server without loading a new page) but also the trickier and, in our
22opinion, somewhat cooler technique known as COMET (the web server
23sending commands to the <em>browser</em>).</p>
24
25<h2>Who is this tutorial <em>not</em> for?</h2>
26
27<p>Nevow Athena is <em>not</em> for people who want a normal web application
28framework. If you want one of those, you should use
29non-Athena-<a href="http://divmod.org/trac/wiki/DivmodNevow">Nevow</a>,
30<a href="http://www.djangoproject.com/">Django</a>,
31<a href="http://turbogears.org/">TurboGears</a>, or maybe even
32<a href="http://rubyonrails.org/">Ruby On Rails</a>. Athena doesn't work in terms
33of pages, links, or HTTP requests and responses; it is a client-server
34framework that works in terms of widgets, JavaScript objects, and symmetric
35asynchronous message queues.</p>
36
37<p>However, as alluded to above, Athena is part of a larger framework, Nevow,
38which can be used to build more general-purpose and <q>traditional</q>
39web applications.</p>
40
41<h2>AJAX</h2>
42
43<p>AJAX isn't a technology in and of itself, bur rather an amalgam of
44technologies used together in order to accomplish the goal of making web
45applications more responsive than traditional delivery and interactive
46mechanisms, such as HTML forms submitted to a server.</p>
47
48<p>In particular, AJAX consists of the following:</p>
49<ul>
50<li>Asynchronous communications from a user's browser to a server</li>
51<li>JavaScript</li>
52<li>Exchanged data (usually XML or JSON)</li>
53</ul>
54
55<h2>COMET</h2>
56
57<p>Historically, the focus of AJAX technologies was user-event driven. However,
58with the need to update the user's browser with events generated at the server,
59a solution more sophisticated than AJAX was needed; this has been dubbed COMET.
60Athena is implemented using both AJAX and COMET techniques, and therefore
61allows two-way browser &lt;-&gt; server communications.</p>
62
63<h2>Athena Basics</h2>
64
65<p>We've provided brief background information on AJAX/COMET, but what is the
66purpose of Athena? What makes Athena different than other solutions? Here are a
67few key points that should help with these questions::</p>
68<ul>
69<li>Athena exists to make writing COMET web applications easy.</li>
70<li>Athena is written in Python and JavaScript</li>
71<li>It is written to be used with Nevow, a <a
72href="http://twistedmatrix.com/">Twisted</a>-based web framework.</li>
73<li>Similar to Twisted's <a
74href="http://twistedmatrix.com/projects/core/documentation/howto/pb-intro.html">Perspective
75Broker</a>, Athena employs remote calls.</li>
76</ul>
77
78<p>Athena was written by Twisted and Divmod developers (in addition to
79contributing members of the community) in order to bring the outdated and
80Nevow-incompatible Woven LivePage technology to Nevow. In addition, it was an
81opportunity to improve upon the original design and incorporate new features to
82address the growing needs of developers.</p>
83
84<h2>Target Applications</h2>
85
86<p>Good candidates for Athena web applications would include those where the
87application needs to respond to user input and/or updates from servers, such
88as the following:</p>
89<ul>
90<li>conference software (e.g. whiteboard, shared text, chat, etc.)</li>
91<li>mail clients</li>
92<li>interactive, multi-player games</li>
93<li>social networking tools</li>
94<li>office applications (e.g., spreadsheets, word processors, etc.)</li>
95</ul>
96
97<h2>Target Developers</h2>
98
99<p>Anyone who wants to create interactive, web-based applications is a
100potential Nevow/Athena user. It's best to have some background in writing web
101applications, and in addition, to know how to use Nevow. However, we hope that
102this tutorial will be just as useful for beginners as experienced
103developers.</p>
104
105</body>
106</html>
1070
=== removed directory 'Nevow/doc/howto/chattutorial/part00'
=== removed file 'Nevow/doc/howto/chattutorial/part00/index.xhtml'
--- Nevow/doc/howto/chattutorial/part00/index.xhtml 2008-09-03 20:03:47 +0000
+++ Nevow/doc/howto/chattutorial/part00/index.xhtml 1970-01-01 00:00:00 +0000
@@ -1,230 +0,0 @@
1<?xml version="1.0"?>
2<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
3"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
4<html xmlns="http://www.w3.org/1999/xhtml">
5 <head>
6 <title>Nevow Athena from Scratch: Echo Application</title>
7 </head>
8<body>
9
10<h2>What is an "Echo Application?"</h2>
11
12<p>
13Our first foray into building an Athena application will be an easy venture:
14we want to type something in an input box and have it echoed back to us on
15the same page, without having to reload anything. Why? Well, our eventual
16goal is to have a working chat server, with all sorts of technical bells
17and whistles (persistent storage, authentication,
18etc.), but that's a bit heady for right now. Many of the same principles
19which we will eventually employ in our chat application exist for a simple
20case of sending textual messages between a web browser and a server. This
21is the essence of our "Echo" application.
22</p>
23
24<h2>Mental Preparation</h2>
25
26<p>In the
27<a href="../intro.html">Introduction</a> and the
28<a href="../concepts.html">Concepts</a> pages, we had a refresher on AJAX and
29COMET and we learned a little bit about what that looks like for Athena. But
30as we sit down to actually write an Athena application, what do we need to
31wrap our heads around?
32</p>
33
34<p>Given the introductory knowledge we have, we know that we will need to
35write some JavaScript, some Python, and if our past experience in developing
36web applications is any guide, some form of template. This indeed is the
37case, but here's something big: we're not working with pages and page
38templates; we're working with "elements", or parts of the DOM tree. We will
39not be creating page resources; we will be creating just the parts of a
40"traditional" page that will be dynamic and interactive.
41</p>
42
43<h2>Architecture</h2>
44
45<p>Now that we've pumped ourselves up and before we start clacking away at the
46keyboard, we need to get pointed in the right direction. We need a
47plan. Here's what we know:</p>
48
49<ol>
50<li>We will have a server that:
51 <ul>
52 <li>serves dynamic elements in a resource accessible via a URL;</li>
53 <li>communicates with a client.</li>
54 </ul>
55</li>
56<li>We will have a client that:
57 <ul>
58 <li>communicates with the server;</li>
59 <li>updates its DOM tree.</li>
60 </ul>
61</li>
62</ol>
63
64<p>The user experience of this application will be the following:</p>
65<ol>
66<li>they will type text in an input on a form; and</li>
67<li>the typed text will be rendered to a different part of the page upon
68hitting a submit button.</li>
69</ol>
70
71<p>We will not simply write user input to a <code>div</code> with JavaScript
72DOM manipulation, but will instead pass data like we expect will be necessary
73when we write our chat application. After all, it's probably best to build
74towards our goal. In order to accomplish this, the application will do
75something like the following:</p>
76
77<ol>
78<li>JavaScript client code will extract user input and send
79it to our server;</li>
80<li>Python code will receive messages from the client;</li>
81<li>Python code will send messages to the client; and</li>
82<li>a template file (or <code>stan</code> code) will be used for
83presentation.</li>
84</ol>
85
86<p></p>
87
88<h2>Let the Coding Begin</h2>
89
90<p>In a future installment, we will outline the development process from
91the perspective of test-driven development, in order to not only show how
92to write unit tests for Athena (Python and JavaScript), but to encourage
93good programming practices while working with Athena. For now, though, we will
94just dive right in.</p>
95
96<h3>Presentation</h3>
97
98<p>Let's start with the easy bit: what our app will look like. Here is the
99template for our echo application:</p>
100
101<a href="listings/echothing/template.html" class="html-listing" />
102
103<p>Things to note:</p>
104<ul>
105<li>This is not a complete HTML document, but is an XHTML template for an
106"element".</li>
107<li>The name space declarations in the top <code>div</code> tag are necessary
108for the operation of Athena.</li>
109<li>When we hit the "Send" button, our JavaScript class will call the
110<code>doSay()</code> method.</li>
111</ul>
112
113<h3>Writing the Client</h3>
114
115<p>Next up is the JavaScript. We need to send our data to the server. In a
116full chat application, it would be necessary to send the data to the server
117so that we could propagate the message to all connected clients. In this
118case, with the simple echo, we're not going to do anything with the data
119that gets sent to the server, except send it back, of course.</p>
120
121<p>Our JavaScript will need to do several things:</p>
122<ol>
123<li>import required modules;</li>
124<li>inherit <code>callRemote</code> functionality from the base
125<code>Widget</code> class;</li>
126<li>setup convenience attributes;</li>
127<li>implement the <code>doSay()</code> method we put in our template above;
128and</li>
129<li>implement a method for updating the DOM with data it receives from
130the server</li>
131</ol>
132
133<a href="listings/echothing/js/EchoThing.js" class="py-listing" />
134
135<p>Points to note:</p>
136<ul>
137<li>Those import statements aren't just pretty: they are necessary! In Athena,
138you need to treat those like you treat the import statements in Python.
139</li>
140<li>The attributes set in the <code>__init__()</code> method are for
141convenience when we reference them in other methods.</li>
142<li>Note the <code>callRemote()</code> method in <code>doSay()</code>,
143As mentioned in the <a href="../concepts.html">Concepts</a> section, this
144is how JavaScript is communicating with our Python server.</li>
145<li>Another thing about <code>doSay</code>: this is the submit handler. As
146such, it needs to return false so that the browser is prevented from doing a
147normal form submission.</li>
148<li><code>addText()</code> is the method that will be updating the browser
149DOM once the server sends the data back.</li>
150</ul>
151
152<p>There's not much to say about the next one. This is what sets up the
153relationship between our module name and the actual file itself (so that
154the JavaScript can be loaded):</p>
155
156<a href="listings/nevow/plugins/echothing_package.py" class="py-listing" />
157
158<h3>Writing the Server</h3>
159
160<p>Despite what one might think, writing the server may be the easiest
161part! If you've created Nevow applications before, then this will look
162very familiar. The only method we need is one that will send data back to
163the client. Besides importing the necessary modules and creating a class
164with some boilerplate, that's about it.
165</p>
166
167<p>Let's take a look at the code:</p>
168
169<a href="listings/echothing/echobox.py" class="py-listing" />
170
171<p>As promised, simple as can be. We do make use of a Twisted utility that
172simplifies typing the path to our template. Some very important points:</p>
173<ul>
174<li>The <code>jsClass</code> assignment is what connects this code to your
175JavaScript code.</li>
176<li>As discussed in the <a href="../concepts.html">Concepts</a> section,
177the <code>expose</code> decorator is required if our JavaScript is going
178to be able to call the <code>say()</code> method.</li>
179</ul>
180
181<h3>Putting it All Together</h3>
182
183<p>Now that we've got all the code in front of us, we can trace out exactly
184what happens:</p>
185<ol>
186<li>the user loads the resource in their browser, and the template is
187rendered;</li>
188<li>after typing a message in the input box, the user hits submit;</li>
189<li>upon hitting submit, the client code <code>doSay()</code> method is
190called;</li>
191<li><code>doSay()</code> makes a remote call to the Python server method
192<code>say()</code>;</li>
193<li>the Python server receives the data when <code>say()</code> is called, and
194then it passes that data to the client code's <code>addText()</code> method;</li>
195<li>with control back in the client code and data fresh from the server,
196JavaScript can now update the page's DOM with the new data, and this is
197what the <code>addText()</code> method does;</li>
198<li>when <code>addText()</code> finishes, the cycle has completed and the
199browser now displays the latest data input by the user.</li>
200</ol>
201
202<h3>The Fruits of Our Labor</h3>
203
204<p>Now we get to run it! This is a little different than what you may be
205used to, if you have written Twisted applications in the past. We are using
206the plugin architecture of Twisted and Nevow such that <code>twistd</code>
207will publish our element in an HTTP service. To do this, we will use
208<code>twistd</code>'s <code>athena-widget</code> command:</p>
209
210<pre class="shell">
211cd Nevow/doc/howto/chattutorial/part00/listings
212twistd -n athena-widget --element=echothing.echobox.EchoElement
213</pre>
214
215<p>If you executed this against the tutorial code on your local machine,
216you can now visit <a href="http://localhost:8080">localhost:8080</a> and start
217echoing to your heart's content.</p>
218
219<h2>Summary</h2>
220
221<p>As you can see, our echo application is a toy app that doesn't do
222anything very useful. However, it has provided us with a basis for learning how
223to write working Athena code that lets a browser and server communicate
224with each other, both sending and receiving data. As such, we now have a
225solid foundation upon which we can build a functional, useful <i>and</i>
226instructional chat application.</p>
227
228</body>
229</html>
230
2310
=== removed directory 'Nevow/doc/howto/chattutorial/part00/listings'
=== removed directory 'Nevow/doc/howto/chattutorial/part00/listings/echothing'
=== removed file 'Nevow/doc/howto/chattutorial/part00/listings/echothing/__init__.py'
--- Nevow/doc/howto/chattutorial/part00/listings/echothing/__init__.py 2008-09-03 20:03:47 +0000
+++ Nevow/doc/howto/chattutorial/part00/listings/echothing/__init__.py 1970-01-01 00:00:00 +0000
@@ -1,1 +0,0 @@
1
20
=== removed file 'Nevow/doc/howto/chattutorial/part00/listings/echothing/echobox.py'
--- Nevow/doc/howto/chattutorial/part00/listings/echothing/echobox.py 2008-09-03 20:03:47 +0000
+++ Nevow/doc/howto/chattutorial/part00/listings/echothing/echobox.py 1970-01-01 00:00:00 +0000
@@ -1,12 +0,0 @@
1from twisted.python.util import sibpath
2from nevow.athena import LiveElement, expose
3from nevow.loaders import xmlfile
4
5class EchoElement(LiveElement):
6
7 docFactory = xmlfile(sibpath(__file__, 'template.html'))
8 jsClass = u'EchoThing.EchoWidget'
9
10 def say(self, message):
11 self.callRemote('addText', message)
12 say = expose(say)
130
=== removed directory 'Nevow/doc/howto/chattutorial/part00/listings/echothing/js'
=== removed file 'Nevow/doc/howto/chattutorial/part00/listings/echothing/js/EchoThing.js'
--- Nevow/doc/howto/chattutorial/part00/listings/echothing/js/EchoThing.js 2009-01-21 22:58:03 +0000
+++ Nevow/doc/howto/chattutorial/part00/listings/echothing/js/EchoThing.js 1970-01-01 00:00:00 +0000
@@ -1,22 +0,0 @@
1// import Nevow.Athena
2
3Nevow.Athena.Widget.subclass(EchoThing, 'EchoWidget').methods(
4 function __init__(self, node) {
5 EchoThing.EchoWidget.upcall(self, "__init__", node);
6 self.echoWidget = self.nodeByAttribute('name', 'echoElement');
7 self.scrollArea = self.nodeByAttribute('name', 'scrollArea');
8 self.message = self.nodeByAttribute('name', 'message');
9 },
10
11 function doSay(self) {
12 self.callRemote("say", self.message.value);
13 self.message.value = "";
14 return false;
15 },
16
17 function addText(self, text) {
18 var newNode = document.createElement('div');
19 newNode.appendChild(document.createTextNode(text));
20 self.scrollArea.appendChild(newNode);
21 document.body.scrollTop = document.body.scrollHeight;
22 });
230
=== removed file 'Nevow/doc/howto/chattutorial/part00/listings/echothing/template.html'
--- Nevow/doc/howto/chattutorial/part00/listings/echothing/template.html 2008-09-03 20:03:47 +0000
+++ Nevow/doc/howto/chattutorial/part00/listings/echothing/template.html 1970-01-01 00:00:00 +0000
@@ -1,11 +0,0 @@
1<div xmlns:nevow="http://nevow.com/ns/nevow/0.1"
2 xmlns:athena="http://divmod.org/ns/athena/0.7"
3 nevow:render="liveElement">
4 <h2>Echo Element</h2>
5 <form name="echoElement">
6 <athena:handler event="onsubmit" handler="doSay" />
7 <div name="scrollArea">
8 </div>
9 <input name="message" /><input type="submit" value="Send" />
10 </form>
11</div>
120
=== removed directory 'Nevow/doc/howto/chattutorial/part00/listings/nevow'
=== removed directory 'Nevow/doc/howto/chattutorial/part00/listings/nevow/plugins'
=== removed file 'Nevow/doc/howto/chattutorial/part00/listings/nevow/plugins/echothing_package.py'
--- Nevow/doc/howto/chattutorial/part00/listings/nevow/plugins/echothing_package.py 2008-09-03 20:03:47 +0000
+++ Nevow/doc/howto/chattutorial/part00/listings/nevow/plugins/echothing_package.py 1970-01-01 00:00:00 +0000
@@ -1,8 +0,0 @@
1
2from twisted.python import util
3
4from nevow import athena
5
6import echothing
7
8chatthingPkg = athena.AutoJSPackage(util.sibpath(echothing.__file__, 'js'))
90
=== removed directory 'Nevow/doc/howto/chattutorial/part01'
=== removed file 'Nevow/doc/howto/chattutorial/part01/index.xhtml'
--- Nevow/doc/howto/chattutorial/part01/index.xhtml 2008-09-03 20:03:47 +0000
+++ Nevow/doc/howto/chattutorial/part01/index.xhtml 1970-01-01 00:00:00 +0000
@@ -1,236 +0,0 @@
1<?xml version="1.0"?>
2<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
3"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
4<html xmlns="http://www.w3.org/1999/xhtml">
5 <head>
6 <title>Nevow Athena from Scratch: Chat Application</title>
7 </head>
8<body>
9
10<h2>Architecture</h2>
11
12<p>We'll assume that you've read all the preceding sections of this tutorial
13and have just finished the "Echo" application example. As such, we don't need
14to do any more "mental preparation" and can skip straight to a description of
15the architecture.</p>
16
17<p>Fundamentally, this is no different than our echo application: there is
18a little more chatter that takes place between the client and server;
19there's another object involved (a <code>ChatRoom</code>); and we'll have
20to run the server a little differently.
21</p>
22
23<p>Here are the new features we want to support:</p>
24<ul>
25<li>login form;</li>
26<li>in-memory user storage;</li>
27<li>the ability to send global alerts to all users; and</li>
28<li>the ability for all users to "hear" when another user speaks in the
29chat room;</li>
30</ul>
31
32<p>A general rule we can establish about our architecture is that if something
33has to happen for everyone, that code needs to appear on the server side,
34since it's the server that is keeping track of all users. If something is
35going to happen irrespective of other users or if browser DOM manipulation
36is required, then we know the client will be the recipient of the code.</p>
37
38<p>As such, in the features above, the login form will be client code. The
39user storage, global alerts, and "hearing" will be implemented in server
40code for the data; updating the DOM with that data will be implemented in
41client code.</p>
42
43<p>The user experience of this application will be the following:</p>
44<ol>
45<li>they will be presented with a login box (no password, only username);</li>
46<li>upon logging in, a message will be sent to all logged in users that
47this person has joined, they will see a message at the bottom of the
48chat that states their login name, and the login form will be replaced with
49a chat area and a text input field;</li>
50<li>they will type text in the input field; and</li>
51<li>the typed text will appear in the browser of every person who is
52logged in.</li>
53</ol>
54
55<p>Building upon our previous example, our application will do the
56following:</p>
57
58<ol>
59<li>JavaScript client code will extract user input and send
60it to our server;</li>
61<li>Python code will receive messages from the client;</li>
62<li>Python code will process these messages;</li>
63<li>Python code will send messages to the all clients; and</li>
64<li>a template file (or <code>stan</code> code) will be used for
65presentation.</li>
66</ol>
67
68<h2>More Coding</h2>
69
70<h3>Presentation</h3>
71
72<p>The template is very similar as it was in the previous example, with
73the differences being a new login box, a "logged in as"
74area, and some name changes:</p>
75
76<a href="listings/chatthing/template.html" class="html-listing" />
77
78<p>We've now got two JavaScript methods that need to be defined:
79<code>doSetUsername()</code> and <code>doSay()</code>. We can also infer
80from this template that elements will be hidden and shown after login
81(note the presence of <code>style="display:none"</code> in two places). With
82these observations in hand, let's proceed to the JavaScript code.</p>
83
84<h3>Writing the Client</h3>
85
86<p>Referring back to our thoughts in the "Architecture" section above, we
87can establish that the JavaScript code needs the following:</p>
88
89<ul>
90<li>have the same basic boilerplate as in the "echo" example (imports,
91inheritance, attribute-setting in the constructor);</li>
92<li>implement the <code>doSetUsername()</code> and <code>doSay()</code>
93methods;</li>
94<li>create a method that will send a message to all users; and</li>
95<li>create a method that will let everyone know when someone says
96something. Let's see how this is done.</li>
97</ul>
98
99<a href="listings/chatthing/js/ChatThing.js" class="py-listing" />
100
101<p>There is a little abstraction here:</p>
102<ul>
103<li>we need a general message-sending method (<code>displayMessage()</code>) for any
104message that gets sent to all users;</li>
105<li>for user chat messages, we need something that will prepend the username so
106that everyone knows who said what (<code>displayUserMessage()</code>), and once this method
107does its thing, it passes the adjusted message on to <code>displayMessage()</code>.</li>
108</ul>
109
110<p>Other than that, this is very straight-forward code; it's pretty much
111the same as the "Echo" tutorial. The <code>display*()</code> methods
112are only responsible for updating the UI, just as we would expect.</p>
113
114We also need the same glue that we demonstrated in the "Echo" example:
115
116<a href="listings/nevow/plugins/chatthing_package.py" class="py-listing" />
117
118<h3>Writing the Server</h3>
119
120<p>The server code is a bit more complicated. We
121anticipated this above in the "Architecture" section where we noted that
122the Python code needs to receive, process and send messages.</p>
123
124<a href="listings/chatthing/chatterbox.py" class="py-listing" />
125
126<p>There is something in our "Chat" code that is not at all present in the
127"Echo" application: the <code>ChatRoom</code> object. We need this object for the
128following functionality:</p>
129<ul>
130<li>a means of instantiating new <code>ChatterElement</code> clients;</li>
131<li>a "singleton" instance for keeping track of all <code>ChatterElement</code> clients;</li>
132<li>a means sending messages to all clients;</li>
133</ul>
134
135<p>Let's look at the second two reasons first. In our "Chat" application,
136a new <code>ChatterElement</code> is created whenever a user connects,
137so we will have potentially many of these instances. In order
138for our chat server to function as designed, it will need a way to
139communicate with each of these. If we create an object that can keep the
140<code>ChatterElement</code>es in a list, then it will be able to iterate that
141list and call methods that, in turn, make remote calls to the JavaScript.
142</p>
143
144<p>Because we need the chat room to be a singleton object, it
145can only be instantiated once. But we need many instantiations of
146<code>ChatterElement</code> -- one for each connection, in fact. So what do
147we do? Well, in this case, we make one of the methods
148of <code>ChatRoom</code> a factory for instantiating a
149<code>ChatterElement</code>. Before we return the instance, though, we
150append it to the list of instances that the <code>ChatRoom</code>
151is keeping track of.
152</p>
153
154<h3>Putting it All Together</h3>
155
156
157<p>Now that we've got all the code in front of us, we can trace out exactly what happens:</p>
158
159<ol>
160<li>the user loads the resource in their browser, and the template is rendered;</li>
161<li>after typing a message in the input box, the user hits submit;</li>
162<li>JavaScript client code calls to the server with the text the user submitted;</li>
163<li>the server gets the message and shares it with all the connected
164<code>ChatterElement</code>s;</li>
165<li>each <code>ChatterElement</code> hears this message and passes it back to the JavaScript client;</li>
166<li>the client prepends the username to the message and then updates the display with the complete message.</li>
167</ol>
168
169<p>
170Keep in mind that <code>ChatterElement</code> entails several duties: it
171establishes a relationship with a room object, it "registers" a user (there's a
172one-to-one mapping between users and <code>ChatterElement</code>), it sends
173messages to the browser, and it receives messages from the chat room. Being a
174<code>LiveElement</code> subclass, <code>ChatterElement</code> is also
175responsible for the view (via the document factory).
176</p>
177
178
179<h3>Running with <code>twistd</code></h3>
180
181<p>One last bit of code that may seem odd is the <code>chat</code>
182variable we define right after the <code>ChatRoom</code> class. What
183is this? This is how we make all this cleverness work as a twisted
184plugin. </p>
185
186<p>If you recall, in our "Echo" application, we ran the code with
187the following command:
188</p>
189
190<pre class="shell">
191twistd -n athena-widget --element=echothing.echobox.EchoElement
192</pre>
193
194<p>The value we pass as the <code>--element</code> argument is the dotted
195name of the <code>LiveElement</code> object of which our "web page"
196is primarily comprised: the <code>EchoElement</code> object. In
197our "Chat" application, we have more moving parts: not only
198do we have the <code>ChatterElement</code> object, but we have the
199<code>ChatRoom</code> object which is responsible for keeping track of
200many <code>ChatterElement</code>es. By defining the <code>chat</code>
201variable, we are accomplishing the following all at once:
202</p>
203
204<ul>
205<li>providing a variable that can be accessed as a dotted name and thus
206used when starting the server (<code>chatthing.chatterbox.chat</code>);</li>
207<li>creating a singleton of <code>ChatRoom</code> (via the "magic"
208of Python module-level instantiations);</li>
209<li>making use of a factory, that when called, will both return a
210new <code>ChatterElement</code> instance <i>and</i> add itself to the
211<code>ChatRoom</code>.</li>
212</ul>
213
214<p>Running this version of our code is a little bit different than the
215"Echo" version. This is because of the <code>ChatRoom</code> code we
216discussed above. As such, we pass a factory as our element, like so:</p>
217
218<pre class="shell">
219cd Nevow/doc/howto/chattutorial/part01/listings
220twistd -n athena-widget --element=chatthing.chatterbox.chat
221</pre>
222
223<p>If you executed this against the tutorial code on your local machine,
224you can now visit <a href="http://localhost:8080/">http://localhost:8080/</a>
225and start chatting to your heart's content.</p>
226
227<h2>Summary</h2>
228<p>
229Unlike our echo application, the chat application has some real functionality
230and does some useful stuff: supporting user chats via browser/server two-way
231communications. It should be evident now how the echo application provided a
232basic conceptual and (partially) functional foundation upon which our chat work
233could be based.
234</p>
235</body>
236</html>
2370
=== removed directory 'Nevow/doc/howto/chattutorial/part01/listings'
=== removed directory 'Nevow/doc/howto/chattutorial/part01/listings/chatthing'
=== removed file 'Nevow/doc/howto/chattutorial/part01/listings/chatthing/__init__.py'
--- Nevow/doc/howto/chattutorial/part01/listings/chatthing/__init__.py 2008-09-03 20:03:47 +0000
+++ Nevow/doc/howto/chattutorial/part01/listings/chatthing/__init__.py 1970-01-01 00:00:00 +0000
@@ -1,1 +0,0 @@
1
20
=== removed file 'Nevow/doc/howto/chattutorial/part01/listings/chatthing/chatterbox.py'
--- Nevow/doc/howto/chattutorial/part01/listings/chatthing/chatterbox.py 2008-09-03 20:03:47 +0000
+++ Nevow/doc/howto/chattutorial/part01/listings/chatthing/chatterbox.py 1970-01-01 00:00:00 +0000
@@ -1,48 +0,0 @@
1from twisted.python.util import sibpath
2from nevow.loaders import xmlfile
3from nevow.athena import LiveElement, expose
4
5class ChatRoom(object):
6
7 def __init__(self):
8 self.chatters = []
9
10 def wall(self, message):
11 for chatter in self.chatters:
12 chatter.wall(message)
13
14 def tellEverybody(self, who, what):
15 for chatter in self.chatters:
16 chatter.hear(who.username, what)
17
18 def makeChatter(self):
19 elem = ChatterElement(self)
20 self.chatters.append(elem)
21 return elem
22
23# element to be run with twistd
24chat = ChatRoom().makeChatter
25
26class ChatterElement(LiveElement):
27
28 docFactory = xmlfile(sibpath(__file__, 'template.html'))
29 jsClass = u'ChatThing.ChatterWidget'
30
31 def __init__(self, room):
32 self.room = room
33
34 def setUsername(self, username):
35 self.username = username
36 message = ' * user '+username+' has joined the room'
37 self.room.wall(message)
38 setUsername = expose(setUsername)
39
40 def say(self, message):
41 self.room.tellEverybody(self, message)
42 say = expose(say)
43
44 def wall(self, message):
45 self.callRemote('displayMessage', message)
46
47 def hear(self, username, what):
48 self.callRemote('displayUserMessage', username, what)
490
=== removed directory 'Nevow/doc/howto/chattutorial/part01/listings/chatthing/js'
=== removed file 'Nevow/doc/howto/chattutorial/part01/listings/chatthing/js/ChatThing.js'
--- Nevow/doc/howto/chattutorial/part01/listings/chatthing/js/ChatThing.js 2009-01-21 22:58:03 +0000
+++ Nevow/doc/howto/chattutorial/part01/listings/chatthing/js/ChatThing.js 1970-01-01 00:00:00 +0000
@@ -1,42 +0,0 @@
1// import Nevow.Athena
2
3Nevow.Athena.Widget.subclass(ChatThing, 'ChatterWidget').methods(
4 function __init__(self, node) {
5 ChatThing.ChatterWidget.upcall(self, "__init__", node);
6 self.chooseBox = self.nodeByAttribute('name', 'chooseBox');
7 self.scrollArea = self.nodeByAttribute('name', 'scrollArea');
8 self.sendLine = self.nodeByAttribute('name', 'sendLine');
9 self.usernameField = self.nodeByAttribute('name', 'username');
10 self.userMessage = self.nodeByAttribute('name', 'userMessage');
11 self.loggedInAs = self.nodeByAttribute('name', 'loggedInAs');
12 },
13
14 function doSetUsername(self) {
15 var username = self.usernameField.value;
16 self.callRemote("setUsername", username).addCallback(
17 function (result) {
18 self.chooseBox.style.display = "none";
19 self.sendLine.style.display = "block";
20 self.loggedInAs.appendChild(document.createTextNode(username));
21 self.loggedInAs.style.display = "block";
22 });
23 return false;
24 },
25
26 function doSay(self) {
27 self.callRemote("say", self.userMessage.value);
28 self.nodeByAttribute('name', 'userMessage').value = "";
29 return false;
30 },
31
32 function displayMessage(self, message) {
33 var newNode = document.createElement('div');
34 newNode.appendChild(document.createTextNode(message));
35 self.scrollArea.appendChild(newNode);
36 document.body.scrollTop = document.body.scrollHeight;
37 },
38
39 function displayUserMessage(self, avatarName, text) {
40 var msg = avatarName+': '+text;
41 self.displayMessage(msg);
42 });
430
=== removed file 'Nevow/doc/howto/chattutorial/part01/listings/chatthing/template.html'
--- Nevow/doc/howto/chattutorial/part01/listings/chatthing/template.html 2008-09-03 20:03:47 +0000
+++ Nevow/doc/howto/chattutorial/part01/listings/chatthing/template.html 1970-01-01 00:00:00 +0000
@@ -1,20 +0,0 @@
1<div xmlns:nevow="http://nevow.com/ns/nevow/0.1"
2 xmlns:athena="http://divmod.org/ns/athena/0.7"
3 nevow:render="liveElement">
4 <h2>Chatter Element</h2>
5 <form name="chatBox">
6 <athena:handler event="onsubmit" handler="doSay" />
7 <div name="scrollArea"
8 style="border: 1px solid gray; padding: 5; margin: 5">
9 </div>
10 <div name="sendLine" style="display: none">
11 <input name="userMessage" /><input type="submit" value="Send" />
12 </div>
13 </form>
14 <form name="chooseBox">
15 <athena:handler event="onsubmit" handler="doSetUsername" />
16 Choose your username: <input name="username" />
17 <input type="submit" name="GO" value="Enter"/>
18 </form>
19 <div name="loggedInAs" style="display:none"><span>Logged in as </span></div>
20</div>
210
=== removed directory 'Nevow/doc/howto/chattutorial/part01/listings/nevow'
=== removed directory 'Nevow/doc/howto/chattutorial/part01/listings/nevow/plugins'
=== removed file 'Nevow/doc/howto/chattutorial/part01/listings/nevow/plugins/chatthing_package.py'
--- Nevow/doc/howto/chattutorial/part01/listings/nevow/plugins/chatthing_package.py 2008-09-03 20:03:47 +0000
+++ Nevow/doc/howto/chattutorial/part01/listings/nevow/plugins/chatthing_package.py 1970-01-01 00:00:00 +0000
@@ -1,8 +0,0 @@
1
2from twisted.python import util
3
4from nevow import athena
5
6import chatthing
7
8chatthingPkg = athena.AutoJSPackage(util.sibpath(chatthing.__file__, 'js'))
90
=== removed file 'Nevow/doc/howto/deployment.xhtml'
--- Nevow/doc/howto/deployment.xhtml 2008-08-26 13:45:59 +0000
+++ Nevow/doc/howto/deployment.xhtml 1970-01-01 00:00:00 +0000
@@ -1,300 +0,0 @@
1<?xml version="1.0"?>
2<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
3 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
4
5<html xmlns="http://www.w3.org/1999/xhtml">
6 <head>
7 <title>
8 Deployment
9 </title>
10 </head>
11 <body>
12 <h1>Deployment</h1>
13
14 <p>
15 Nevow includes two major phases for deciding what HTML to render. <a
16 href="traversal.xhtml">Object Traversal</a> is the procedure by which a
17 URL is mapped to a Python object which will perform the HTML
18 generation. <a href="glossary.xhtml">Page Rendering</a> is the process by
19 which data objects are combined with an HTML template to produce the
20 final output.
21 </p>
22
23 <p>
24 Before any of this can take place, however, we must have an environment
25 in which our Python code can run in response to an HTTP request, and HTML
26 can be returned to the browser for rendering. This is called the
27 <a href="glossary.xhtml">Deployment Environment</a>.
28 </p>
29
30 <p>
31 There are various deployment options for Nevow page code:
32 </p>
33
34 <ul>
35 <li>
36 CGI: Simple deployment in almost any HTTP server
37 </li>
38 <li>
39 WSGI: A more complete and flexible way for deploying on many HTTP
40 servers
41 </li>
42 <li>
43 Twisted.Web: A standalone application server process which includes a
44 built-in HTTP server
45 </li>
46 <li>
47 Zomne: A small CGI which hands off HTTP requests to a long-running
48 application server process, similar to FastCGI or SCGI
49 </li>
50 </ul>
51
52 <h2>CGI</h2>
53
54 <p>
55 You can deploy Nevow on any webserver which uses the Common Gateway
56 Interface. Using this method, your code is responsible for properly
57 formatting and outputting the HTTP response headers, and Nevow is used
58 only to generate the HTML body of your page. Here is the simplest
59 possible CGI:
60 </p>
61
62 <pre class="python">
63#!/usr/bin/env python
64
65print "Content-type: text/plain\r\n\r\n",
66
67from nevow import rend, loaders
68
69class HelloWorld(rend.Page):
70 docFactory = loaders.stan("Hello, world!")
71
72print HelloWorld().renderSynchronously()
73 </pre>
74
75 <p>
76 With this simple CGI you can use the Nevow template loaders and standard
77 nevow template interpolation techniques in your CGIs. However, you do not
78 get any <a href="traversal.xhtml">Object Traversal</a> features, and you
79 have to generate HTTP headers yourself. WSGI is a slightly higher-level
80 deployment option which does not suffer these problems.
81 </p>
82
83 <h2>WSGI</h2>
84
85 <p>
86 WSGI is a python interface for plugging web applications into various
87 HTTP server architectures. It is described in <a
88 href="http://www.python.org/peps/pep-0333.html">PEP 333</a>, the Python
89 Web Services Gateway Interface Python Enhancement Proposal. Nevow
90 includes the <code class="API">nevow.wsgi</code> module, which includes a
91 <code>createWSGIApplication</code> function which takes a Page and
92 returns a standard WSGI application callable. With the help of the
93 <code>run_with_cgi</code> example gateway from the PEP (which I will omit
94 here), our CGI example becomes shorter:
95 </p>
96
97 <pre class="python">
98#!/usr/bin/env python
99
100from nevow import rend, loaders, wsgi
101
102class HelloWorld(rend.Page):
103 docFactory = loaders.stan("Hello, world!")
104
105run_with_cgi(wsgi.createWSGIApplication(HelloWorld()))
106 </pre>
107
108 <p>
109 Of course, you can use any available WSGI gateway to publish your
110 application object, such as one of the gateways which comes with the <a
111 href="http://peak.telecommunity.com/">PEAK</a> toolkit. For example, here
112 is a simple python module which creates a WSGI application which we will
113 then deploy with PEAK's SimpleHTTPServer gateway::
114 </p>
115
116 <pre class="python">
117## helloworld.py
118
119from nevow import rend, loaders, wsgi
120
121class HelloWorld(rend.Page):
122 docFactory = loaders.stan("Hello, world!")
123
124application = wsgi.createWSGIApplication(HelloWorld())
125 </pre>
126
127 <p>
128 Save this file as "helloworld.py" somewhere on your PYTHONPATH and then
129 run the following command:
130 </p>
131
132 <pre>peak launch WSGI import:helloworld.application</pre>
133
134 <p>
135 This will bring up a SimpleHTTPServer running your Nevow code and launch
136 a web browser to view the output. (TODO: I couldn't get this working
137 immediately but I will seek assistance with PEAK and update the
138 instructions once I do.)
139 </p>
140
141 <h2>Twisted.Web</h2>
142
143 <p>
144 A convenient and powerful way to deploy Nevow applications is inside a
145 process running the twisted.web HTTP server. With Python, Twisted, and
146 Nevow installed, you have all you need to run a Web Application, with no
147 other dependencies or external HTTP servers such as Apache
148 required. Running your Nevow applications under twisted.web also gives
149 you access to some of the more advanced "Live" features of Nevow, such as
150 <code>nevow.livepage</code> and <code>nevow.canvas</code>. Currently,
151 these modules require more control over the HTTP socket than CGI or WSGI
152 can provide. (This may change in the future.)
153 </p>
154
155 <p>
156 Deploying a Nevow application under twisted.web requires a little more
157 boilerplate, but can be considerably easier to set up than other
158 deployment options because there are no external dependencies. Note that
159 normally you should declare your Page classes in modules external to the
160 twisted configuration file, but everything is included in one file here
161 for brevity. Here is the minimal configuration file required to use
162 Nevow with twisted.web:
163 </p>
164
165 <pre class="python">
166from nevow import rend, loaders, appserver
167
168class HelloWorld(rend.Page):
169 docFactory = loaders.stan("Hello, world!")
170
171from twisted.application import service, internet
172application = service.Application("hello-world")
173internet.TCPServer(8080, appserver.NevowSite(HelloWorld())).setServiceParent(application)
174 </pre>
175
176 <p>
177 Save this file as "helloworld.tac" and start the server using the
178 command:
179 </p>
180
181 <pre>twistd -noy helloworld.tac</pre>
182
183 <p>
184 Then visit your twisted.web server by viewing the url
185 "http://localhost:8080/" in your browser. See the twistd man page for
186 more information about what twistd is capable of, including daemonizing
187 the HTTP server.
188 </p>
189
190 <h2>Zomne</h2>
191
192 <p>
193 <em>Warning</em> Zomne is experimental. It may blow up your computer and
194 require your first born son as a sacrifice. Zomne also only works in
195 UNIX-like environments where unix domain sockets are available, and may
196 not work on windows.
197 </p>
198
199 <p>
200 Zomne, or "Zombie Nevow", is a CGI written in C which can start up a
201 long-running Application Server process if one is not already running. It
202 then uses a simple custom protocol to transmit information about the HTTP
203 request from the CGI process to the application server process.
204 </p>
205
206 <p>
207 Zomne combines the ease of deployment of the CGI environment with the
208 speed and flexibility of the twisted.web long-running application server
209 process model.
210 </p>
211
212 <p>
213 To use Zomne, you must first compile the CGI. cd into the directory
214 created when unpacking the Nevow tarball, and compile the CGI:
215 </p>
216
217 <pre>% gcc zomne.c</pre>
218
219 <p>
220 Move it into your cgi-bin:
221 </p>
222
223 <pre>% mv a.out /Library/WebServer/CGI-Executables/nevow.cgi</pre>
224
225 <p>
226 Create a file which tells the cgi where to look for the application:
227 </p>
228
229 <pre>
230% cat &gt; /Library/WebServer/CGI-Executables/.nevow.cgi.dir
231/Users/dp/zomne-test
232^D</pre>
233
234 <p>
235 The CGI name can be anything, as long as there is a file with a prepended
236 "." and a postfixed ".dir" in the same directory which contains the full
237 path of a zomne application directory. Next, create the application
238 directory:
239 </p>
240
241 <pre>mkdir /Users/dp/zomne-test</pre>
242
243 <p>
244 Finally, create the zomne.tac file which the zomne.cgi will execute to
245 start the long-running application server process:
246 </p>
247
248 <pre class="python">
249from nevow import rend, loaders, zomnesrv
250
251class HelloWorld(rend.Page):
252 docFactory = loaders.stan("Hello, world!")
253
254from twisted.application import service, internet
255application = service.Application('nevow-zomne-test')
256internet.UNIXServer('zomne.socket', zomnesrv.ZomneFactory(HelloWorld())).setServiceParent(application)
257 </pre>
258
259 <p>
260 Now, visiting the nevow.cgi URL through the web should render the Hello
261 World page, after a pause while the server is starting up. Subsequent
262 requests should be very fast, because the application server is already
263 running, and the CGI merely has to forward the request to it.
264 </p>
265
266 <p>
267 Another useful capability of the zomne CGI process is the ability to
268 control environment variables the CGI will use. Create a directory named
269 "zomne_environ" in the application directory, and fill it with text files
270 whose name will be the environment key and whose contents will be the
271 environment value:
272 </p>
273
274 <pre>
275% cd zomne-test
276% mkdir zomne-environ
277% cd zomne-environ
278% cat &gt; PYTHONPATH
279/Users/dp/Projects/Nevow:/Users/dp/Projects/helloworld
280^D</pre>
281
282 <h2>Conclusion</h2>
283
284 <p>
285 Nevow may be deployed in a number of environments, from the most
286 restrictive to the most permissive. Writing a CGI can be an easy way to
287 try out the Nevow templating mechanism, but can be slow. A long-running
288 application server process can be a good way to get good performance as
289 well as additional features such as in-memory server-side sessions,
290 advanced automatic form handling with formless, and live page updating
291 features such as nevow.livepage and nevow.canvas.
292 </p>
293
294 <p>
295 Which deployment option you choose will depend on the amount of control
296 you have over your deployment environment, and what advanced features
297 your application will require.
298 </p>
299 </body>
300</html>
3010
=== removed file 'Nevow/doc/howto/gettingstarted.xhtml'
--- Nevow/doc/howto/gettingstarted.xhtml 2008-08-26 13:45:59 +0000
+++ Nevow/doc/howto/gettingstarted.xhtml 1970-01-01 00:00:00 +0000
@@ -1,110 +0,0 @@
1<?xml version="1.0"?>
2<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
3 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
4
5<html xmlns="http://www.w3.org/1999/xhtml">
6 <head>
7 <title>
8 Getting Started
9 </title>
10 </head>
11 <body>
12 <h1>Getting Started</h1>
13
14 <p>
15 Warning: This document has only just been started. It's not going to get
16 you very far right now.
17 </p>
18
19 <p>
20 Nevow is a reasonably large library and can be quite daunting at
21 first. This document's aim is to guide the first time user in building a
22 Nevow application.
23 </p>
24
25 <h2>Our First Application</h2>
26
27 <p>
28 Let's dive straight in, here's the code for our first (very, very simple)
29 application. Create the following module, helloworld.py:
30 </p>
31
32 <a href="listings/gettingstarted/helloworld.py" class="py-listing">
33 helloworld.py
34 </a>
35
36 <p>
37 It looks quite simple but let's walk through it anyway.
38 </p>
39
40 <p>
41 First, we import two Nevow modules. <code
42 class="API">nevow.loaders</code> contains template loaders of which the
43 two most useful are <code class="API" base="nevow.loaders">xmlfile</code>
44 and <code class="API" base="nevow.loaders">stan</code>.
45 <code>xmlfile</code> can load any well-formed XML (i.e. XHTML) file;
46 <code>stan</code> loads a stan tree (more on these later). The other
47 module, <code class="API">nevow.rend</code>, contains all Nevow's
48 standard renders, many of which we'll meet in this document.
49 </p>
50
51 <p>
52 We then define the <code>HelloWorld</code> class that subclasses <code
53 class="API" base="nevow">rend.Page</code>, Nevow's main resource
54 class. <code>HelloWorld</code> has two class
55 attributes. <code>addSlash</code> tells <code>rend.Page</code> to
56 redirect to a version of the request URL that ends in a <code>/</code> if
57 necessary. You generally want to set this to <code>True</code> for the
58 root resource. <code>docFactory</code> tells the page instance where to
59 get the template from. In this case we're providing a loader that parses
60 an HTML file (not shown) from disk.
61 </p>
62
63 <p>
64 Hmm, ok I hear you say but how do I see it. Well, Twisted provides a good
65 web server which we can use. Twisted also includes a clever little
66 application for starting Twisted applications. Here's the helloworld.tac
67 file, a Twisted Application Configuration:
68 </p>
69
70 <a href="listings/gettingstarted/helloworld.tac" class="py-listing">
71 helloworld.tac
72 </a>
73
74 <p>
75 Give it a go, run the following and connect to <a
76 href="http://localhost:8080/">http://localhost:8080/</a> to see your
77 application:
78 </p>
79
80 <pre>twistd -ny helloworld.tac</pre>
81
82 <p>
83 You'll probably notice that you get log output on the console. This is
84 just one of the good things that twistd does. It can also daemonize the
85 application, shed privileges if run as root, etc.
86 </p>
87
88 <p>
89 TAC files are covered in more detail in the Twisted documentation but
90 let's quickly explain what all this does anyway.
91 </p>
92
93 <p>
94 When <code class="shell">twistd</code> starts up it loads the
95 <code>.tac</code> file (it's just Python) and looks for the attribute
96 called <code>application</code>. When <code class="shell">twistd</code>
97 is all ready to go it starts the <code>application</code>.
98 </p>
99
100 <p>
101 The application is not much use unless it actually does something so the
102 next thing we do is create a <code class="API"
103 base="nevow.appserver">NevowSite</code> instance, <code>site</code>, and
104 pass it a root resource, a <code>HelloWorld</code> instance. Finally, we
105 create a TCP server that makes the site available on port 8080 and bind
106 the server to the application to ensure the server is started when the
107 application is started.
108 </p>
109 </body>
110</html>
1110
=== removed file 'Nevow/doc/howto/glossary.xhtml'
--- Nevow/doc/howto/glossary.xhtml 2010-04-06 11:05:45 +0000
+++ Nevow/doc/howto/glossary.xhtml 1970-01-01 00:00:00 +0000
@@ -1,82 +0,0 @@
1<?xml version="1.0"?>
2<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
3 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
4
5<html xmlns="http://www.w3.org/1999/xhtml">
6 <head>
7 <title>
8 Glossary
9 </title>
10 </head>
11 <body>
12 <h1>Glossary</h1>
13
14 <h2>Object Traversal</h2>
15
16 <p>
17 The process by which a Python object is located to render HTML for a
18 given HTTP URL. For example, given the URL http://example.com/foo/bar,
19 Object Traversal will begin at the "Root Resource" object by asking it
20 for an object which is capable of rendering the page at ('foo',
21 'bar'). The "Root Resource" returns an object and a list of unhandled
22 path segments, and the traversal continues across this new Resource
23 object until all path segments have been consumed.
24 </p>
25
26 <h2>Page Rendering</h2>
27
28 <p>
29 The process by which a Python object, usually a rend.Page subclass, turns
30 itself into HTML. Page Rendering involves locating some page data,
31 loading a template document, and applying the template to the data, in
32 the process generating HTML.
33 </p>
34
35 <h2>Deployment Environment</h2>
36
37 <p>
38 The environment in which a Nevow application is deployed. Generally
39 involves an HTTP server which is configured to route certain (or all)
40 HTTP requests through the Nevow Object Traversal and Page Rendering
41 process. Deployment environments include CGI, WSGI, and twisted.web.
42 </p>
43
44 <h2>DOM</h2>
45
46 <p>
47 Document Object Model. A tree of objects which represent the structure of
48 an XHTML document in memory. Nevow uses a nonstandard DOM named "stan",
49 which is made up of simple Python lists, dicts, strings, and
50 nevow.stan.Tag instances.
51 </p>
52
53 <h2>Flattener</h2>
54
55 <p>
56 A Python function which knows how to translate from a rich type to a
57 string containing HTML. For example, the integer flattener calls str() on
58 the integer. The string flattener escapes characters which are unsafe in
59 HTML, such as &lt;, &gt;, and &amp;.
60 </p>
61
62 <h2>Tag</h2>
63
64 <p>
65 A class, defined at nevow.stan.Tag, which holds information about a
66 single HTML tag in a DOM. Tag instances have three attributes: tagName,
67 attributes, and children. tagName is a string indicating the tag
68 name. attributes is a dict indicating the HTML attributes of that
69 node. children is a list indicating the child nodes of that node.
70 </p>
71
72 <h2>Tag Specials</h2>
73
74 <p>
75 A Tag attribute which is "special" to nevow. Tag specials include data,
76 render, pattern, slot, and macro. Tag Specials will never be output as
77 HTML attributes of tags, but will be used by the internal Nevow rendering
78 process to influence how the Tag is rendered.
79 </p>
80
81 </body>
82</html>
830
=== removed file 'Nevow/doc/howto/index.xhtml'
--- Nevow/doc/howto/index.xhtml 2008-09-20 01:06:47 +0000
+++ Nevow/doc/howto/index.xhtml 1970-01-01 00:00:00 +0000
@@ -1,49 +0,0 @@
1<?xml version="1.0"?>
2<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
3 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
4
5<html xmlns="http://www.w3.org/1999/xhtml">
6 <head>
7 <title>
8 Manual
9 </title>
10 </head>
11 <body>
12 <h1>
13 Manual
14 </h1>
15 <ul class="toc">
16 <li>
17 <a href="intro.xhtml">Introduction</a>
18 </li>
19 <li>
20 <a href="gettingstarted.xhtml">Getting Started</a>
21 <p>A basic introduction to rendering a web page in Nevow.</p>
22 </li>
23 <li>
24 <a href="traversal.xhtml">Object Traversal</a>
25 <p>Getting from an URL to a Python page object you want to render.</p>
26 </li>
27 <li>
28 <a href="publishing.xhtml">Object Publishing</a>
29 <p>Exposing Python objects as parts of a web page in Nevow.</p>
30 </li>
31 <li>
32 <a href="xmltemplates.xhtml">XML Templates</a>
33 <p>Using standard XHTML as a template for Nevow.</p>
34 </li>
35 <li>
36 <a href="deployment.xhtml">Deployment</a>
37 <p>How to get your Nevow application running on different types of
38 servers.</p>
39 </li>
40 <li>
41 <a href="chattutorial/index.xhtml">Nevow Athena</a>
42 <p>Two-way communication with JavaScript in a web browser.</p>
43 </li>
44 <li>
45 <a href="glossary.xhtml">Glossary</a>
46 </li>
47 </ul>
48 </body>
49</html>
500
=== removed file 'Nevow/doc/howto/intro.xhtml'
--- Nevow/doc/howto/intro.xhtml 2008-08-26 13:45:59 +0000
+++ Nevow/doc/howto/intro.xhtml 1970-01-01 00:00:00 +0000
@@ -1,294 +0,0 @@
1<?xml version="1.0"?>
2<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
3 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
4
5<html xmlns="http://www.w3.org/1999/xhtml">
6 <head>
7 <title>
8 A Web Application Construction Kit
9 </title>
10 </head>
11 <body>
12 <h1>A Web Application Construction Kit</h1>
13
14 <h2>Summary</h2>
15
16 <p>
17 Nevow is a next-generation web application templating system, based on
18 the ideas developed in the Twisted Woven package. Its main focus is on
19 separating the HTML template from both the business logic and the display
20 logic, while allowing the programmer to write pure Python code as much as
21 possible. It separates your code into 'data' and 'render' functions, a
22 simplified implementation of traditional MVC. It has various parts which
23 can be used individually or as a whole, integrated web solution:
24 </p>
25
26 <ul>
27 <li>
28 XHTML templates: contain no programming logic, only nodes tagged with
29 nevow attributes
30 </li>
31 <li>
32 data/render methods: simplified MVC
33 </li>
34 <li>
35 stan: An s-expression-like syntax for expressing xml in pure python
36 </li>
37 <li>
38 formless: For describing the types of objects which may be passed to
39 methods of your classes, validating and coercing string input from
40 either web or command-line sources, and calling your methods
41 automatically once validation passes
42 </li>
43 <li>
44 formless.webform: For rendering web forms based on formless type
45 descriptions, accepting form posts and passing them to formless
46 validators, and rendering error forms in the event validation fails
47 </li>
48 <li>
49 livepage: Cross-browser JavaScript glue for sending client side events
50 to the server and server side events to the client after the page has
51 loaded, without causing the entire page to refresh
52 </li>
53 </ul>
54
55 <h2>Disk based templates</h2>
56
57 <p>
58 Nevow includes the ability to load templates off disk. These templates
59 may have processing directives which cause the execution of python
60 methods at render time. The attribute technique was inspired by the
61 attributes used by ZPT. However, no actual code may be embedded in the
62 HTML template:
63 </p>
64
65 <pre>
66&lt;html xmlns:nevow="http://nevow.com/ns/nevow/0.1"&gt;
67 &lt;head&gt;
68 &lt;title&gt;Greetings!&lt;/title&gt;
69 &lt;/head&gt;
70 &lt;body&gt;
71 &lt;h1 style="font-size: large"&gt;Now I will greet you:&lt;/h1&gt;
72 &lt;span nevow:render="greet" /&gt;
73 &lt;/body&gt;
74&lt;/html&gt;</pre>
75
76 <p>
77 This template can then be loaded and rendered like so:
78 </p>
79
80 <pre class="python">
81class Greeter(rend.Page):
82 docFactory = loaders.xmlfile("Greeting.html")
83
84 def render_greet(self, context, data):
85 return random.choice(["Hello", "Greetings", "Hi"]), " ", data
86
87Greeter("My name is").renderString()
88 </pre>
89
90 <h2>data/render methods</h2>
91
92 <p>
93 To allow clean isolation between code which fetches data from a data
94 source and code which renders the data into HTML, nevow allows you to
95 write both 'data' methods and 'render' methods. These concepts are
96 inspired by MVC, but simpler, since the framework can handle most of the
97 controller aspect. An example:
98 </p>
99
100 <pre>
101&lt;html xmlns:nevow="http://nevow.com/ns/nevow/0.1"&gt;
102 &lt;body&gt;
103 &lt;span nevow:data="name" nevow:render="colorful" /&gt;
104 &lt;span nevow:data="fun" nevow:render="colorful" /&gt;
105 &lt;/body&gt;
106&lt;/html&gt;</pre>
107
108 <p>
109 This template can be loaded and rendered using a class such as this:
110 </p>
111
112 <pre class="python">
113class Colorful(rend.Page):
114 docFactory = loaders.xmlfile("Colorful.html")
115
116 def render_colorful(self, context, data):
117 color = random.choice(['red', 'green', 'blue'])
118 return context.tag(style="color: %s" % color)
119
120 def data_name(self, context, data):
121 return "Your name here"
122
123 def data_fun(self, context, data):
124 return "Are we having fun yet?"
125 </pre>
126
127 <h2>Stan</h2>
128
129 <p>
130 One of the most powerful things about nevow is stan, an s-expression-like
131 syntax for producing XML fragments in pure Python syntax. Stan is not
132 required for using nevow, but it is both a simple and powerful way to
133 both lay out one's XHTML templates and express one's display logic. A
134 brief example will illustrate its utility:
135 </p>
136
137 <pre class="python">
138import random
139from nevow import rend, tags
140
141class Greeter(rend.Page):
142 def greet(self, context, data):
143 return random.choice(["Hello", "Greetings", "Hi"]), " ", data
144
145 docFactory = loaders.stan(
146 tags.html[
147 tags.head[ tags.title[ "Greetings!" ]],
148 tags.body[
149 tags.h1(style="font-size: large")[ "Now I will greet you:" ],
150 greet
151 ]
152 ])
153 </pre>
154
155 <p>
156 When the Greeter class is constructed, it is passed a Python object which
157 will be used as that page's data:
158 </p>
159
160 <pre class="python">
161Greeter("Your name here").renderString()
162 </pre>
163
164 <h2>Formless</h2>
165
166 <p>
167 Python is dynamically typed, which means it has no built-in controls for
168 enforcing the types of objects which are passed to one's methods. This is
169 great for programmers, but not necessarily great if you are going to be
170 passing user-entered input to those methods. Formless is a simple way to
171 describe the types of objects that can be passed to one's methods, as
172 well as coerce from string input to those types. Other code can then
173 accept user input from a command line or from a web form, validate the
174 input against the types described using formless, and call the method
175 once validation has passed. A simple example:
176 </p>
177
178 <pre class="python">
179from zope.interface import implements
180from formless.annotate import TypedInterface, Integer, String
181
182class ISimpleMethod(TypedInterface):
183 def simple(self,
184 name=String(description="Your name."),
185 age=Integer(description="Your age.")):
186 """
187 Simple
188
189 Please enter your name and age.
190 """
191
192class Implementation(object):
193 implements(ISimpleMethod)
194
195 def simple(self, name, age):
196 print "Hello, %s, who is %s" % (name, age)
197 </pre>
198
199 <h2>Webform</h2>
200
201 <p>
202 Webform is a nevow module which will automatically render web forms and
203 accept form posts based on types described using the classes in
204 formless. Used in conjunction with the twisted.web HTTP server, the
205 process is almost automatic:
206 </p>
207
208 <pre class="python">
209from nevow import rend, tags
210from formless import webform
211
212class WebForm(rend.Page):
213 document = rend.stan(
214 tags.html[
215 tags.body[
216 h1["Here is the form:"],
217 webform.renderForms('original')
218 ]
219])
220
221resource = WebForm(Implementation())
222 </pre>
223
224 <p>
225 Exposing this resource instance to the web using twisted.web and visiting
226 it will cause a form with two input boxes to be rendered. Posting the
227 form will cause form validation to occur. Upon error, the user will be
228 returned to the original page, with the form annotated with error
229 messages. Upon success, the "simple" method of the Implementation
230 instance will be called and passed a string and an integer.
231 </p>
232
233 <h2>LivePage</h2>
234
235 <p>
236 LivePage was a Woven technology which allowed programmers to receive
237 server-side notification of client-side JavaScript events, and to send
238 JavaScript to the client in response to a server-side event. New for
239 Nevow 0.3, LivePage has been updated to support Mozilla, Firefox, IE6
240 Win, and Safari. Using LivePage is very easy:
241 </p>
242
243 <pre class="python">
244from nevow.liveevil import handler
245
246def greeter(client, nodeName):
247 client.alert("Greetings. You clicked the %s node." % nodeName)
248
249# Any string arguments after the event handler function will be evaluated
250# as JavaScript in the context of the web browser and results passed to the
251# Python event handler
252handler = handler(greeter, 'node.name')
253
254class Live(rend.Page):
255 docFactory = loaders.stan(
256 tags.html[
257 tags.body[
258 ol[
259 li(onclick=handler, name="one")["One"]
260 li(onclick=handler, name="two")["Two"]
261 li(onclick=handler, name="three")["Three"]
262 ]
263 ]
264 ])
265 </pre>
266
267 <h2>More Information</h2>
268
269 <p>
270 The <a href="http://divmod.org/trac/wiki/DivmodNevow">Nevow website</a>
271 has more information. Starting with 0.3, it contains a simple WSGI
272 implementation and can also be used to render CGIs. However, the
273 recommended mode of operation is using the <a
274 href="http://twistedmatrix.com/trac/wiki/TwistedWeb">Twisted web</a>
275 server. Nevow is an active project, and many new bugfixes and features
276 are committed to the Nevow SVN repository. Information about Nevow
277 commits is available by subscribing to the <a
278 href="http://divmod.net/users/mailman.twistd/listinfo/divmod-commits">
279 Divmod commits</a> mailing list. The Nevow SVN repository can be checked
280 out using:
281 </p>
282
283 <pre>svn co svn://divmod.org/svn/Nevow/trunk Nevow</pre>
284
285 <p>
286 Discussion of Nevow occurs on the <a
287 href="http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-web">
288 twisted.web mailing list</a>. The Nevow developers are also often
289 available for real-time help on the <a
290 href="irc://irc.freenode.net/#twisted.web">#twisted.web channel</a> on
291 irc.freenode.net.
292 </p>
293 </body>
294</html>
2950
=== removed directory 'Nevow/doc/howto/listings'
=== removed directory 'Nevow/doc/howto/listings/gettingstarted'
=== removed file 'Nevow/doc/howto/listings/gettingstarted/helloworld.py'
--- Nevow/doc/howto/listings/gettingstarted/helloworld.py 2008-08-26 13:45:59 +0000
+++ Nevow/doc/howto/listings/gettingstarted/helloworld.py 1970-01-01 00:00:00 +0000
@@ -1,6 +0,0 @@
1from nevow import loaders, rend
2
3class HelloWorld(rend.Page):
4 addSlash = True
5 docFactory = loaders.xmlfile('helloworld.html')
6
70
=== removed file 'Nevow/doc/howto/listings/gettingstarted/helloworld.tac'
--- Nevow/doc/howto/listings/gettingstarted/helloworld.tac 2008-08-26 13:45:59 +0000
+++ Nevow/doc/howto/listings/gettingstarted/helloworld.tac 1970-01-01 00:00:00 +0000
@@ -1,10 +0,0 @@
1from twisted.application import internet
2from twisted.application import service
3from nevow import appserver
4import helloworld
5
6application = service.Application('helloworld')
7site = appserver.NevowSite(helloworld.HelloWorld())
8webServer = internet.TCPServer(8080, site)
9webServer.setServiceParent(application)
10
110
=== removed file 'Nevow/doc/howto/publishing.xhtml'
--- Nevow/doc/howto/publishing.xhtml 2008-08-26 13:45:59 +0000
+++ Nevow/doc/howto/publishing.xhtml 1970-01-01 00:00:00 +0000
@@ -1,658 +0,0 @@
1<?xml version="1.0"?>
2<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
3 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
4
5<html xmlns="http://www.w3.org/1999/xhtml">
6 <head>
7 <title>
8 Object Publishing
9 </title>
10 </head>
11 <body>
12 <h1>
13 Object Publishing
14 </h1>
15
16 <p>
17 In <a href="traversal.xhtml">Object Traversal</a>, we learned about the
18 <code class="API">nevow.inevow.IResource.renderHTTP</code> method, which
19 is the most basic way to send HTML to a browser when using
20 Nevow. However, it is not very convenient (or clean) to generate HTML
21 tags by concatenating strings in Python code. In the <a
22 href="deployment.xhtml">Deployment</a> documentation, we saw that it was
23 possible to render a <em>Hello World</em> page using a <code class="API">
24 nevow.rend.Page</code> subclass and providing a <code>docFactory</code>:
25 </p>
26
27 <pre class="python-interpreter">
28&gt;&gt;&gt; from nevow import rend, loaders
29&gt;&gt;&gt; class HelloWorld(rend.Page):
30... docFactory = loaders.stan("Hello, world!")
31...
32&gt;&gt;&gt; HelloWorld().renderSynchronously()
33'Hello, world!'</pre>
34
35 <p>
36 This example does nothing interesting, but the concept of a loader is
37 important in Nevow. The <code>rend.Page.renderHTTP</code> implementation
38 always starts rendering HTML by loading a template from the
39 <code>docFactory</code>.
40 </p>
41
42
43 <h2>The stan DOM</h2>
44
45 <p>
46 Nevow uses a DOM-based approach to rendering HTML. A tree of objects is
47 first constructed in memory by the template loader. This tree is then
48 processed one node at a time, applying functions which transform from
49 various Python types to HTML strings.
50 </p>
51
52 <p>
53 Nevow uses a nonstandard DOM named "stan". Unlike the W3C DOM, stan is
54 made up of simple python lists, strings, and instances of the
55 nevow.stan.Tag class. During the rendering process, "Flattener"
56 functions convert from rich types to HTML strings. For example, we can
57 load a template made up of some nested lists and Python types, render it,
58 and see what happens:
59 </p>
60
61 <pre class="python-interpreter">
62&gt;&gt;&gt; class PythonTypes(rend.Page):
63... docFactory = loaders.stan(["Hello", 1, 1.5, True, ["Goodbye", 3]])
64...
65&gt;&gt;&gt; PythonTypes().renderSynchronously()
66'Hello11.5TrueGoodbye3'</pre>
67
68 <h2>Tag instances</h2>
69
70 <p>
71 So far, we have only rendered simple strings as output. However, the main
72 purpose of Nevow is HTML generation. In the stan DOM, HTML tags are
73 represented by instances of the <code class="API">nevow.stan.Tag</code>
74 class. <code>Tag</code> is a very simple class, whose instances have an
75 <code>attributes</code> dictionary and a <code>children</code> list. The
76 <code>Tag</code> flattener knows how to recursively flatten attributes
77 and children of the tag. To show you how <code>Tag</code>s really work
78 before you layer Nevow's convenience syntax on top, try this horrible
79 example:
80 </p>
81
82 <pre class="python-interpreter">
83&gt;&gt;&gt; from nevow import stan
84&gt;&gt;&gt; h = stan.Tag('html')
85&gt;&gt;&gt; d = stan.Tag('div')
86&gt;&gt;&gt; d.attributes['style'] = 'border: 1px solid black'
87&gt;&gt;&gt; h.children.append(d)
88&gt;&gt;&gt; class Tags(rend.Page):
89... docFactory = loaders.stan(h)
90...
91&gt;&gt;&gt; Tags().renderSynchronously()
92'&lt;html&gt;&lt;div style="border: 1px solid black"&gt;&lt;/div&gt;&lt;/html&gt;'</pre>
93
94 <p>
95 So, we see how it is possible to programatically generate HTML by
96 constructing and nesting stan <code>Tag</code> instances. However, it is
97 far more convenient to use the overloaded operators <code>Tag</code>
98 provides to manipulate them. <code>Tag</code> implements a
99 <code>__call__</code> method which takes any keyword arguments and values
100 and updates the attributes dictionary; it also implements a
101 <code>__getitem__</code> method which takes whatever is between the square
102 brackets and appends them to the children list. A simple example should
103 clarify things:
104 </p>
105
106 <pre class="python-interpreter">
107&gt;&gt;&gt; class Tags2(rend.Page):
108... docFactory = loaders.stan(stan.Tag('html')[stan.Tag('div')(style="border: 1px solid black")])
109...
110&gt;&gt;&gt; Tags2().renderSynchronously()
111'&lt;html&gt;&lt;div style="border: 1px solid black"&gt;&lt;/div&gt;&lt;/html&gt;'</pre>
112
113 <p>
114 This isn't very easy to read, but luckily we can simplify the example
115 even further by using the nevow.tags module, which is full of "Tag
116 prototypes" for every tag type described by the XHTML 1.0 specification:
117 </p>
118
119 <pre class="python-interpreter">
120&gt;&gt;&gt; class Tags3(rend.Page):
121... docFactory = loaders.stan(tags.html[tags.div(style="border: 1px solid black")])
122...
123&gt;&gt;&gt; Tags3().renderSynchronously()
124'&lt;html&gt;&lt;div style="border: 1px solid black"&gt;&lt;/div&gt;&lt;/html&gt;'</pre>
125
126 <p>
127 Using stan syntax is not the only way to construct template DOM for use
128 by the Nevow rendering process. Nevow also includes <code class="API"
129 base="nevow">loaders.xmlfile</code> which implements a simple tag
130 attribute language similar to the Zope Page Templates (ZPT) Tag Attribute
131 Language (TAL). However, experience with the stan DOM should give you
132 insight into how the Nevow rendering process really works. Rendering a
133 template into HTML in Nevow is really nothing more than iterating a tree
134 of objects and recursively applying "Flattener" functions to objects in
135 this tree, until all HTML has been generated.
136 </p>
137
138 <h2>Functions in the DOM</h2>
139
140 <p>
141 So far, all of our examples have generated static HTML pages, which is
142 not terribly interesting when discussing dynamic web applications. Nevow
143 takes a very simple approach to dynamic HTML generation. If you put a
144 Python function reference in the DOM, Nevow will call it when the page is
145 rendered. The return value of the function replaces the function itself
146 in the DOM, and the results are flattened further. This makes it easy to
147 express looping and branching structures in Nevow, because normal Python
148 looping and branching constructs are used to do the job:
149 </p>
150
151 <pre class="python-interpreter">
152&gt;&gt;&gt; def repeat(ctx, data):
153... return [tags.div(style="color: %s" % (color, ))
154... for color in ['red', 'blue', 'green']]
155...
156&gt;&gt;&gt; class Repeat(rend.Page):
157... docFactory = loaders.stan(tags.html[repeat])
158...
159&gt;&gt;&gt; Repeat().renderSynchronously()
160'&lt;html&gt;&lt;div style="color: red"&gt;&lt;/div&gt;&lt;div style="color: blue"&gt;&lt;/div&gt;&lt;div style="color: green"&gt;&lt;/div&gt;&lt;/html&gt;'</pre>
161
162 <p>
163 However, in the example above, the repeat function isn't even necessary,
164 because we could have inlined the list comprehension right where we
165 placed the function reference in the DOM. Things only really become
166 interesting when we begin writing parameterized render functions which
167 cause templates to render differently depending on the input to the web
168 application.
169 </p>
170
171 <p>
172 The required signature of functions which we can place in the DOM is
173 (ctx, data). The "context" object is essentially opaque for now, and we
174 will learn how to extract useful information out of it later. The "data"
175 object is anything we want it to be, and can change during the rendering
176 of the page. By default, the data object is whatever we pass as the first
177 argument to the Page constructor, <em>or</em> the Page instance itself if
178 nothing is passed. Armed with this knowledge, we can create a Page which
179 renders differently depending on the data we pass to the Page
180 constructor:
181 </p>
182
183 <pre class="python">
184class Root(rend.Page):
185 docFactory = loaders.stan(tags.html[
186 tags.h1["Welcome."],
187 tags.a(href="foo")["Foo"],
188 tags.a(href="bar")["Bar"],
189 tags.a(href="baz")["Baz"]])
190
191 def childFactory(self, ctx, name):
192 return Leaf(name)
193
194def greet(ctx, name):
195 return "Hello. You are visiting the ", name, " page."
196
197class Leaf(rend.Page):
198 docFactory = loaders.stan(tags.html[greet])
199 </pre>
200
201 <p>
202 Armed with this knowledge and the information in the <a
203 href="traversal.xhtml">Object Traversal</a> documentation, we now have
204 enough information to create dynamic websites with arbitrary URL
205 hierarchies whose pages render dynamically depending on which URL was
206 used to access them.
207 </p>
208
209 <h2>Accessing query parameters and form post data</h2>
210
211 <p>
212 Before we move on to more advanced rendering techniques, let us first
213 examine how one could further customize the rendering of a Page based on
214 the URL query parameters and form post information provided to us by a
215 browser. Recall that URL parameters are expressed in the form:
216 </p>
217
218 <pre>http://example.com/foo/bar?baz=1&amp;quux=2</pre>
219
220 <p>
221 And form post data can be generated by providing a form to a browser:
222 </p>
223
224 <pre>
225&lt;form action="" method="POST"&gt;
226 &lt;input type="text" name="baz" /&gt;
227 &lt;input type="text" name="quux" /&gt;
228 &lt;input type="submit" /&gt;
229&lt;/form&gt;</pre>
230
231 <p>
232 Accessing this information is such a common procedure that Nevow provides
233 a convenience method on the context to do it. Let's examine a simple page
234 whose output can be influenced by the query parameters in the URL used to
235 access it:
236 </p>
237
238 <pre class="python">
239def showChoice(ctx, data):
240 choice = ctx.arg('choice')
241 if choice is None:
242 return ''
243 return "You chose ", choice, "."
244
245class Custom(rend.Page):
246 docFactory = loaders.stan(tags.html[
247 tags.a(href="?choice=baz")["Baz"],
248 tags.a(href="?choice=quux")["Quux"],
249 tags.p[showChoice]])
250 </pre>
251
252 <p>
253 The procedure is exactly the same for simple form post information:
254 </p>
255
256 <pre class="python">
257def greet(ctx, data):
258 name = ctx.arg('name')
259 if name is None:
260 return ''
261 return "Greetings, ", name, "!"
262
263class Form(rend.Page):
264 docFactory = loaders.stan(tags.html[
265 tags.form(action="", method="POST")[
266 tags.input(name="name"),
267 tags.input(type="submit")],
268 greet])
269</pre>
270
271 <p>
272 Note that <code>ctx.arg</code> returns only the first argument with the
273 given name. For complex cases where multiple arguments and lists of
274 argument values are required, you can access the request argument
275 dictionary directly using the syntax:
276 </p>
277
278 <pre class="python">
279def arguments(ctx, data):
280 args = inevow.IRequest(ctx).args
281 return "Request arguments are: ", str(args)
282 </pre>
283
284 <h2>Generators in the DOM</h2>
285
286 <p>
287 One common operation when building dynamic pages is iterating a list of
288 data and emitting some HTML for each item. Python generators are well
289 suited for expressing this sort of logic, and code which is written as a
290 python generator can perform tests (<code>if</code>) and loops of various
291 kinds (<code>while</code>, <code>for</code>) and emit a row of html
292 whenever it has enough data to do so. Nevow can handle generators in the
293 DOM just as gracefully as it can handle anything else:
294 </p>
295
296 <pre class="python-interpreter">
297&gt;&gt;&gt; from nevow import rend, loaders, tags
298&gt;&gt;&gt; def generate(ctx, items):
299... for item in items:
300... yield tags.div[ item ]
301...
302&gt;&gt;&gt; class List(rend.Page):
303... docFactory = loaders.stan(tags.html[ generate ])
304...
305&gt;&gt;&gt; List(['one', 'two', 'three']).renderSynchronously()
306'&lt;html&gt;&lt;div&gt;one&lt;/div&gt;&lt;div&gt;two&lt;/div&gt;&lt;div&gt;three&lt;/div&gt;&lt;/html&gt;'</pre>
307
308 <p>
309 As you can see, generating HTML inside of functions or generators can be
310 very convenient, and can lead to very rapid application
311 development. However, it is also what I would call a "template
312 abstraction violation", and we will learn how we can keep knowledge of
313 HTML out of our python code when we learn about patterns and slots.
314 </p>
315
316 <h2>Methods in the DOM</h2>
317
318 <p>
319 Up until now, we have been placing our template manipulation logic inside
320 of simple Python functions and generators. However, it is often
321 appropriate to use a method instead of a function. Nevow makes it just as
322 easy to use a method to render HTML:
323 </p>
324
325 <pre class="python">
326class MethodRender(rend.Page):
327 def __init__(self, foo):
328 self.foo = foo
329
330 def render_foo(self, ctx, data):
331 return self.foo
332
333 docFactory = loaders.stan(tags.html[ render_foo ])
334 </pre>
335
336 <p>
337 Using render methods makes it possible to parameterize your Page class
338 with more parameters. With render methods, you can also use the Page
339 instance as a state machine to keep track of the state of the
340 render. While Nevow is designed to allow you to render the same Page
341 instance repeatedly, it can also be convenient to know that a Page
342 instance will only be used one time, and that the Page instance can be
343 used as a scratch pad to manage information about the render.
344 </p>
345
346 <h2>Data specials</h2>
347
348 <p>
349 Previously we saw how passing a parameter to the default Page constructor
350 makes it available as the "data" parameter to all of our render
351 methods. This "data" parameter can change as the page render proceeds,
352 and is a useful way to ensure that render functions are isolated and only
353 act upon the data which is available to them. Render functions which do
354 not pull information from sources other than the "data" parameter are
355 more easily reusable and can be composed into larger parts more easily.
356 </p>
357
358 <p>
359 Deciding which data gets passed as the data parameter is as simple as
360 changing the "Data special" for a Tag. See the <a
361 href="glossary.xhtml">Glossary</a> under "Tag Specials" for more
362 information about specials. Assigning to the data special is as simple as
363 assigning to a tag attribute:
364 </p>
365
366 <pre class="python-interpreter">
367&gt;&gt;&gt; def hello(ctx, name):
368... return "Hello, ", name
369...
370&gt;&gt;&gt; class DataSpecial(rend.Page):
371... docFactory = loaders.stan(tags.html[
372... tags.div(data="foo")[ hello ],
373... tags.div(data="bar")[ hello ]])
374...
375&gt;&gt;&gt; DataSpecial().renderSynchronously()
376'&lt;html&gt;&lt;div&gt;Hello, foo&lt;/div&gt;&lt;div&gt;Hello, bar&lt;/div&gt;&lt;/html&gt;'</pre>
377
378 <p>
379 Data specials may be assigned any python value. Data specials are only in
380 scope during the rendering of the tag they are assigned to, so if the
381 "hello" renderer were placed in the DOM inside the html node directly,
382 "Hello, None" would be output.
383 </p>
384
385 <p>
386 Before data is passed to a render function, Nevow first checks to see if
387 there is an <code class="API">IGettable</code> adapter for it. If there
388 is, it calls <code>IGettable.get()</code>, and passes the result of this
389 as the data parameter instead. Nevow includes an <code>IGettable</code>
390 adapter for python functions, which means you can set a Tag data special
391 to a function reference and Nevow will call it to obtain the data when
392 the Tag is rendered. The signature for data methods is similar to that of
393 render methods, (ctx, data). For example:
394 </p>
395
396 <pre class="python">
397def getName(ctx, data):
398 return ctx.arg('name')
399
400def greet(ctx, name):
401 return "Greetings, ", name
402
403class GreetName(rend.Page):
404 docFactory = loaders.stan(tags.html[
405 tags.form(action="")[
406 tags.input(name="name"),
407 tags.input(type="submit")],
408 tags.div(data=getName)[ greet ]])
409 </pre>
410
411 <p>
412 Data specials exist mainly to allow you to construct and enforce a
413 Model-View-Controller style separation of the Model code from the
414 View. Here we see that the greet function is capable of rendering a
415 greeting view for a name model, and that the implementation of getName
416 may change without the view code changing.
417 </p>
418
419 <h2>Render specials</h2>
420
421 <p>
422 Previously, we have seen how render functions can be placed directly in
423 the DOM, and the return value replaces the render function in the
424 DOM. However, these free functions and methods are devoid of any
425 contextual information about the template they are living in. The
426 render special is a way to associate a render function or method with a
427 particular Tag instance, which the render function can then examine to
428 decide how to render:
429 </p>
430
431 <pre class="python-interpreter">
432&gt;&gt;&gt; def alignment(ctx, data):
433... align = ctx.tag.attributes.get('align')
434... if align == 'right':
435... return ctx.tag["Aligned right"]
436... elif align == 'center':
437... return ctx.tag["Aligned center"]
438... else:
439... return ctx.tag["Aligned left"]
440...
441&gt;&gt;&gt; class AlignmentPage(rend.Page):
442... docFactory = loaders.stan(tags.html[
443... tags.p(render=alignment),
444... tags.p(render=alignment, align="center"),
445... tags.p(render=alignment, align="right")])
446...
447&gt;&gt;&gt; AlignmentPage().renderSynchronously()
448'&lt;html&gt;&lt;p&gt;Aligned left&lt;/p&gt;&lt;p align="center"&gt;Aligned center&lt;/p&gt;&lt;p align="right"&gt;Aligned right&lt;/p&gt;&lt;/html&gt;'</pre>
449
450 <p>
451 Note how the alignment renderer has access to the template node as
452 <code>ctx.tag</code>. It can examine and change this node, and the return value of
453 the render function replaces the original node in the DOM. Note that
454 here we are returning the template node after changing it. We will see
455 later how we can instead mutate the context and use slots so that the
456 knowledge the renderer requires about the structure of the template is
457 reduced even more.
458 </p>
459
460 <h2>Pattern specials</h2>
461
462 <p>
463 When writing render methods, it is easy to inline the construction of
464 Tag instances to generate HTML programatically. However, this creates a
465 template abstraction violation, where part of the HTML which will show
466 up in the final page output is hidden away inside of render methods
467 instead of inside the template. Pattern specials are designed to avoid
468 this problem. A node which has been tagged with a pattern special can
469 then be located and copied by a render method. The render method does
470 not need to know anything about the structure or location of the
471 pattern, only it's name.
472 </p>
473
474 <p>
475 We can rewrite our previous generator example so that the generator
476 does not have to know what type of tag the template designer would like
477 repeated for each item in the list:
478 </p>
479
480 <pre class="python-interpreter">
481&gt;&gt;&gt; from nevow import rend, loaders, tags, inevow
482&gt;&gt;&gt; def generate(ctx, items):
483... pat = inevow.IQ(ctx).patternGenerator('item')
484... for item in items:
485... ctx.tag[ pat(data=item) ]
486... return ctx.tag
487...
488&gt;&gt;&gt; def string(ctx, item):
489... return ctx.tag[ str(item) ]
490...
491&gt;&gt;&gt; class List(rend.Page):
492... docFactory = loaders.stan(tags.html[
493... tags.ul(render=generate)[
494... tags.li(pattern="item", render=string)]])
495...
496&gt;&gt;&gt; List([1, 2, 3]).renderSynchronously()
497'&lt;html&gt;&lt;ol&gt;&lt;li&gt;1&lt;/li&gt;&lt;li&gt;2&lt;/li&gt;&lt;li&gt;3&lt;/li&gt;&lt;/ol&gt;&lt;/html&gt;'</pre>
498
499 <p>
500 Note that we have to mutate the tag in place and repeatedly copy the
501 item pattern, applying the item as the data special to the resulting
502 Tag. It turns out that this is such a common operation that nevow comes
503 out of the box with these two render functions:
504 </p>
505
506 <pre class="python-interpreter">
507&gt;&gt;&gt; class List(rend.Page):
508... docFactory = loaders.stan(tags.html[
509... tags.ul(render=rend.sequence)[
510... tags.li(pattern="item", render=rend.data)]])
511...
512&gt;&gt;&gt; List([1, 2, 3]).renderSynchronously()
513'&lt;html&gt;&lt;ul&gt;&lt;li&gt;1&lt;/li&gt;&lt;li&gt;2&lt;/li&gt;&lt;li&gt;3&lt;/li&gt;&lt;/ul&gt;&lt;/html&gt;'</pre>
514
515 <h2>Slot specials</h2>
516
517 <p>
518 The problem with render methods is that they are only capable of making
519 changes to their direct children. Because of the architecture of Nevow,
520 they should not attempt to change grandchildren or parent nodes. It is
521 possible to write one render method for every node you wish to change,
522 but there is a better way. A node with a slot special can be "filled"
523 with content by any renderer above the slot. Creating a slot special is
524 such a frequent task that there is a prototype in <code>nevow.tags</code>
525 which is usually used.
526 </p>
527
528 <p>
529 Let us examine a renderer which fills a template with information about
530 a person:
531 </p>
532
533 <pre class="python-interpreter">
534&gt;&gt;&gt; from nevow import loaders, rend, tags
535...
536&gt;&gt;&gt; person = ('Donovan', 'Preston', 'Male', 'California')
537...
538&gt;&gt;&gt; def render_person(ctx, person):
539... firstName, lastName, sex, location = person
540... ctx.fillSlots('firstName', firstName)
541... ctx.fillSlots('lastName', lastName)
542... ctx.fillSlots('sex', sex)
543... ctx.fillSlots('location', location)
544... return ctx.tag
545...
546&gt;&gt;&gt; class PersonPage(rend.Page):
547... docFactory = loaders.stan(tags.html(render=render_person)[
548... tags.table[
549... tags.tr[
550... tags.td[tags.slot('firstName')],
551... tags.td[tags.slot('lastName')],
552... tags.td[tags.slot('sex')],
553... tags.td[tags.slot('location')]]]])
554...
555&gt;&gt;&gt; PersonPage(person).renderSynchronously()
556'&lt;html&gt;&lt;table&gt;&lt;tr&gt;&lt;td&gt;Donovan&lt;/td&gt;&lt;td&gt;Preston&lt;/td&gt;&lt;td&gt;Male&lt;/td&gt;&lt;td&gt;California&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/html&gt;'</pre>
557
558 <p>
559 Using patterns in combination with slots can lead to very powerful
560 template abstraction. Nevow also includes another standard renderer
561 called "mapping" which takes any data which responds to the "items()"
562 message and inserts the items into appropriate slots:
563 </p>
564
565 <pre class="python-interpreter">
566&gt;&gt;&gt; class DictPage(rend.Page):
567... docFactory = loaders.stan(tags.html(render=rend.mapping)[
568... tags.span[ tags.slot('foo') ], tags.span[ tags.slot('bar') ]])
569...
570&gt;&gt;&gt; DictPage(dict(foo=1, bar=2)).renderSynchronously()
571'&lt;html&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/html&gt;'</pre>
572
573 <h2>Data directives</h2>
574
575 <p>
576 So far, we have always placed data functions directly in the Data
577 special attribute of a Tag. Sometimes, it is preferable to look up a
578 data method from the Page class as the Page has being rendered. For
579 example, a base class may define a template and a subclass may provide
580 the implementation of the data method. We can accomplish this effect by
581 using a data directive as a Tag's data special:
582 </p>
583
584 <pre class="python">
585class Base(rend.Page):
586 docFactory = loaders.stan(tags.html[
587 tags.div(data=tags.directive('name'), render=rend.data)])
588
589class Subclass(Base):
590 def data_name(self, ctx, data):
591 return "Your name"
592 </pre>
593
594 <p>
595 The data directive is resolved by searching for the
596 <code>IContainer</code> implementation in the context.
597 <code>rend.Page</code> implements <code>IContainer.get</code> by
598 performing an attribute lookup on the Page with the prefix 'data_*'. You
599 can provide your own <code>IContainer</code> implementation if you wish,
600 and also you should know that <code>IContainer</code> implementations for
601 list and dict are included in the <code class="API">nevow.accessors</code>
602 module.
603 </p>
604
605 <p>
606 A common gotcha is that the closest <code>IContainer</code> is used to
607 resolve data directives. This means that if a list is being used as the
608 data during the rendering process, data directives below this will be
609 resolved against the <code>IContainer</code> implementation in
610 <code>nevow.accessors.ListAccessor</code>. If you are expecting a data
611 directive to invoke a Page's data_* method but instead get a
612 <code>KeyError</code>, this is why.
613 </p>
614
615 <h2>Render directives</h2>
616
617 <p>
618 Render directives are almost exactly the same, except they are resolved
619 using the closest <code>IRendererFactory</code> implementation in the
620 context. Render directives can be used to allow subclasses to override
621 certain render methods, and also can be used to allow Fragments to
622 locate their own prefixed render methods.
623 </p>
624
625 <h2>Flatteners</h2>
626
627 <p>
628 TODO This section isn't done yet.
629 </p>
630
631 <p>
632 Nevow's flatteners use a type/function registry to determine how to
633 render objects which Nevow encounters in the DOM during the rendering
634 process. "Explicit is better than implicit", so in most cases,
635 explicitly applying render methods to data will be better than
636 registering a flattener, but in some cases it can be useful:
637 </p>
638
639 <pre class="python">
640class Person(object):
641 def __init__(self, firstName, lastName):
642 self.firstName = firstName
643 self.lastName = lastName
644
645def flattenPerson(person, ctx):
646 return flat.partialflatten(ctx, (person.firstName, " ", person.lastName))
647
648from nevow import flat
649flat.registerFlattener(flattenPerson, Person)
650
651def insertData(ctx, data):
652 return data
653
654class PersonPage(rend.Page):
655 docFactory = loaders.stan(tags.html[insertData])
656 </pre>
657 </body>
658</html>
6590
=== removed file 'Nevow/doc/howto/stylesheet.css'
--- Nevow/doc/howto/stylesheet.css 2008-09-20 01:06:47 +0000
+++ Nevow/doc/howto/stylesheet.css 1970-01-01 00:00:00 +0000
@@ -1,129 +0,0 @@
1body
2{
3 margin-left: 2em;
4 margin-right: 2em;
5 border: 0px;
6 padding: 0px;
7 font-family: sans-serif;
8}
9
10pre
11{
12 padding: 1em;
13 font-family: Monospace, Neep Alt, Courier New, Courier;
14 font-size: 12pt;
15 border: thin black solid;
16}
17
18.python
19{
20 background-color: #dddddd;
21}
22
23.py-listing, .html-listing, .listing
24{
25 margin: 1ex;
26 border: thin solid black;
27 background-color: #eee;
28}
29
30.py-listing pre, .html-listing pre, .listing pre
31{
32 margin: 0px;
33 border: none;
34 border-bottom: thin solid black;
35}
36
37.py-listing .python
38{
39 margin-top: 0;
40 margin-bottom: 0;
41 border: none;
42 border-bottom: thin solid black;
43}
44
45.py-src-comment
46{
47 color: #1111CC
48}
49
50.py-src-keyword
51{
52 color: #3333CC;
53 font-weight: bold;
54}
55
56.py-src-parameter
57{
58 color: #000066;
59 font-weight: bold;
60}
61
62.py-src-identifier
63{
64 color: #CC0000
65}
66
67.py-src-string
68{
69 color: #115511
70}
71
72.py-src-endmarker
73{
74 display: block; /* IE hack; prevents following line from being sucked into the py-listing box. */
75}
76
77hr
78{
79 display: inline;
80}
81
82ul
83{
84 padding: 0px;
85 margin: 0px;
86 margin-left: 1em;
87 padding-left: 1em;
88 border-left: 1em;
89}
90
91li
92{
93 padding: 2px;
94}
95
96dt
97{
98 font-weight: bold;
99 margin-left: 1ex;
100}
101
102dd
103{
104 margin-bottom: 1em;
105}
106
107div.note
108{
109 background-color: #FFFFCC;
110 margin-top: 1ex;
111 margin-left: 5%;
112 margin-right: 5%;
113 padding-top: 1ex;
114 padding-left: 5%;
115 padding-right: 5%;
116 border: thin black solid;
117}
118
119.caption
120{
121 text-align: center;
122 padding-top: 0.5em;
123 padding-bottom: 0.5em;
124}
125
126.filename
127{
128 font-style: italic;
129}
1300
=== removed file 'Nevow/doc/howto/template.tpl'
--- Nevow/doc/howto/template.tpl 2008-08-26 13:45:59 +0000
+++ Nevow/doc/howto/template.tpl 1970-01-01 00:00:00 +0000
@@ -1,24 +0,0 @@
1<?xml version="1.0"?>
2<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
3 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
4
5<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
6 <head>
7 <title>
8 Nevow:
9 </title>
10 <link type="text/css" rel="stylesheet" href="stylesheet.css" />
11 </head>
12
13 <body bgcolor="white">
14 <h1 class="title"></h1>
15 <div class="toc"></div>
16 <div class="body">
17
18 </div>
19
20 <p><a href="index.html">Index</a></p>
21 <span class="version">Version: </span>
22 </body>
23</html>
24
250
=== removed file 'Nevow/doc/howto/traversal.xhtml'
--- Nevow/doc/howto/traversal.xhtml 2008-09-26 16:30:04 +0000
+++ Nevow/doc/howto/traversal.xhtml 1970-01-01 00:00:00 +0000
@@ -1,448 +0,0 @@
1<?xml version="1.0"?>
2<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
3 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
4
5<html xmlns="http://www.w3.org/1999/xhtml">
6 <head>
7 <title>
8 Object Traversal
9 </title>
10 </head>
11 <body>
12 <h1>Object Traversal</h1>
13
14 <p>
15 <strong>Object traversal</strong> is the process Nevow uses to determine
16 what object to use to render HTML for a particular URL. When an HTTP
17 request comes in to the web server, the object publisher splits the URL
18 into segments, and repeatedly calls methods which consume path segments
19 and return objects which represent that path, until all segments have
20 been consumed. At the core, the Nevow traversal API is very
21 simple. However, it provides some higher level functionality layered on
22 top of this to satisfy common use cases.
23 </p>
24
25 <h2>Object Traversal Basics</h2>
26
27 <p>
28 The <strong>root resource</strong> is the top-level object in the URL
29 space; it conceptually represents the URI <code>/</code>. The Nevow
30 <strong>object traversal</strong> and <strong>object publishing</strong>
31 machinery uses only two methods to locate an object suitable for
32 publishing and to generate the HTML from it; these methods are described
33 in the interface <code class="API">nevow.inevow.IResource</code>:
34 </p>
35
36 <pre class="python">
37class IResource(Interface):
38 def locateChild(self, ctx, segments):
39 """Locate another object which can be adapted to IResource
40 Return a tuple of resource, path segments
41 """
42
43 def renderHTTP(self, ctx):
44 """Render a request
45 """
46 </pre>
47
48 <p>
49 <code class="API" base="nevow.inevow.IResource">renderHTTP</code> can be
50 as simple as a method which simply returns a string of HTML. Let's
51 examine what happens when object traversal occurs over a very simple root
52 resource:
53 </p>
54
55 <pre class="python">
56from zope.interface import implements
57
58class SimpleRoot(object):
59 implements(inevow.IResource)
60
61 def locateChild(self, ctx, segments):
62 return self, ()
63
64 def renderHTTP(self, ctx):
65 return "Hello, world!"
66 </pre>
67
68 <p>
69 This resource, when passed as the root resource to <code class="API"
70 base="nevow">appserver.NevowSite</code> or <code class="API"
71 base="nevow">wsgi.createWSGIApplication</code>, will immediately return
72 itself, consuming all path segments. This means that for every URI a user
73 visits on a web server which is serving this root resource, the text
74 <code>"Hello, world!"</code> will be rendered. Let's examine the value of
75 <code>segments</code> for various values of URI:
76 </p>
77
78 <ul>
79 <li><code>/</code> - <code>('',)</code></li>
80 <li><code>/foo/bar</code> - <code>('foo', 'bar')</code></li>
81 <li>
82 <code>/foo/bar/baz.html</code> -
83 <code>('foo', 'bar', 'baz.html')</code>
84 </li>
85 <li>
86 <code>/foo/bar/directory/</code> -
87 <code>('foo', 'bar', 'directory', '')</code>
88 </li>
89 </ul>
90
91 <p>
92 So we see that Nevow does nothing more than split the URI on the string
93 <code>/</code> and pass these path segments to our application for
94 consumption. Armed with these two methods alone, we already have enough
95 information to write applications which service any form of URL
96 imaginable in any way we wish. However, there are some common URL
97 handling patterns which Nevow provides higher level support for.
98 </p>
99
100 <h2><code>locateChild</code> In Depth</h2>
101
102 <p>
103 One common URL handling pattern involves parents which only know about
104 their direct children. For example, a ``Directory`` object may only know
105 about the contents of a single directory, but if it contains other
106 directories, it does not know about the contents of them. Let's examine a
107 simple ``Directory`` object which can provide directory listings and
108 serves up objects for child directories and files:
109 </p>
110
111 <pre class="python">
112from zope.interface import implements
113
114class Directory(object):
115 implements(inevow.IResource)
116
117 def __init__(self, directory):
118 self.directory = directory
119
120 def renderHTTP(self, ctx):
121 html = ['&lt;ul&gt;']
122 for child in os.listdir(self.directory):
123 fullpath = os.path.join(self.directory, child)
124 if os.path.isdir(fullpath):
125 child += '/'
126 html.extend(['&lt;li&gt;&lt;a href="', child, '"&gt;', child, '&lt;/a&gt;&lt;/li&gt;'])
127 html.append('&lt;/ul&gt;')
128 return ''.join(html)
129
130 def locateChild(self, ctx, segments):
131 name = segments[0]
132 fullpath = os.path.join(self.directory, name)
133 if not os.path.exists(fullpath):
134 return None, () # 404
135
136 if os.path.isdir(fullpath):
137 return Directory(fullpath), segments[1:]
138 if os.path.isfile(fullpath):
139 return static.File(fullpath), segments[1:]
140 </pre>
141
142 <p>
143 Because this implementation of <code>locateChild</code> only consumed one
144 segment and returned the rest of them (<code>segments[1:]</code>), the
145 object traversal process will continue by calling
146 <code>locateChild</code> on the returned resource and passing the
147 partially-consumed segments. In this way, a directory structure of any
148 depth can be traversed, and directory listings or file contents can be
149 rendered for any existing directories and files.
150 </p>
151
152 <p>
153 So, let us examine what happens when the URI
154 <code>"/foo/bar/baz.html"</code> is traversed, where <code>"foo"</code>
155 and <code>"bar"</code> are directories, and <code>"baz.html"</code> is a
156 file.
157 </p>
158
159 <ol>
160 <li>
161 <code>
162 Directory('/').locateChild(ctx, ('foo', 'bar', 'baz.html'))
163 </code>
164 returns
165 <code>Directory('/foo'), ('bar', 'baz.html')</code>
166 </li>
167 <li>
168 <code>
169 Directory('/foo').locateChild(ctx, ('bar', 'baz.html'))
170 </code>
171 returns
172 <code>Directory('/foo/bar'), ('baz.html, )</code>
173 </li>
174 <li>
175 <code>
176 Directory('/foo/bar').locateChild(ctx, ('baz.html'))
177 </code>
178 returns
179 <code>File('/foo/bar/baz.html'), ()</code>
180 </li>
181 <li>
182 No more segments to be consumed;
183 <code>File('/foo/bar/baz.html').renderHTTP(ctx)</code> is called, and
184 the result is sent to the browser.
185 </li>
186 </ol>
187
188
189 <h2><code>childFactory</code> Method</h2>
190
191 <p>
192 Consuming one URI segment at a time by checking to see if a requested
193 resource exists and returning a new object is a very common
194 pattern. Nevow's default implementation of <code class="API"
195 base="nevow.inevow">IResource</code>, <code
196 class="API">nevow.rend.Page</code>, contains an implementation of
197 <code>locateChild</code> which provides more convenient hooks for
198 implementing object traversal. One of these hooks is
199 <code>childFactory</code>. Let us imagine for the sake of example that we
200 wished to render a tree of dictionaries. Our data structure might look
201 something like this:
202 </p>
203
204 <pre class="python">
205tree = dict(
206 one=dict(
207 foo=None,
208 bar=None),
209 two=dict(
210 baz=dict(
211 quux=None)))
212 </pre>
213
214 <p>
215 Given this data structure, the valid URIs would be:
216 </p>
217
218 <ul>
219 <li>/</li>
220 <li>/one</li>
221 <li>/one/foo</li>
222 <li>/one/bar</li>
223 <li>/two</li>
224 <li>/two/baz</li>
225 <li>/two/baz/quux</li>
226 </ul>
227
228 <p>
229 Let us construct a <code class="API" base="nevow">rend.Page</code>
230 subclass which uses the default <code>locateChild</code> implementation
231 and overrides the <code>childFactory</code> hook instead:
232 </p>
233
234 <pre class="python">
235class DictTree(rend.Page):
236 def __init__(self, dataDict):
237 self.dataDict = dataDict
238
239 def renderHTTP(self, ctx):
240 if self.dataDict is None:
241 return "Leaf"
242 html = ['&lt;ul&gt;']
243 for key in self.dataDict.keys():
244 html.extend(['&lt;li&gt;&lt;a href="', key, '"&gt;', key, '&lt;/a&gt;&lt;/li&gt;'])
245 html.append('&lt;/ul&gt;')
246 return ''.join(html)
247
248 def childFactory(self, ctx, name):
249 if name not in self.dataDict:
250 return rend.NotFound # 404
251 return DictTree(self.dataDict[name])
252 </pre>
253
254 <p>
255 As you can see, the <code>childFactory</code> implementation is
256 considerably shorter than the equivalent <code>locateChild</code>
257 implementation would have been.
258 </p>
259
260 <h2><code>child_*</code> methods and attributes</h2>
261
262 <p>
263 Often we may wish to have some hardcoded URLs which are not dynamically
264 generated based on some data structure. For example, we might have an
265 application which uses an external CSS stylesheet, an external JavaScript
266 file, and a folder full of images. The <code class="API"
267 base="nevow">rend.Page.locateChild</code> implementation provides a
268 convenient way for us to express these relationships by using
269 child-prefixed methods:
270 </p>
271
272 <pre class="python">
273class Linker(rend.Page):
274 def renderHTTP(self, ctx):
275 return """&lt;html&gt;
276&lt;head&gt;
277 &lt;link href="css" rel="stylesheet" /&gt;
278 &lt;script type="text/javascript" src="scripts" /&gt;
279 &lt;body&gt;
280 &lt;img src="images/logo.png" /&gt;
281 &lt;/body&gt;
282&lt;/html&gt;"""
283
284 def child_css(self, ctx):
285 return static.File('styles.css')
286
287 def child_scripts(self, ctx):
288 return static.File('scripts.js')
289
290 def child_images(self, ctx):
291 return static.File('images/')
292 </pre>
293
294 <p>
295 One thing you may have noticed is that all of the examples so far have
296 returned new object instances whenever they were implementing a traversal
297 API. However, there is no reason these instances cannot be shared. One
298 could for example return a global resource instance, an instance which
299 was previously inserted in a dict, or lazily create and cache dynamic
300 resource instances on the fly. The <code>rend.Page.locateChild</code>
301 implementation also provides a convenient way to express that one global
302 resource instance should always be used for a particular URL, the
303 child-prefixed attribute:
304 </p>
305
306 <pre class="python">
307class FasterLinker(Linker):
308 child_css = static.File('styles.css')
309 child_scripts = static.File('scripts.js')
310 child_images = static.File('images/')
311 </pre>
312
313 <h2>Dots in child names</h2>
314
315 <p>
316 When a URL contains dots, which is quite common in normal URLs, it is
317 simple enough to handle these URL segments in <code>locateChild</code> or
318 <code>childFactory</code> -- one of the passed segments will simply be a
319 string containing a dot. However, it is not immediately obvious how one
320 would express a URL segment with a dot in it when using child-prefixed
321 methods. The solution is really quite simple:
322 </p>
323
324 <pre class="python">
325class DotChildren(rend.Page):
326 def renderHTTP(self, ctx):
327 return """
328 &lt;html&gt;
329 &lt;head&gt;
330 &lt;script type="text/javascript" src="scripts.js" /&gt;
331 &lt;/head&gt;
332 &lt;/html&gt;"""
333
334setattr(DotChildren, 'child_scripts.js', static.File('scripts.js'))
335 </pre>
336
337 <p>
338 The same technique could be used to install a child method with a dot in
339 the name.
340 </p>
341
342
343 <h2>children dictionary</h2>
344
345 <p>
346 The final hook supported by the default implementation of
347 <code>locateChild</code> is the <code>rend.Page.children</code>
348 dictionary:
349 </p>
350
351 <pre class="python">
352class Main(rend.Page):
353 children = {
354 'people': People(),
355 'jobs': Jobs(),
356 'events': Events()}
357
358 def renderHTTP(self, ctx):
359 return """
360 &lt;html&gt;
361 &lt;head&gt;
362 &lt;title&gt;Our Site&lt;/title&gt;
363 &lt;/head&gt;
364 &lt;body&gt;
365 &lt;p&gt;bla bla bla&lt;/p&gt;
366 &lt;/body&gt;
367 &lt;/html&gt;"""
368 </pre>
369
370 <p>
371 Hooks are checked in the following order:
372 </p>
373
374 <ol>
375 <li><code>self.children</code></li>
376 <li><code>self.child_*</code></li>
377 <li><code>self.childFactory</code></li>
378 </ol>
379
380 <h2>The default trailing slash handler</h2>
381
382 <p>
383 When a URI which is being handled ends in a slash, such as when the
384 <code>/</code> URI is being rendered or when a directory-like URI is
385 being rendered, the string <code>''</code> appears in the path segments
386 which will be traversed. Again, handling this case is trivial inside
387 either <code>locateChild</code> or <code>childFactory</code>, but it may
388 not be immediately obvious what child-prefixed method or attribute will
389 be looked up. The method or attribute name which will be used is simply
390 <code>child</code> with a single trailing underscore.
391 </p>
392
393 <p>
394 The <code>rend.Page</code> class provides an implementation of this
395 method which can work in two different ways. If the attribute
396 <code>addSlash</code> is <code>True</code>, the default trailing slash
397 handler will return <code>self</code>. In the case when
398 <code>addSlash</code> is <code>True</code>, the default
399 <code>rend.Page.renderHTTP</code> implementation will simply perform a
400 redirect which adds the missing slash to the URL.
401 </p>
402
403 <p>
404 The default trailing slash handler also returns self if
405 <code>addSlash</code> is <code>False</code>, but emits a warning as it
406 does so. This warning may become an exception at some point in the
407 future.
408 </p>
409
410 <h2><code>ICurrentSegments</code> and <code>IRemainingSegments</code></h2>
411
412 <p>
413 During the object traversal process, it may be useful to discover which
414 segments have already been handled and which segments are remaining to be
415 handled. This information may be obtained from the <code>context</code>
416 object which is passed to all the traversal APIs. The interfaces <code
417 class="API">nevow.inevow.ICurrentSegments</code> and <code
418 class="API">nevow.inevow.IRemainingSegments</code> are used to retrieve
419 this information. To retrieve a tuple of segments which have previously
420 been consumed during object traversal, use this syntax:
421 </p>
422
423 <pre class="python">
424segs = ICurrentSegments(ctx)
425 </pre>
426
427 <p>
428 The same is true of <code>IRemainingSegments</code>.
429 <code>IRemainingSegments</code> is the same value which is passed as
430 <code>segments</code> to <code>locateChild</code>, but may also be useful
431 in the implementations of <code>childFactory</code> or a child-prefixed
432 method, where this information would not otherwise be available.
433 </p>
434
435 <h2>Conclusion</h2>
436
437 <p>
438 Nevow makes it easy to handle complex URL hierarchies. The most basic
439 object traversal interface, <code
440 class="API">nevow.inevow.IResource.locateChild</code>, provides powerful
441 and flexible control over the entire object traversal process. Nevow's
442 canonical <code>IResource</code> implementation, <code>rend.Page</code>,
443 also includes the convenience hooks <code>childFactory</code> along with
444 child-prefixed method and attribute semantics to simplify common use
445 cases.
446 </p>
447 </body>
448</html>
4490
=== removed file 'Nevow/doc/howto/xmltemplates.xhtml'
--- Nevow/doc/howto/xmltemplates.xhtml 2008-08-26 13:45:59 +0000
+++ Nevow/doc/howto/xmltemplates.xhtml 1970-01-01 00:00:00 +0000
@@ -1,407 +0,0 @@
1<?xml version="1.0"?>
2<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
3 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
4
5<html xmlns="http://www.w3.org/1999/xhtml">
6 <head>
7 <title>
8 XML Templates
9 </title>
10 </head>
11 <body>
12 <h1>Nevow XML Templates</h1>
13
14 <p>
15 Stan syntax is cool, but eventually you are going to want to integrate
16 your Python code with a template designed by an HTML monkey. Nevow
17 accomplishes this by providing an xmlfile loader which uses the built-in
18 Python SAX libraries to generate a tree of stan behind the scenes. The
19 general rule is anything that is possible in stan should be possible in a
20 pure XML template; of course, the XML syntax is generally going to be
21 much more verbose.
22 </p>
23
24 <h2>loaders.xmlfile</h2>
25
26 <p>
27 Wherever you have seen a loaders.stan being created in any of the example
28 code, a <code class="API" base="nevow">loaders.xmlfile</code> can be
29 substituted instead. At the most basic, <code>xmlfile</code> merely
30 requires the name of an xml template:
31 </p>
32
33 <pre class="python">
34class HelloXML(rend.Page):
35 docFactory = loaders.xmlfile('hello.xml')
36 </pre>
37
38 <p>
39 Placing the following xml in the <code>hello.xml</code> file will cause
40 <code>HelloXML</code> to display a static page when it is rendered:
41 </p>
42
43 <pre>&lt;html&gt;Hello, world!&lt;/html&gt;</pre>
44
45 <p>
46 The following additional keyword arguments may be given to
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches