Merge lp:~exarkun/divmod.org/remove-nevow into lp:divmod.org
- remove-nevow
- Merge into trunk
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 | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Tristan Seligmann | Approve | ||
Review via email: mp+222457@code.launchpad.net |
Commit message
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
1 | === modified file 'Divmod.pth' |
2 | --- Divmod.pth 2014-05-18 17:48:04 +0000 |
3 | +++ Divmod.pth 2014-06-08 12:16:37 +0000 |
4 | @@ -1,9 +1,8 @@ |
5 | -# -*- test-case-name: axiom,combinator,epsilon,xmantissa,nevow,formless,xquotient,reverend,sine,hyperbola -*- |
6 | +# -*- test-case-name: axiom,combinator,epsilon,xmantissa,xquotient,reverend,sine,hyperbola -*- |
7 | Axiom |
8 | Combinator |
9 | Epsilon |
10 | Mantissa |
11 | -Nevow |
12 | Quotient |
13 | Reverend |
14 | Sine |
15 | |
16 | === removed directory 'Nevow' |
17 | === removed file 'Nevow/ChangeLog' |
18 | --- Nevow/ChangeLog 2006-06-14 11:54:41 +0000 |
19 | +++ Nevow/ChangeLog 1970-01-01 00:00:00 +0000 |
20 | @@ -1,743 +0,0 @@ |
21 | -2006-06-12 Glyph Lefkowitz <glyph@divmod.com> |
22 | - |
23 | - * Nevow 0.9.0: see NEWS.txt for details. |
24 | - |
25 | -2006-04-07 Jp Calderone <exarkun@divmod.com> |
26 | - |
27 | - * Nevow 0.8.0 released |
28 | - |
29 | -2006-03-30 Tommi Virtanen <tv@twistedmatrix.com> |
30 | - |
31 | - * nevow/static.py: Fix handling of range requests on static files. |
32 | - |
33 | -2006-03-30 Jp Calderone <exarkun@divmod.com> |
34 | - |
35 | - * formless/freeform-defaults.css, formless/annotate.py: Style and |
36 | - feedback improvements. |
37 | - |
38 | -2006-03-29 Jp Calderone <exarkun@divmod.com> |
39 | - |
40 | - * examples/formbuilder/: Apply Cory Dodt's patch to make this |
41 | - example work again. |
42 | - |
43 | -2006-03-27 Jp Calderone <exarkun@divmod.com> |
44 | - |
45 | - * nevow/athena.py: Add getInitialArguments method which will be |
46 | - invoked during rendering and may return a list or tuple of objects |
47 | - which will be be passed to the client-side Widget's __init__ method. |
48 | - |
49 | -2006-03-24 Allen Short <washort@divmod.com> |
50 | - |
51 | - * Upgrade MochiKit to 1.2 |
52 | - |
53 | -2006-03-17 Tristan Seligmann <mithrandi@mithrandi.za.net> |
54 | - |
55 | - * Remove usage of twisted.python.components.Interface from formless. |
56 | - Convert TypedInterface to zope.interface. |
57 | - |
58 | -2006-03-17 Jp Calderone <exarkun@divmod.com> |
59 | - |
60 | - * nevow/json.py: Improve (hopefully correct this time ;) unicode |
61 | - support. |
62 | - |
63 | -2006-03-08 Valentino Volonghi <dialtone@divmod.com> |
64 | - |
65 | - * Remove usage of twisted.python.components.Interface from nevow. |
66 | - Remove compyCompat. |
67 | - |
68 | -2006-02-28 Jp Calderone <exarkun@divmod.com> |
69 | - |
70 | - * nevow/athena.py: Make the "Connection: Close" header of Athena |
71 | - transport responses optional (toggleable by a flag on LivePage) to |
72 | - allow TCP connection setup overhead to be avoided. |
73 | - |
74 | -2006-02-15 Tristan Seligmann <mithrandi@mithrandi.za.net> |
75 | - |
76 | - * nevow/athena.js, nevow/athena.py: Pass JavaScript call-stack |
77 | - information back to the server and include it in logged tracebacks |
78 | - (Firefox only). |
79 | - |
80 | -2006-02-14 Jp Calderone <exarkun@divmod.com> |
81 | - |
82 | - * nevow/util.py: Delete a bunch of code duplicated from Twisted. |
83 | - |
84 | -2006-02-06 Glyph Lefkowitz <glyph@twistedmatrix.com> |
85 | - |
86 | - * nevow/athena.py, nevow/athena.js: Pop up an obnoxious widget when |
87 | - an Athena connection is lost. |
88 | - |
89 | -2006-02-06 Jp Calderone <exarkun@divmod.com> |
90 | - |
91 | - * nevow/runtime.js: Add Platform.getPage, a wrapper around the |
92 | - browser-provided HTTP request function. |
93 | - |
94 | -2006-02-01 Tristan Seligmann <mithrandi@mithrandi.za.net> |
95 | - |
96 | - * nevow/athena.js: Add support for <athena:handler> element, a |
97 | - declarative mechanism for attaching event handlers to nodes. |
98 | - |
99 | -2006-02-01 Tristan Seligmann <mithrandi@mithrandi.za.net> |
100 | - |
101 | - * bin/nit: Test collector/runner for Athena widgets. |
102 | - |
103 | -2006-02-01 Jp Calderone <exarkun@divmod.com> |
104 | - |
105 | - * nevow/defer.js: Deferred implementation to replace MochiKit |
106 | - Deferreds. |
107 | - |
108 | -2006-01-21 Valentino Volonghi <dialtone@divmod.com> |
109 | - |
110 | - * nevow/rend.py, formless/webform.py: Support Deferreds returned |
111 | - from bind_ methods. |
112 | - |
113 | -2006-01-21 Valentino Volonghi <dialtone@divmod.com> |
114 | - |
115 | - * nevow/flat/flatstan.py: Fix macros inside of other specials. |
116 | - |
117 | -2006-01-19 Jp Calderone <exarkun@divmod.com> |
118 | - |
119 | - * nevow/athena.js: Added Divmod.Class.methods() for defining |
120 | - multiple methods at once. |
121 | - |
122 | -2006-01-19 Jp Calderone <exarkun@divmod.com> |
123 | - |
124 | - * nevow/athena.py, nevow/athena.js: Support the addition of |
125 | - LiveFragment instances to a page after the initial render pass. |
126 | - |
127 | -2006-01-15 Jp Calderone <exarkun@divmod.com> |
128 | - |
129 | - * nevow/athena.js: Introduced new form of Divmod.Class.method() for |
130 | - adding methods to JavaScript classes. Added a child-window based |
131 | - log viewer. |
132 | - |
133 | -2006-01-08 Valentino Volonghi <dialtone@divmod.com> |
134 | - |
135 | - * examples/hello/hellohtml.py: Removed htmlfile usage |
136 | - * nevow/loaders.py: Deprecated htmlfile/htmlstr |
137 | - |
138 | -2006-01-08 Glyph Lefkowitz <glyph@twistedmatrix.com> |
139 | - |
140 | - * nevow/test/, formless/test/: Removed all usage of trial's |
141 | - deferredResult() and util.wait() functions. |
142 | - |
143 | -2006-01-04 Glyph Lefkowitz <glyph@twistedmatrix.com> |
144 | - |
145 | - * nevow/athena.py: Added fragment and widget nesting. On the |
146 | - server side, this documents and provides a supported way of |
147 | - setting the magical required "page" attribute. On the client |
148 | - side, this provides a convenient hook for multiple widgets within |
149 | - a page to communicate with each other. |
150 | - |
151 | -2005-12-26 Jp Calderone <exarkun@divmod.com> |
152 | - |
153 | - * nevow/athena.py: Added athena.js and MochiKit.js to the dictionary |
154 | - returned by allJavascriptModules(), allowing them to be referenced |
155 | - using the JS import mechanism, in turn allowing them both to be |
156 | - served from a single site-wide URL, rather than once per page. |
157 | - |
158 | -2005-12-22 Jp Calderone <exarkun@divmod.com> |
159 | - |
160 | - * nevow/athena.py: Remove Python 2.4 dependencies. |
161 | - |
162 | -2005-12-21 Jp Calderone <exarkun@divmod.com> |
163 | - |
164 | - * Nevow 0.7.0 released |
165 | - |
166 | -2005-12-18 Jp Calderone <exarkun@divmod.com> |
167 | - |
168 | - * nevow/athena.py: Server-side processing of .js files to allow for |
169 | - an import directive. Imported JavaScript modules are inserted into |
170 | - the page during the render process in dependency order. |
171 | - |
172 | - * nevow/widget.js: Athena Widgets class and support code definitions |
173 | - moved here. |
174 | - |
175 | -2005-12-13 Matt Goodall <matt@pollenation.net> |
176 | - |
177 | - * nevow/athena.js: Improved IE compatibility. |
178 | - |
179 | -2005-12-05 Jp Calderone <exarkun@divmod.com> |
180 | - |
181 | - * nevow/athena.js: Added Divmod.Class object which provides a |
182 | - class-based object model for JavaScript programs. Added |
183 | - Nevow.Athena.Widget, a base class for "Live Widgets" - JavaScript |
184 | - classes which can control a particular section of a LivePage and can |
185 | - communicate with corresponding LiveFragment instances on the server. |
186 | - |
187 | - * nevow/athena.py: Added a callRemote method to LiveFragment - this |
188 | - allows the server to invoke methods on particular Widgets on the |
189 | - client. |
190 | - |
191 | -2005-12-03 Jp Calderone <exarkun@divmod.com> |
192 | - |
193 | - * nevow/rend.py: Fixed a bug in xmlfile caching which could lead to |
194 | - a corrupt loader cache. |
195 | - |
196 | -2005-11-29 Jp Calderone <exarkun@divmod.com> |
197 | - |
198 | - * nevow/appserver.py: Removed "support" (which consisted of logging |
199 | - an error message and continuing) for returning objects which do not |
200 | - provide IResource. |
201 | - |
202 | -2005-11-26 Jp Calderone <exarkun@divmod.com> |
203 | - |
204 | - * nevow/athena.py, nevow/athena.js: Use POST for the LivePage |
205 | - transport, rather than GET. |
206 | - |
207 | - * nevow/json.py: Fix a bug in JSON support for floating points. |
208 | - |
209 | -2005-11-25 Jp Calderone <exarkun@divmod.com> |
210 | - |
211 | - * nevow/athena.js: Go live by default. |
212 | - |
213 | -2005-11-22 Glyph Lefkowitz <glyph@divmod.com> |
214 | - |
215 | - * nevow/guard.py: Removed __session_just_startd__. |
216 | - |
217 | -2005-11-15 Jp Calderone <exarkun@divmod.com> |
218 | - |
219 | - * nevow/athena.py: Added LiveFragment - base class for Fragments |
220 | - which may cooperatively share a single LivePage connection. |
221 | - |
222 | - |
223 | -2005-11-09 Jp Calderone <exarkun@divmod.com> |
224 | - |
225 | - * Athena JavaScript API unified into a pseudo-namespace hierarchy. |
226 | - |
227 | -2005-11-07 Jp Calderone <exarkun@divmod.com> |
228 | - |
229 | - * JSON serializer now quotes dict/object keys. |
230 | - |
231 | -2005-11-02 Jp Calderone <exarkun@divmod.com> |
232 | - |
233 | - * Nevow 0.6.0 released |
234 | - |
235 | -2005-09-21 Jp Calderone <exarkun@divmod.com> |
236 | - |
237 | - * nevow/athena.py: New implementation of LivePage with a |
238 | - data-centric API: generation of JavaScript on the server is highly |
239 | - discouraged, instead an API for passing around simple or complex |
240 | - data structures is provided. |
241 | - |
242 | -2005-08-01 Matt Goodall <matt@pollenation.net> |
243 | - |
244 | - egg-ify the distribution. "python setup.py bdist_egg" will now build |
245 | - a .egg in dist for Python 2.3 and Python 2.4. |
246 | - |
247 | -2005-07-14 Donovan Preston <dp@divmod.org> |
248 | - |
249 | - * It's no longer necessary to specify addSlash = True on |
250 | - the root resource. nevow.appserver.NevowSite automatically |
251 | - sets it on the first argument you pass to it (the root |
252 | - resource). |
253 | - |
254 | -2005-07-12 Donovan Preston <dp@divmod.org> |
255 | - |
256 | - * Usability improvements for formless at the expense of |
257 | - purity of abstraction. Since the only thing anybody uses |
258 | - formless for is rendering web forms, make it a little easier |
259 | - to do common things. For example: |
260 | - |
261 | - - _nevow_carryover_ does not get appended to URLs unless absolutely |
262 | - necessary (because you return a value from an autocallable) |
263 | - |
264 | - - TypedInterface is being deprecated in favor of using |
265 | - IConfigurable directly, and an IConfigurable implementation |
266 | - on Fragment/Page that is easy to use. To expose a "foo" method |
267 | - on a page which takes a "bar" string and a "baz" integer, do this: |
268 | - |
269 | - def bind_foo(self, ctx): |
270 | - return [('bar', String()), ('baz', Integer())] |
271 | - |
272 | - Previously, you would have had to create a TypedInterface, |
273 | - declare foo and the types of the arguments in the class body, |
274 | - declare that foo is autocallable, and declare that your Page |
275 | - class __implements__ the interface. Now, just implement |
276 | - bind_foo to return an IBinding or a list which can be munged |
277 | - into one. |
278 | - |
279 | - - It is possible to return a Page from an autocallable to have |
280 | - that page displayed directly after posting the autocallable. |
281 | - The URL that is used is freeform_hand, which means that the |
282 | - Page goes into your "hand" in the session. The hand can only |
283 | - hold one value, the most recent return result of an autocallable. |
284 | - This isn't very back-button friendly but it makes it super |
285 | - easy to put together a multi-step wizard interface. |
286 | - |
287 | - See examples/tests/testformless.py and the /testformless on |
288 | - the example server to see how to do this. |
289 | - |
290 | - - It is possible to return a URL instance from an autocallable |
291 | - to have the user redirected to that page after posting the |
292 | - form successfully. This replaces and deprecates the old, |
293 | - whacko method of setting IRedirectAfterPost on the Request. |
294 | - |
295 | - See examples/tests/testformless.py and the /formless_redirector |
296 | - on the example server to see how to do this. |
297 | - |
298 | - * There is now livetest coverage of the formless examples, |
299 | - including posting forms and checking erroneous conditions. |
300 | - |
301 | -2005-07-06 Donovan Preston <dp@divmod.org> |
302 | - |
303 | - * Major non-backwards-compatible improvements to livepage. Changes |
304 | - are designed to avoid an uncollectable garbage problem which was |
305 | - inherent in the previous design. |
306 | - |
307 | - The livepage javascript glue now includes a global object named |
308 | - "server". This object has a "handle" method which takes at least |
309 | - one argument, a string indicating the name of the handler to |
310 | - invoke on the server. When called by client-side javascript, |
311 | - LivePage.locateHandler is invoked. locateHandler should return |
312 | - a callable which will be called with a context indicating |
313 | - which client is invoking the method, and any additional arguments |
314 | - which were passed to server.handle, as strings. |
315 | - |
316 | - The default implementation of LivePage.locateHandler looks for |
317 | - a correspondingly named "handle_*" method. Using livepage is |
318 | - now as simple as subclassing LivePage and providing handle_* |
319 | - methods: |
320 | - |
321 | - class Foo(LivePage): |
322 | - def handle_bar(self, ctx, something): |
323 | - print "something!", something |
324 | - |
325 | - And calling server.handle in javascript: |
326 | - |
327 | - <a onclick="server.handle('bar', 'here is something')">Click me</a> |
328 | - |
329 | - The previous behavior of registering closures or other callables |
330 | - as event handlers and then embedding them in the page is still |
331 | - available using the IClientHandle.transient method. These one- |
332 | - shot handlers are only invokable by the client once before being |
333 | - garbage collected on the server. This makes it possible to |
334 | - implement temporary dialog boxes and the like. |
335 | - |
336 | -2005-04-09 Tommi Virtanen <tv@twistedmatrix.com> |
337 | - |
338 | - * Allow remembering ILogger to specify an alternate access logging |
339 | - method. |
340 | - |
341 | -2005-04-06 Matt Goodall <matt@pollenation.net> |
342 | - |
343 | - * Added optional context argument to Page's renderString and |
344 | - renderSynchronously methods. This provides a site-like context that is |
345 | - useful when rendering multiple pages that need common remembered data. |
346 | - |
347 | -2005-3-23 Donovan Preston <dp@divmod.org> |
348 | - |
349 | - * Releasing 0.4.1 |
350 | - |
351 | -2005-3-22 Donovan Preston <dp@divmod.org> |
352 | - |
353 | - * Releasing 0.4 |
354 | - |
355 | -2005-02-22 Matt Goodall <matt@pollenation.net> |
356 | - |
357 | - * Added a "data" renderer (rend.data) that replaces the tag's content |
358 | - with the current data. i.e. <p n:data="name" n:render="data">Foo Bar</p>. |
359 | - |
360 | -2005-02-17 Matt Goodall <matt@pollenation.net> |
361 | - |
362 | - * Added i18n - a gettext-like mechanism for marking translatable content |
363 | - in an application's Python modules by wrapping a string in _(). Standard |
364 | - Python gettext tools can be used to generate translation files. |
365 | - |
366 | - Translation happens during rendering and depends on a list of languages |
367 | - found in the context. By default, the browser's preferred languages are |
368 | - used. The default behaviour can be overridden by remembering the languages |
369 | - as inevow.ILanguages in the context; allowing the language to be selected |
370 | - from user preferences, for example. |
371 | - |
372 | -2005-02-08 Matt Goodall <matt@pollenation.net> |
373 | - |
374 | - * Extended the IDocFactory interface's load method to accept an optional |
375 | - context. |
376 | - |
377 | - The current loaders do not use the context but future loaders may, i.e. one |
378 | - that loads a localised template based on some language in the context. |
379 | - |
380 | -2005-01-01 Donovan Preston <dp@divmod.org> |
381 | - |
382 | - * Rewrote LivePage quoting code to be much more correct; added many unit |
383 | - tests. Some older livepage code must be changed to use the |
384 | - livepage.literal object instead of passing normal strings to handler or |
385 | - the LivePage client APIs. |
386 | - |
387 | - * Added nevow.livepage module, LivePage, and ILivePage. The name liveevil |
388 | - is deprecated. |
389 | - |
390 | -2004-12-23 Phil Frost <indigo@bitglue.com> |
391 | - |
392 | - * Added support for formless to return unicode objects. annotate.String |
393 | - and subclasses (Text, Password, etc.) take a 'unicode' parameter to |
394 | - enable unicode, like so: |
395 | - |
396 | - | annotate.String(unicode=True) |
397 | - |
398 | - The coerced value will then be a unicode object. |
399 | - |
400 | -2004-12-16 Matt Goodall <matt@pollenation.net> |
401 | - |
402 | - * Added ObjectContainer - a data directive accessor for retrieving an |
403 | - attribute of an object. If the current data in the context (the IData) is an |
404 | - object you can register ObjectContainer as the IContainer adapter for the |
405 | - object's class and Nevow will automatically look inside the object to fetch |
406 | - the attribute. |
407 | - |
408 | - Note: ObjectContainer is *not* registered as the adapter for all object |
409 | - types. You must explicitly register the adapter for application classes as |
410 | - needed. |
411 | - |
412 | -2004-12-08 Matt Goodall <matt@pollenation.net> |
413 | - |
414 | - * Applied the foom/mesozoic patch to make Page.remember work correctly and |
415 | - without the hack. You can now use the method reliably to remember objects at |
416 | - Page construction time or any other time before the PageContext is created. |
417 | - The remembered objects can be found from the context in the usual way. |
418 | - |
419 | - class MyPage(rend.Page): |
420 | - |
421 | - def __init__(self, original): |
422 | - # Make original available as ISomething(ctx) for later. |
423 | - self.remember(original, ISomething) |
424 | - rend.Page.__init__(self, original) |
425 | - |
426 | - * Added a similar remember method for NevowSite (and made a SiteContext |
427 | - object the ultimate parent). You can know remember objects on the site and |
428 | - have them available anywhere there's a context. A typical use case is making |
429 | - some object store available to the site. This was often achieved using a |
430 | - wrapper resource but now it's as easy as: |
431 | - |
432 | - store = makeStore() |
433 | - site = NevowSite(rootResource) |
434 | - site.remember(store, IStore) |
435 | - |
436 | -2004-12-08 Matt Goodall <matt@pollenation.net> |
437 | - |
438 | - * Renamed URL.fromRequest to URL.fromContext. URL.fromRequest was a little |
439 | - confusing - the URL it returned only included the segments that had been |
440 | - consumed so far by the locateChild process and not the whole URL as the name |
441 | - might suggest. Eventually, fromRequest will change to return a full URL but, |
442 | - for now, its use is deprecated. |
443 | - |
444 | - * Renamed URL.parent to URL.parentdir. URL.parent() was logically equivalent |
445 | - to '..' and so removed more segments than expected. URL.parent's use is now |
446 | - deprecated and in a future release will be changed to remove exactly one |
447 | - segment. |
448 | - |
449 | - * Improve URL.click to normalise any segments of '.' or '..'. Browsers |
450 | - normalise the URL so, according to the docstring, click should too. |
451 | - |
452 | -2004-12-04 Donovan Preston <dp@divmod.org> |
453 | - |
454 | - * Added macros! This is the same patch as the one I attached to my |
455 | - "Macros in Nevow" mail, with the addition of an IMacroFactory, |
456 | - a MacroFactory implementation on rend.Page, and macro directive |
457 | - support. Macros are like render functions that take only the |
458 | - context (no data parameter) and run only once during the lifetime |
459 | - of a template loader. Here is an example of the difference between |
460 | - a macro and a renderer: |
461 | - |
462 | - >>> class Bumper(object): |
463 | - ... num = 0 |
464 | - ... def bump(self): |
465 | - ... self.num += 1 |
466 | - ... return self.num |
467 | - ... |
468 | - >>> staysTheSame = Bumper() |
469 | - >>> changes = Bumper() |
470 | - >>> from nevow import flat, tags, loaders |
471 | - >>> document = loaders.stan([tags.invisible(macro=lambda ctx: staysTheSame.bump()), tags.invisible(render=lambda ctx, data: changes.bump())]) |
472 | - >>> flat.flatten(document) |
473 | - '11' |
474 | - >>> flat.flatten(document) |
475 | - '12' |
476 | - >>> flat.flatten(document) |
477 | - '13' |
478 | - |
479 | -2004-12-01 Donovan Preston <dp@divmod.org> |
480 | - |
481 | - * Added __iter__ to nevow.stan.slot to prevent infinite loops by |
482 | - trying to do "for x in slot('foo'): print x". |
483 | - |
484 | - * Added an IGettable adapter for nevow.stan.slot. It is now possible |
485 | - to specify a slot as the data for a node, so the following example |
486 | - would work: |
487 | - |
488 | - from nevow import rend, tags |
489 | - |
490 | - def fillEm(ctx, data): |
491 | - ctx.fillSlots('value', [1, 2]) |
492 | - return ctx.tag |
493 | - |
494 | - tags.html(render=fillEm)[ |
495 | - tags.ul(data=tags.slot('value'), render=rend.sequence)[ |
496 | - tags.li(pattern='item')[ |
497 | - str ]]] |
498 | - |
499 | -2004-09-26 Donovan Preston <dp@divmod.org> |
500 | - |
501 | - * Added nevow.inevow.IQ interface, an interface for querying the |
502 | - stan DOM. Eventually, this interface will contain APIs for doing |
503 | - traditional DOM introspection, such as iterating children, |
504 | - examining tag names, and examining attributes. For now, it contains |
505 | - only the patternGenerator, onePattern, and allPatterns APIs. These |
506 | - APIs have been deprecated from Context. |
507 | - |
508 | - The main benefit of this is the ability to do: |
509 | - |
510 | - IQ(loaders.xmlfile(...)).patternGenerator(...) |
511 | - |
512 | - which would be nice for creating "pattern library" files containing |
513 | - common skin idioms which can then be copied and used throughout |
514 | - the app. |
515 | - |
516 | -2004-09-25 Donovan Preston <dp@divmod.org> |
517 | - |
518 | - * Chatola received a major facelift, bringing it from cool demo |
519 | - up to almost a full fledged web-based chat server. The helper API |
520 | - LiveEvil.call(...) was added, which deprecates |
521 | - LiveEvil.sendScript(callJS(...)) |
522 | - |
523 | -2004-09-23 Tommi Virtanen <tv@twistedmatrix.com> |
524 | - |
525 | - * Make guard.SessionWrapper store its URL location in all requests it |
526 | - passes to its children. This allows the children know where to post |
527 | - the __login__ and __logout__ forms, even deep inside the resource |
528 | - tree (fixes issue59). |
529 | - |
530 | - * Guard now works as a non-root resource, with help from the above |
531 | - change. Semantics of __login__ clarified in unit tests; if your guard |
532 | - is at /foo, posting to /foo/__login__ redirects to /foo, and posting |
533 | - to /foo/__login__/ redirects to /foo/. The two unit tests that failed |
534 | - earlier now pass (with that change in their __login__ URLs). |
535 | - |
536 | - * If URL-based sessions are used, login no longer loses session |
537 | - information due to redirect to / (fixes issue56). |
538 | - |
539 | -2004-09-20 Matt Goodall <matt@pollenation.net> |
540 | - |
541 | - * Added URL.secure() method to make switching between http and |
542 | - https easier. |
543 | - |
544 | -2004-09-08 Donovan Preston <dp@divmod.org> |
545 | - |
546 | - * Nevow now includes a very simple proof-of-concept WSGI Application |
547 | - implementation, and can be used with no Twisted dependency. Nevow can |
548 | - also be used to write CGIs, either using a simple CGI WSGI gateway |
549 | - (which supports URL traversal), or by using Page.renderString (which does not). |
550 | - |
551 | - * Two new context interfaces, ICurrentSegments and IRemainingSegments, |
552 | - replace the need to examine the Request prepath and postpath attributes |
553 | - directly. |
554 | - |
555 | - * ISerializable is deprecated, and has been replaced with a simple |
556 | - Flattener registry. nevow.flat.registerFlattener and |
557 | - nevow.flat.getFlattener have been added to support this. |
558 | - |
559 | -2004-09-06 Donovan Preston <dp@divmod.org> |
560 | - |
561 | - * BACKWARDS INCOMPATIBLE CHANGE. Page.configurable_ *always* returns |
562 | - self, and a new Page.configurable_original *always* returns |
563 | - self.original. If you were relying on Page.configurable_'s |
564 | - introspection behavior and are now getting errors about adapting |
565 | - to IConfigurable, change your renderForms() calls to: |
566 | - |
567 | - renderForms('original') |
568 | - |
569 | - This causes Page.configurable_original to be invoked and |
570 | - introspected for form rendering. |
571 | - |
572 | -2004-08-23 Donovan Preston <dp@divmod.org> |
573 | - |
574 | - * LivePage uses a simpler implementation strategy which requires |
575 | - the browser to make one request per output event. As a result, |
576 | - LivePage now works on Mozilla, Safari, and Internet Explorer Windows. |
577 | - |
578 | -2004-08-05 Donovan Preston <dp@divmod.org> |
579 | - |
580 | - * Implemented support for IFoo(ctx) synonym syntax. It does the |
581 | - same thing as ctx.locate(IFoo) |
582 | - |
583 | - * Removed Resource Generators, a feature of NevowSite that nobody |
584 | - used and wasn't really useful. |
585 | - |
586 | - * Changed all inevow.IResource apis to take a Context object |
587 | - where they used to take the request. Remembering objects in |
588 | - PageContexts is now much easier, and fewer hacks are required to |
589 | - build the context chain. The context chain now looks like: |
590 | - |
591 | - SiteContext->RequestContext->PageContext(s)->WovenContext(s) |
592 | - |
593 | -2004-7-28 Donovan Preston <dp@divmod.org> |
594 | - |
595 | - * Parameterize data_* methods in the same way as render_* methods. |
596 | - Patch by k3mper. |
597 | - |
598 | - For example, <div nevow:data="foo bar,baz" /> will cause |
599 | - data_foo(self, bar, baz) to be called with the strings "bar" and |
600 | - "baz". This data method should return a callable taking ctx, data. |
601 | - The return value of this callable will be remembered as IData at |
602 | - this point in the context stack. |
603 | - |
604 | - * Added list-slicing support to ListContainer. You may now use |
605 | - list slicing syntax in a data directive in addition to a simple |
606 | - index. For example: |
607 | - |
608 | - def data_aList(self, ctx, data): |
609 | - return ["Buckle", "My", "Shoe"] |
610 | - |
611 | - <div nevow:data="aList"> |
612 | - <span nevow:data="1:-1" nevow:render="string" /> |
613 | - </div> |
614 | - |
615 | - Will render as <div><span>My</span></div> |
616 | - |
617 | -2004-7-20 Matt Goodall <matt@pollenation.net> |
618 | - |
619 | - * Modified sax loader to retain doctypes, comments and xmlns attributes. |
620 | - It's now possible to build XHTML valid pages :). |
621 | - |
622 | - xmlns attributes are always kept but there are options to ignore the doctype |
623 | - and comment (at the request of foom, not sure why yet). Right now, the default |
624 | - is to retain doctypes and comments but you can use the ignoreDocType and |
625 | - ignoreComment args to the xml loaders and flatsax parse functions. This bit |
626 | - may change. |
627 | - |
628 | - * Add a URL -> IResource adapter that performs a HTTP redirect. URLs can then |
629 | - be returned from locateChild(). |
630 | - |
631 | -2004-06-07 Donovan Preston <dp@divmod.org> |
632 | - |
633 | - * Added nevow.canvas, an experimental module similar to LivePage |
634 | - which provides a Python server-side API for drawing arbitrary lines, |
635 | - curves, and text in the browser. The implementation is socket-based |
636 | - and asynchronous, so the server can issue drawing commands to the |
637 | - client at any time. |
638 | - |
639 | - The idea is to provide a server-side API to the Python programmer |
640 | - and shield them from implementation details, but the current |
641 | - implementation uses a pre-compiled Flash movie (which never changes; |
642 | - we are not generating Flash bytecodes). An implementation using SVG |
643 | - or Safari's Canvas (nevow.canvas was written before the Safari Canvas |
644 | - announcement) would be possible. |
645 | - |
646 | -2004-05-26 Donovan Preston <dp@divmod.org> |
647 | - |
648 | - * Add URLOverlay.keep, an API which lets you specify which query args |
649 | - will be carried on from the current page render into the new URL. |
650 | - |
651 | -2004-05-24 Matt Goodall <matt@pollenation.net> |
652 | - |
653 | - * Extracted Fragment from Page. Hopefully, it will make it more obvious |
654 | - that embedding an object with data_ and render_ methods in a stan tree is |
655 | - possible without using something as "heavy" as Page which is really meant |
656 | - to be a web resource. |
657 | - |
658 | -2004-05-23 Donovan Preston <dp@divmod.org> |
659 | - |
660 | - * Added some useful APIs to LiveEvil for manipulating the client-side |
661 | - page: |
662 | - |
663 | - - flt(stan): Flatten some stan, quoting apostrophes as |
664 | - as appropriate for embedding in javascript |
665 | - |
666 | - - set(what, to): Set the contents of the client-side node |
667 | - with the id 'what' to the stan 'to'. |
668 | - |
669 | - - append(where, what): Append the stan 'what' to the client- |
670 | - side node with the id 'where' |
671 | - |
672 | - - alert(what): Show an alert to the user with the text "what" |
673 | - |
674 | -2004-05-19 Jonathan Simms <slyphon@divmod.com> |
675 | - |
676 | - * 0.2 released. |
677 | - |
678 | -2004-05-14 Donovan Preston <dp@divmod.org> |
679 | - |
680 | - * nevow.url.URLPath is renamed nevow.url.URL |
681 | - |
682 | - * URL objects are now lazier about casting things to strings; they will |
683 | - keep track of path segments in a list and defer to the nevow rendering |
684 | - machinery to do the conversion; This means you can do things like |
685 | - here.child(deferred) or here.child(function) |
686 | - |
687 | - * URL objects have a better api for manipulating query arguments |
688 | - - add(key, value=None) adds a new query arg at the end; the value may |
689 | - be None if only a query key needs to be added |
690 | - - replace(key, value) removes all occurrences of 'key' and inserts a |
691 | - new (key, value) at the same location as the previous first |
692 | - occurrence of key |
693 | - - clear() clears all args |
694 | - |
695 | -2004-05-06 Donovan Preston <dp@divmod.org> |
696 | - |
697 | - * Merged freeform-patterned branch, a large formless/freeform refactor. |
698 | - It is now possible to influence the rendering of forms by providing |
699 | - "patterns" to renderForms. |
700 | - |
701 | - * Formless is now a top-level package. Freeform has been renamed |
702 | - formless.webform. It should be possible to use formless outside |
703 | - the context of nevow for doing things such as validating network |
704 | - input based on method argument type annotations. |
705 | - |
706 | - * TypedInterface, autocallable, and all the Typed subclasses are now |
707 | - in the formless.annotate module. |
708 | - |
709 | -2004-04-30 Donovan Preston <dp@divmod.org> |
710 | - |
711 | - * Created nevow.blocks, a module containing helpful code for working |
712 | - around display: inline-block bugs in Mozilla. |
713 | - |
714 | -2004-04-27 Donovan Preston <dp@divmod.org> |
715 | - |
716 | - * IRenderer.__call__ was renamed IRenderer.rend to be more explicit. |
717 | - |
718 | -2004-04-21 Donovan Preston <dp@divmod.org> |
719 | - |
720 | - * Implemented nevow.flat.flatten and nevow.flat.precompile, functions |
721 | - useful for using stan outside of the context of Page classes. Useful |
722 | - for generating some XML or even raw text; use it any time you want |
723 | - to convert a tree data structure into a contiguous string! |
724 | - |
725 | - import random |
726 | - import string |
727 | - |
728 | - from nevow import flat |
729 | - |
730 | - def letters(howMany): |
731 | - for i in range(howMany): |
732 | - yield ' ', string.letters[i], '\n' |
733 | - |
734 | - def outline(): |
735 | - for i in range(5): |
736 | - yield i, '\n' |
737 | - yield letters(random.choice(range(7))) |
738 | - yield '\n' |
739 | - |
740 | - print flat.flatten(outline()) |
741 | - |
742 | -2004-04-20 Donovan Preston <dp@divmod.org> |
743 | - |
744 | - * guard sessions are no longer required to use formless. |
745 | - |
746 | -2004-04-19 Donovan Preston <dp@divmod.org> |
747 | - |
748 | - * Implemented lazy context factories. It is now possible to register |
749 | - an adapter against various *Context classes and an interface. They |
750 | - will be invoked if *Context.locate(interface) is called. |
751 | - |
752 | - Implemented a lazy ISession adapter against RequestContext, making |
753 | - it possible to do ctx.locate(ISession), which is nice. |
754 | - |
755 | -2004-04-16 Donovan Preston <dp@divmod.org> |
756 | - |
757 | - * Added nevow.entities module, a module containing literals for all of |
758 | - the valid XHTML entities. For example: |
759 | - |
760 | - def render_nbsp(self, ctx, data): |
761 | - from nevow import entities |
762 | - return entities.nbsp |
763 | - |
764 | |
765 | === removed file 'Nevow/LICENSE' |
766 | --- Nevow/LICENSE 2005-10-14 17:36:24 +0000 |
767 | +++ Nevow/LICENSE 1970-01-01 00:00:00 +0000 |
768 | @@ -1,35 +0,0 @@ |
769 | -Copyright (c) 2004 |
770 | -Donovan Preston |
771 | -Matt Goodall |
772 | -James Y. Knight |
773 | -Glyph Lefkowitz |
774 | -JP Calderone |
775 | -Allen Short |
776 | -Alex Levy |
777 | -Justin Johnson |
778 | -Christopher Armstrong |
779 | -Jonathan Simms |
780 | -Phil Frost |
781 | -Tommi Virtanen |
782 | -Michal Pasternak |
783 | -Valentino Volonghi |
784 | - |
785 | - |
786 | -Permission is hereby granted, free of charge, to any person obtaining |
787 | -a copy of this software and associated documentation files (the |
788 | -"Software"), to deal in the Software without restriction, including |
789 | -without limitation the rights to use, copy, modify, merge, publish, |
790 | -distribute, sublicense, and/or sell copies of the Software, and to |
791 | -permit persons to whom the Software is furnished to do so, subject to |
792 | -the following conditions: |
793 | - |
794 | -The above copyright notice and this permission notice shall be |
795 | -included in all copies or substantial portions of the Software. |
796 | - |
797 | -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
798 | -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
799 | -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
800 | -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
801 | -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
802 | -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
803 | -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
804 | |
805 | === removed file 'Nevow/MANIFEST.in' |
806 | --- Nevow/MANIFEST.in 2010-04-06 11:05:45 +0000 |
807 | +++ Nevow/MANIFEST.in 1970-01-01 00:00:00 +0000 |
808 | @@ -1,24 +0,0 @@ |
809 | -include ChangeLog |
810 | -include LICENSE |
811 | -include zomne.c |
812 | -include formless/freeform-default.css |
813 | -include nevow/Canvas.swf |
814 | -include nevow/athena_private/*.png |
815 | -include debian/* |
816 | -recursive-include twisted *.py |
817 | -recursive-include nevow *.css *.js |
818 | -include bin/nevow-xmlgettext |
819 | -graft doc |
820 | -recursive-include examples *.css *.gif *.html *.jpg *.js *.py *.png *.tac *.mo *.po *.pot *.xml *.sql *.xul |
821 | -include examples/i18n/update-l10n |
822 | -include examples/files/words |
823 | -include examples/pastebin/data |
824 | -include examples/pastebin/static/robots.txt |
825 | -include examples/pastebin/TODO |
826 | -include examples/wsgi/README |
827 | -include extras/xhtml-nevow.rnc |
828 | -include nevow/Canvas.fla |
829 | -include nevow/canvas.as |
830 | -include win32/* |
831 | -prune */.svn |
832 | -prune doc/html/*.html |
833 | |
834 | === removed file 'Nevow/NEWS.txt' |
835 | --- Nevow/NEWS.txt 2009-11-30 01:08:55 +0000 |
836 | +++ Nevow/NEWS.txt 1970-01-01 00:00:00 +0000 |
837 | @@ -1,244 +0,0 @@ |
838 | -0.10.0 (2009-11-25): |
839 | - - Added a system for CSS dependency declarations similar to the one in |
840 | - Athena for JavaScript. |
841 | - - Fix Athena's transport cleanup on page unload in Internet Explorer. |
842 | - - Fix nit's results coloring in Internet Explorer. |
843 | - - Added an API for declaring JavaScript classes which involves less |
844 | - repetition than the existing Divmod.Class.subclass API. |
845 | - - Added human-readable formatting for the new flattener's error reporting; |
846 | - rendering error stacks will now display lines from Python code as well |
847 | - as stan and XML templates. |
848 | - - Override the setuptools sdist command with the original distutils sdist |
849 | - command to avoid setuptools' version number transformation. |
850 | - - Added support for default values for slots in XML templates. |
851 | - - Fixed a problem with setup.py which led to css files not being |
852 | - installed. |
853 | - - Removed the old Chatola example and replaced it with a link to the new |
854 | - chat example. |
855 | - - Sped up some of the JavaScript dependency calculations. |
856 | - |
857 | -0.9.33 (2008-12-09): |
858 | - - Add error handling to the integration between the old flattener |
859 | - and the new flattener so that if the new flattener fails with an |
860 | - exception or a Failure the error is propagated properly to the old |
861 | - flattener which invoked it. |
862 | - - Changed nit so that it doesn't use private `twistd` APIs and |
863 | - instead just sets up a server and runs the reactor. This makes |
864 | - nit work with all versions of Twisted supported by Nevow. |
865 | - - Changed Nevow's setup.py to use setuptools if setuptools is |
866 | - available. This has the user-facing consequence of installing |
867 | - Nevow as an egg if setuptools is available at installation time |
868 | - and of making Nevow installable using the `easy_install´ tool. |
869 | - - TabbedPane naively set DOM attributes, making it unusable in |
870 | - Internet Explorer 6 and 7. Introduced a reliable method for |
871 | - setting DOM node attributes, with name mangling, to address the |
872 | - issue. |
873 | - |
874 | -0.9.32 (2008-08-12): |
875 | - - A resource wrapper for on-the-fly gzip compression has been added. |
876 | - - A twistd plugin, 'athena-widget', is now available for serving |
877 | - single Athena widgets. |
878 | - - Basic Athena support for Safari added. |
879 | - - Added file name, line number, and column number information to |
880 | - slots and tags parsed from XML files in order to make debugging |
881 | - template/renderer interactions simpler. |
882 | - - A context-free flattener has been added. Fragment and its |
883 | - subclasses are now deprecated in favor of Element. |
884 | - - Javascript classes derived from the tabbedpane class can now |
885 | - override how tab selection is handled. |
886 | - |
887 | -0.9.31 (2008-02-06): |
888 | - - Fixed Guard's request parameter save/restore feature to not |
889 | - clobber request state after login succeeds when a session has |
890 | - already been negotiated. |
891 | - - Added a hook to nevow.guard.SessionWrapper which allows the |
892 | - domain parameter of the session cookie to be specified. |
893 | - |
894 | -0.9.30 (2008-01-16): |
895 | - - Change DeferredSerializer so that it passes failures from the |
896 | - Deferred being serialized on to the Deferred returned by the |
897 | - flattening function. Without this behavior, the Deferred |
898 | - returned by the flattening function is never fired when a |
899 | - Deferred which fails is serialized. |
900 | - |
901 | -0.9.29 (2008-01-02): |
902 | - - Prevent NevowSite.handleSegment from raising IndexError in certain |
903 | - situations. |
904 | - - Deprecated wsgi and zomne modules. |
905 | - |
906 | -0.9.28 (2007-12-10): |
907 | - - Added two APIs to Athena, one for creating the string used as the id |
908 | - attribute of the top node of a widget and one for creating the string |
909 | - used as the id attribute of a node which had an id attribute in the |
910 | - widget's template document. |
911 | - |
912 | -0.9.27 (2007-11-27): |
913 | - - Unicode URLs now supported. |
914 | - |
915 | -0.9.26 (2007-11-02): |
916 | - - url.URL.path now correctly escapes segments in the string it |
917 | - evaluates to. |
918 | - - inevow.IAthenaTransportable added, along with support for |
919 | - serialization of custom types for server-to-client Athena |
920 | - messages. |
921 | - - Global client-side behaviour is now customizable via a client |
922 | - PageWidget class. |
923 | - |
924 | -0.9.25 (2007-10-16): |
925 | - - The Athena message queue implementation has been improved, fixing problems |
926 | - masked by bugs in Firebug/YSlow. |
927 | - |
928 | -0.9.24 (2007-09-05): |
929 | - - ESC key no longer disconnects Athena connections. |
930 | - - Fixed a bug where URLs with quote characters will cause the Athena |
931 | - connection to be lost. |
932 | - - Fixed 'twistd athena-widget' to create a fresh widget instance for each |
933 | - hit. |
934 | - |
935 | -0.9.23 (2007-08-01): |
936 | - - Fixed install script to include all JavaScript files. |
937 | - |
938 | -0.9.22 (2007-07-06): |
939 | - - Mock DOM implementation for easier browser testing added. |
940 | - - JavaScript source files are now read using universal newlines mode. |
941 | - - athena.AutoJSPackage now excludes dotfiles. |
942 | - - url.URL now properly subclassable. |
943 | - - User-agent parsing added to Athena, to detect known-unsupported browsers. |
944 | - |
945 | -0.9.21 (2007-06-06): |
946 | - - Debug logging messages from the reliable message delivery queue |
947 | - disabled. |
948 | - |
949 | -0.9.20 (2007-05-24): |
950 | - - Athena now no longer holds more than one idle transport open to |
951 | - the browser. |
952 | - |
953 | -0.9.19 (2007-04-27): |
954 | - - Changed the styling of the progressbar to work on IE6. |
955 | - - Athena.Widget.detach added, to allow widgets to cleanly be removed |
956 | - from a page. |
957 | - - Athena.Widget.callLater added, a wrapper around setTimeout and |
958 | - clearTimeout. |
959 | - - 'athena-widget' twistd command added, for starting a server which |
960 | - serves a single LiveFragment or LiveElement. |
961 | - |
962 | -0.9.18 (2007-02-23): |
963 | - - Athena 'connection lost' notification now styleable via the |
964 | - 'nevow-connection-lost' CSS class. |
965 | - - The 'runjstests' script has been removed, now that JS tests can be |
966 | - run with trial. |
967 | - |
968 | -0.9.17 (2006-12-08): |
969 | - - More efficient JSON string parsing. |
970 | - - Give FakeRequests a default status code of OK. Accept all of |
971 | - FakeRequest.__init__'s arguments in the __init__ of |
972 | - AccumulatingFakeRequest. |
973 | - |
974 | -0.9.16 (2006-11-17): |
975 | - - Updated nit to work with Twisted trunk. |
976 | - - Athena module import caching has been fixed. |
977 | - |
978 | -0.9.15 (2006-11-08): |
979 | - - Changed _LiveMixin rendering to be idempotent to support the case |
980 | - where a transport hiccup causes a LiveFragment or LiveElement to |
981 | - be sent to the browser multiple times. |
982 | - - Improvements to the tests. |
983 | - |
984 | -0.9.14 (2006-10-31): |
985 | - - Support code for running non-browser javascript tests has been added. |
986 | - - Added a workaround for nodeById on widgets not yet added to the document in |
987 | - IE. |
988 | - - Athena will now invoke the nodeInserted method (if it exists) on a widget |
989 | - that it instantiates statically. |
990 | - - ID rewriting, similar to existing rewriting support for 'id' attributes, |
991 | - has been added in 'for' and 'headers' attributes of 'label' and 'td'/'th' |
992 | - elements, respectively. |
993 | - |
994 | -0.9.13 (2006-10-21): |
995 | - - Adjust non-selected panes in tabbedpane to be further out of the viewport. |
996 | - - Convert to using the Javascript module plugin system for Nevow-provided |
997 | - modules. |
998 | - |
999 | -0.9.12 (2006-10-17): |
1000 | - - Added id rewriting for LiveElement and LiveFragment, such that id |
1001 | - attributes in a widget template are rewritten so that they are unique to |
1002 | - the widget instance. A client-side API, Nevow.Athena.Widget.nodeById(), |
1003 | - is provided to allow location of these nodes. |
1004 | - |
1005 | -0.9.11 (2006-10-10): |
1006 | - - Fixed dynamic widget instantiation in IE. |
1007 | - - Added support for correctly quoting the values of slots which are used as |
1008 | - attributes. |
1009 | - |
1010 | -0.9.10 (2006-10-05): |
1011 | - - Minor update to nevow.testutil. |
1012 | - |
1013 | -0.9.9 (2006-09-26): |
1014 | - - Several nit changes, including the addition of the "check" method to |
1015 | - Failure, and the addition of an "assertFailure" method. |
1016 | - - The ability to pass Python exceptions to Javascript has been added to |
1017 | - Athena. |
1018 | - - Dynamic module import has been added for the cases where it is necessary |
1019 | - to dynamically add a widget to an existing page. |
1020 | - |
1021 | -0.9.8 (2009-09-20): |
1022 | - - A bug in nit that caused it to fail if there were too many tests in a |
1023 | - test case, and swallow failures in some cases, has been fixed. |
1024 | - - Widgets can no longer be added to a page after render time using |
1025 | - Divmod.Runtime.Platform.{set,append}NodeContent. Instead, they must be |
1026 | - added using Nevow.Athena.Widget.addChildWidgetFromWidgetInfo. |
1027 | - |
1028 | -0.9.7 (2009-09-12): |
1029 | - - Automatic Athena event handler registration is fixed for all supported browsers |
1030 | - and is no longer document-sensitive (ie, it works inside tables now). |
1031 | - - Nit has gained a new assertion method, assertIn. |
1032 | - |
1033 | -0.9.6 (2008-08-30): |
1034 | - - Fixed a bug in the IE implementation of the runtime.js node fetching |
1035 | - functions. |
1036 | - |
1037 | -0.9.5 (2006-08-22): |
1038 | - - Instance attributes can now be exposed to Athena with nevow.utils.Expose |
1039 | - and Expose.exposedMethodNames() no longer returns unexposed names. |
1040 | - |
1041 | -0.9.4 (2006-08-14): |
1042 | - - Added test method discovery to nit test cases, so multiple test methods |
1043 | - may be put in a single test case. |
1044 | - - use XPath for certain DOM traversals when available. This yields |
1045 | - significant speedups on Opera. |
1046 | - - Made Divmod.Runtime.Platform.getAttribute deal with IE attribute |
1047 | - name-mangling properly. |
1048 | - - Javascript logging is now done in Firebug 0.4 style rather than 0.3. |
1049 | - - Some cases where Deferred-returning render methods raised |
1050 | - exceptions or buried failures were fixed. |
1051 | - - Removed MochiKit. The pieces Nevow depends on have been moved to |
1052 | - Divmod.Base in nevow/base.js. |
1053 | - - Various doc fixes. |
1054 | - |
1055 | -0.9.3 (2006-07-17): |
1056 | - - Page rendering now supports preprocessors. |
1057 | - |
1058 | -0.9.2 (2006-07-08): |
1059 | - - Fixes to the typeahead demo. |
1060 | - - Elements are now automatically serialized by json, just like Fragments. |
1061 | - |
1062 | -0.9.1 (2006-07-05): |
1063 | - - Made nevow.athena.expose the mandatory means of publishing a method to |
1064 | - the browser. The allowedMethods dictionary will no longer be respected. |
1065 | - - Added nevow.page.Element and nevow.athena.LiveElement: these are |
1066 | - preferred over nevow.rend.Fragment and nevow.athena.LiveFragment for all |
1067 | - new development. |
1068 | - |
1069 | -0.9.0 (2006-06-12): |
1070 | - - Fixed a bug where nested fragment sending rarely worked. |
1071 | - - Sending large strings in Athena arguments and results is now faster due to |
1072 | - less unnecessary unicode character quoting. |
1073 | - - Module objects are now automatically created for all Athena imports. |
1074 | - - Better error reporting for fragments which are rendered without a parent. |
1075 | - - Disconnect notifiers in Athena pages will no longer clobber each other. |
1076 | - - Many optimizations to javascript initialization. |
1077 | - - Javascript packages are now defined with less boilerplate: a filesystem |
1078 | - convention similar to Python's for module naming, plus one declaration in a |
1079 | - Nevow plugin which indicates the directory, rather than a declaration for |
1080 | - each module. |
1081 | - - Updated README to refer to Athena rather than LivePage |
1082 | |
1083 | === removed file 'Nevow/README' |
1084 | --- Nevow/README 2006-06-14 11:54:41 +0000 |
1085 | +++ Nevow/README 1970-01-01 00:00:00 +0000 |
1086 | @@ -1,69 +0,0 @@ |
1087 | - |
1088 | -Divmod Nevow |
1089 | -============ |
1090 | - |
1091 | -Divmod Nevow is a web application construction kit written in Python. It is |
1092 | -designed to allow the programmer to express as much of the view logic as |
1093 | -desired in Python, and includes a pure Python XML expression syntax named stan |
1094 | -to facilitate this. However it also provides rich support for designer-edited |
1095 | -templates, using a very small XML attribute language to provide bi-directional |
1096 | -template manipulation capability. |
1097 | - |
1098 | -Nevow also includes Divmod Athena, a "two way web" or "`COMET`_" |
1099 | -implementation, providing a two-way bridge between Python code on the server |
1100 | -and JavaScript code on the client. Modular portions of a page, known as |
1101 | -"athena fragments" in the server python and "athena widgets" in the client |
1102 | -javascript, can be individually developed and placed on any Nevow-rendered page |
1103 | -with a small template renderer. Athena abstracts the intricacies of HTTP |
1104 | -communication, session security, and browser-specific bugs behind a simple |
1105 | -remote-method-call interface, where individual widgets or fragments can call |
1106 | -remote methods on their client or server peer with one method: "callRemote". |
1107 | - |
1108 | -Installation |
1109 | ------------- |
1110 | - |
1111 | -Before installing Nevow, you should install `Twisted`_, unless you are going to |
1112 | -write very simple CGI applications. Nevow integrates fully with the twisted.web |
1113 | -server providing easy deployment. |
1114 | - |
1115 | -Nevow uses the standard distutils method of installation:: |
1116 | - |
1117 | - python setup.py install |
1118 | - |
1119 | -If you do not have Twisted installed, you can run a subset of the tests using |
1120 | -the test.py script. If you have twisted installed, the test.py script will |
1121 | -issue the following trial command:: |
1122 | - |
1123 | - trial -v nevow.test formless.test |
1124 | - |
1125 | -.. _`Twisted`: http://twistedmatrix.com/ |
1126 | - |
1127 | -Documentation |
1128 | -------------- |
1129 | - |
1130 | -More detailed introductory documentation is available in the doc/ directory, |
1131 | -along with the beginnings of a reference manual. A large number of examples are |
1132 | -available in the examples/ directory. These examples require Twisted to run. A |
1133 | -tac file (twisted application configuration) can be started by invoking twistd, |
1134 | -the twisted daemon:: |
1135 | - |
1136 | - twistd -noy foo.tac |
1137 | - |
1138 | -More Information |
1139 | ----------------- |
1140 | - |
1141 | -Nevow is an active project, and many new bugfixes and features are committed to |
1142 | -the Nevow SVN repository. Information about Nevow commits is available by |
1143 | -subscribing to the `Nevow commits`_ mailing list. The Nevow SVN repository can |
1144 | -be checked out using:: |
1145 | - |
1146 | - svn co http://divmod.org/svn/Divmod/trunk/Nevow Nevow |
1147 | - |
1148 | -Discussion of Nevow occurs on the `twisted.web mailing list`_. The Nevow |
1149 | -developers are also often available for real-time help on the `#twisted.web |
1150 | -channel`_ on irc.freenode.net. |
1151 | - |
1152 | -.. _`Nevow commits`: http://divmod.org/users/mailman.twistd/listinfo/nevow-commits |
1153 | -.. _`twisted.web mailing list`: http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-web |
1154 | -.. _`#twisted.web channel`: irc://irc.freenode.net/#twisted.web |
1155 | -.. _`COMET`: http://alex.dojotoolkit.org/?p=545 |
1156 | |
1157 | === removed directory 'Nevow/benchmarks' |
1158 | === removed file 'Nevow/benchmarks/fragmentvselement.py' |
1159 | --- Nevow/benchmarks/fragmentvselement.py 2008-05-22 18:46:50 +0000 |
1160 | +++ Nevow/benchmarks/fragmentvselement.py 1970-01-01 00:00:00 +0000 |
1161 | @@ -1,147 +0,0 @@ |
1162 | - |
1163 | -from twisted.internet import reactor |
1164 | -from twisted.internet.defer import succeed |
1165 | - |
1166 | -from nevow.appserver import NevowSite |
1167 | - |
1168 | -from nevow.rend import Page, Fragment |
1169 | -from nevow.page import Element, renderer |
1170 | -from nevow.loaders import stan |
1171 | -from nevow.tags import directive, div, span |
1172 | - |
1173 | - |
1174 | -class Static: |
1175 | - docFactory = stan("Hello, world. " * 100) |
1176 | - |
1177 | - |
1178 | - |
1179 | -class StaticFragment(Static, Fragment): |
1180 | - pass |
1181 | - |
1182 | - |
1183 | - |
1184 | -class StaticElement(Static, Element): |
1185 | - pass |
1186 | - |
1187 | - |
1188 | - |
1189 | -class Tiny: |
1190 | - docFactory = stan(div(render=directive("foo"))) |
1191 | - |
1192 | - |
1193 | - |
1194 | -class TinyFragment(Tiny, Fragment): |
1195 | - def render_foo(self, ctx, data): |
1196 | - return ctx.tag[span["result"]] |
1197 | - |
1198 | - |
1199 | - |
1200 | -class TinyElement(Tiny, Element): |
1201 | - def foo(self, request, tag): |
1202 | - return tag[span["result"]] |
1203 | - renderer(foo) |
1204 | - |
1205 | - |
1206 | - |
1207 | -class Huge: |
1208 | - docFactory = stan(div[[ |
1209 | - div(render=directive("foo")) |
1210 | - for x in range(100)]]) |
1211 | - |
1212 | - |
1213 | - |
1214 | -class HugeFragment(Huge, Fragment): |
1215 | - def render_foo(self, ctx, data): |
1216 | - return ctx.tag[span["Hello, ", "world", "!"]] |
1217 | - |
1218 | - |
1219 | - |
1220 | -class HugeElement(Huge, Element): |
1221 | - def foo(self, request, tag): |
1222 | - return tag[span["Hello, ", "world", "!"]] |
1223 | - renderer(foo) |
1224 | - |
1225 | - |
1226 | - |
1227 | -class Nested: |
1228 | - docFactory = stan(div(render=directive("foo"))) |
1229 | - |
1230 | - def __init__(self, count=6): |
1231 | - self.count = count |
1232 | - |
1233 | - |
1234 | - |
1235 | -class NestedFragment(Nested, Fragment): |
1236 | - def render_foo(self, ctx, data): |
1237 | - if self.count: |
1238 | - return span[NestedFragment(self.count - 1)] |
1239 | - return ctx.tag["Hello"] |
1240 | - |
1241 | - |
1242 | - |
1243 | -class NestedElement(Nested, Element): |
1244 | - def foo(self, request, tag): |
1245 | - if self.count: |
1246 | - return span[NestedFragment(self.count - 1)] |
1247 | - return tag["Hello"] |
1248 | - renderer(foo) |
1249 | - |
1250 | - |
1251 | - |
1252 | -class Deferred: |
1253 | - docFactory = stan(div(render=directive('foo'))) |
1254 | - |
1255 | - |
1256 | - |
1257 | -class DeferredFragment(Deferred, Fragment): |
1258 | - def render_foo(self, ctx, data): |
1259 | - return ctx.tag[succeed("foo")] |
1260 | - |
1261 | - |
1262 | - |
1263 | -class DeferredElement(Deferred, Element): |
1264 | - def foo(self, request, tag): |
1265 | - return tag[succeed("foo")] |
1266 | - renderer(foo) |
1267 | - |
1268 | - |
1269 | - |
1270 | -class Compare(Page): |
1271 | - def __init__(self, fragment, element): |
1272 | - self.fragment = fragment |
1273 | - self.element = element |
1274 | - |
1275 | - def child_fragment(self, ctx): |
1276 | - return Page(docFactory=stan(self.fragment)) |
1277 | - |
1278 | - |
1279 | - def child_element(self, ctx): |
1280 | - return Page(docFactory=stan(self.element)) |
1281 | - |
1282 | - |
1283 | - |
1284 | -class Root(Page): |
1285 | - def child_static(self, ctx): |
1286 | - return Compare(StaticFragment(), StaticElement()) |
1287 | - |
1288 | - |
1289 | - def child_tiny(self, ctx): |
1290 | - return Compare(TinyFragment(), TinyElement()) |
1291 | - |
1292 | - |
1293 | - def child_huge(self, ctx): |
1294 | - return Compare(HugeFragment(), HugeElement()) |
1295 | - |
1296 | - |
1297 | - def child_nested(self, ctx): |
1298 | - return Compare(NestedFragment(), NestedElement()) |
1299 | - |
1300 | - |
1301 | - def child_deferred(self, ctx): |
1302 | - return Compare(DeferredFragment(), DeferredElement()) |
1303 | - |
1304 | - |
1305 | - |
1306 | -if __name__ == '__main__': |
1307 | - reactor.listenTCP(8080, NevowSite(Root())) |
1308 | - reactor.run() |
1309 | |
1310 | === removed file 'Nevow/benchmarks/json_string_tokenizer.py' |
1311 | --- Nevow/benchmarks/json_string_tokenizer.py 2006-11-24 23:15:26 +0000 |
1312 | +++ Nevow/benchmarks/json_string_tokenizer.py 1970-01-01 00:00:00 +0000 |
1313 | @@ -1,48 +0,0 @@ |
1314 | - |
1315 | -from time import time |
1316 | - |
1317 | -from twisted.python.usage import Options |
1318 | - |
1319 | -from nevow.json import serialize, parse |
1320 | - |
1321 | -if __name__ == '__main__': |
1322 | - from json_string_tokenizer import main |
1323 | - raise SystemExit(main()) |
1324 | - |
1325 | - |
1326 | - |
1327 | -class StringTokenizer(Options): |
1328 | - optParameters = [ |
1329 | - ('iterations', 'i', '1000', 'Number of iterations for which to run the benchmark.'), |
1330 | - ('scale', 's', '100', 'Factor determining the overall input size.')] |
1331 | - |
1332 | - |
1333 | - def postOptions(self): |
1334 | - self['iterations'] = int(self['iterations']) |
1335 | - self['scale'] = int(self['scale']) |
1336 | - |
1337 | - |
1338 | -BASE = u'Hello, world. "Quotes".' |
1339 | -def benchmark(iterations, scale): |
1340 | - """ |
1341 | - Deserialize a string C{iterations} times. Make the string longer based |
1342 | - on C{scale}. |
1343 | - |
1344 | - Prints the mean time per parse call. |
1345 | - """ |
1346 | - s = serialize(BASE * scale) |
1347 | - before = time() |
1348 | - for i in xrange(iterations): |
1349 | - parse(s) |
1350 | - after = time() |
1351 | - print (after - before) / iterations, 'per call' |
1352 | - |
1353 | - |
1354 | - |
1355 | -def main(args=None): |
1356 | - """ |
1357 | - Benchmark nevow.json string parsing, maybe with some parameters. |
1358 | - """ |
1359 | - options = StringTokenizer() |
1360 | - options.parseOptions(args) |
1361 | - benchmark(options['iterations'], options['scale']) |
1362 | |
1363 | === removed directory 'Nevow/bin' |
1364 | === removed file 'Nevow/bin/nevow-xmlgettext' |
1365 | --- Nevow/bin/nevow-xmlgettext 2005-10-14 17:36:24 +0000 |
1366 | +++ Nevow/bin/nevow-xmlgettext 1970-01-01 00:00:00 +0000 |
1367 | @@ -1,3 +0,0 @@ |
1368 | -#!/usr/bin/env python |
1369 | -from nevow.scripts.xmlgettext import run |
1370 | -run() |
1371 | |
1372 | === removed file 'Nevow/bin/nit' |
1373 | --- Nevow/bin/nit 2006-11-17 00:50:34 +0000 |
1374 | +++ Nevow/bin/nit 1970-01-01 00:00:00 +0000 |
1375 | @@ -1,3 +0,0 @@ |
1376 | -#!/usr/bin/python |
1377 | -from nevow.scripts.nit import run |
1378 | -run() |
1379 | |
1380 | === removed directory 'Nevow/debian' |
1381 | === removed file 'Nevow/debian/changelog' |
1382 | --- Nevow/debian/changelog 2005-11-06 18:46:50 +0000 |
1383 | +++ Nevow/debian/changelog 1970-01-01 00:00:00 +0000 |
1384 | @@ -1,56 +0,0 @@ |
1385 | -nevow (0.6.0-1.snapshot) unstable; urgency=low |
1386 | - |
1387 | - * SVN snapshot. |
1388 | - |
1389 | - -- Tommi Virtanen <tv@debian.org> Sun, 6 Nov 2005 20:45:27 +0200 |
1390 | - |
1391 | -nevow (0.6.0-1) unstable; urgency=low |
1392 | - |
1393 | - * New upstream version. (Closes: #336027) |
1394 | - * Acknowledge NMU (Closes: #319230), but please be more careful in the |
1395 | - future; no NMU patch was sent to BTS |
1396 | - * Remove setupcommon.pyc when cleaning, or dpkg-source will see a binary |
1397 | - file content change. |
1398 | - * Run unit tests when building. |
1399 | - * Clean build tree, distutils fails to remove all of it. |
1400 | - * Change priority to extra, as twisted is extra and nevow depends on it. |
1401 | - |
1402 | - -- Tommi Virtanen <tv@debian.org> Sun, 6 Nov 2005 20:26:39 +0200 |
1403 | - |
1404 | -nevow (0.4.1-1.1) unstable; urgency=low |
1405 | - |
1406 | - * NMU |
1407 | - * Add missing build depends in python2.4-dev (Closes: #319230) |
1408 | - * lintian error: fix package description indent for list items. |
1409 | - |
1410 | - -- Bastian Kleineidam <calvin@debian.org> Sat, 13 Aug 2005 18:48:20 +0200 |
1411 | - |
1412 | -nevow (0.4.1-1) unstable; urgency=low |
1413 | - |
1414 | - * New upstream version. |
1415 | - * Python 2.4 support. |
1416 | - * Not using upstream tarball as it is too broken compared to |
1417 | - SVN tag; specifically it is missing nevow/Canvas.fla, which |
1418 | - is considered source code. |
1419 | - |
1420 | - -- Tommi Virtanen <tv@debian.org> Mon, 27 Jun 2005 15:35:57 +0200 |
1421 | - |
1422 | -nevow (0.3.0-1) unstable; urgency=low |
1423 | - |
1424 | - * New upstream version. |
1425 | - |
1426 | - -- Tommi Virtanen <tv@debian.org> Thu, 30 Sep 2004 12:12:44 +0300 |
1427 | - |
1428 | -nevow (0.2.0-2) unstable; urgency=low |
1429 | - |
1430 | - * Build-depend on both python2.3-dev and python-dev, it seems that is |
1431 | - what cdbs wants. (Closes: #257911) |
1432 | - |
1433 | - -- Tommi Virtanen <tv@debian.org> Tue, 13 Jul 2004 16:39:17 +0300 |
1434 | - |
1435 | -nevow (0.2.0-1) unstable; urgency=low |
1436 | - |
1437 | - * Initial Release. |
1438 | - |
1439 | - -- Tommi Virtanen <tv@debian.org> Tue, 29 Jun 2004 10:26:36 +0300 |
1440 | - |
1441 | |
1442 | === removed file 'Nevow/debian/compat' |
1443 | --- Nevow/debian/compat 2005-10-14 17:36:24 +0000 |
1444 | +++ Nevow/debian/compat 1970-01-01 00:00:00 +0000 |
1445 | @@ -1,1 +0,0 @@ |
1446 | -4 |
1447 | |
1448 | === removed file 'Nevow/debian/control' |
1449 | --- Nevow/debian/control 2005-11-06 18:46:50 +0000 |
1450 | +++ Nevow/debian/control 1970-01-01 00:00:00 +0000 |
1451 | @@ -1,64 +0,0 @@ |
1452 | -Source: nevow |
1453 | -Section: devel |
1454 | -Priority: extra |
1455 | -Maintainer: Tommi Virtanen <tv@debian.org> |
1456 | -Standards-Version: 3.6.2 |
1457 | -Build-Depends-Indep: python-dev, python2.3-dev, python2.4-dev, cdbs, debhelper (>= 4.1.68) |
1458 | - |
1459 | -Package: python-nevow |
1460 | -Architecture: all |
1461 | -Depends: python (>= 2.3), python (<< 2.4), python2.3-nevow |
1462 | -Description: Web application templating system for Python and Twisted |
1463 | - This is a dummy package that only depends on python2.3-nevow. |
1464 | - |
1465 | -Package: python2.3-nevow |
1466 | -Architecture: all |
1467 | -Depends: python2.3, python2.3-twisted |
1468 | -Description: Web application templating system for Python and Twisted |
1469 | - Nevow's main focus is on separating the HTML template from both the |
1470 | - business logic and the display logic, while allowing the programmer |
1471 | - to write pure Python code as much as possible. It separates your code |
1472 | - into 'data' and 'render' functions, a simplified implementation of |
1473 | - traditional MVC. It has various parts which can be used individually |
1474 | - or as a whole, integrated web solution: |
1475 | - . |
1476 | - - XHTML templates: contain no programming logic, only nodes tagged |
1477 | - with nevow attributes |
1478 | - - data/render methods: simplified MVC |
1479 | - - stan: An s-expression-like syntax for expressing xml in pure python |
1480 | - - formless: For describing the types of objects which may be passed |
1481 | - to methods of your classes, validating and coercing string input from |
1482 | - either web or command-line sources, and calling your methods |
1483 | - automatically once validation passes |
1484 | - - freeform: For rendering web forms based on formless type |
1485 | - descriptions, accepting form posts and passing them to formless |
1486 | - validators, and rendering error forms in the event validation fails |
1487 | - - livepage: Cross-browser JavaScript glue for sending client side |
1488 | - events to the server and server side events to the client after the |
1489 | - page has loaded, without causing the entire page to refresh |
1490 | - |
1491 | -Package: python2.4-nevow |
1492 | -Architecture: all |
1493 | -Depends: python2.4, python2.4-twisted |
1494 | -Description: Web application templating system for Python and Twisted |
1495 | - Nevow's main focus is on separating the HTML template from both the |
1496 | - business logic and the display logic, while allowing the programmer |
1497 | - to write pure Python code as much as possible. It separates your code |
1498 | - into 'data' and 'render' functions, a simplified implementation of |
1499 | - traditional MVC. It has various parts which can be used individually |
1500 | - or as a whole, integrated web solution: |
1501 | - . |
1502 | - - XHTML templates: contain no programming logic, only nodes tagged |
1503 | - with nevow attributes |
1504 | - - data/render methods: simplified MVC |
1505 | - - stan: An s-expression-like syntax for expressing xml in pure python |
1506 | - - formless: For describing the types of objects which may be passed |
1507 | - to methods of your classes, validating and coercing string input from |
1508 | - either web or command-line sources, and calling your methods |
1509 | - automatically once validation passes |
1510 | - - freeform: For rendering web forms based on formless type |
1511 | - descriptions, accepting form posts and passing them to formless |
1512 | - validators, and rendering error forms in the event validation fails |
1513 | - - livepage: Cross-browser JavaScript glue for sending client side |
1514 | - events to the server and server side events to the client after the |
1515 | - page has loaded, without causing the entire page to refresh |
1516 | |
1517 | === removed file 'Nevow/debian/copyright' |
1518 | --- Nevow/debian/copyright 2005-10-14 17:36:24 +0000 |
1519 | +++ Nevow/debian/copyright 1970-01-01 00:00:00 +0000 |
1520 | @@ -1,10 +0,0 @@ |
1521 | -This package was debianized by Tommi Virtanen tv@debian.org on |
1522 | -Sun, 28 Mar 2004 16:44:10 +0300. |
1523 | - |
1524 | -It was originally downloaded from http://www.divmod.org/Home/Projects/Nevow/ |
1525 | - |
1526 | -Upstream Author: Donovan Preston et al <dp@divmod.org> |
1527 | - |
1528 | -Copyright: |
1529 | - |
1530 | -# See the file LICENSE at the top of the source tree. |
1531 | |
1532 | === removed file 'Nevow/debian/python2.3-nevow.manpages' |
1533 | --- Nevow/debian/python2.3-nevow.manpages 2005-10-14 17:36:24 +0000 |
1534 | +++ Nevow/debian/python2.3-nevow.manpages 1970-01-01 00:00:00 +0000 |
1535 | @@ -1,1 +0,0 @@ |
1536 | -doc/man/nevow-xmlgettext.1 |
1537 | |
1538 | === removed file 'Nevow/debian/python2.4-nevow.manpages' |
1539 | --- Nevow/debian/python2.4-nevow.manpages 2005-10-14 17:36:24 +0000 |
1540 | +++ Nevow/debian/python2.4-nevow.manpages 1970-01-01 00:00:00 +0000 |
1541 | @@ -1,1 +0,0 @@ |
1542 | -doc/man/nevow-xmlgettext.1 |
1543 | |
1544 | === removed file 'Nevow/debian/rules' |
1545 | --- Nevow/debian/rules 2005-11-06 18:46:50 +0000 |
1546 | +++ Nevow/debian/rules 1970-01-01 00:00:00 +0000 |
1547 | @@ -1,71 +0,0 @@ |
1548 | -#!/usr/bin/make -f |
1549 | -# -*- mode: makefile; coding: utf-8 -*- |
1550 | -# Copyright © 2002,2003 Colin Walters <walters@debian.org> |
1551 | - |
1552 | -include /usr/share/cdbs/1/rules/debhelper.mk |
1553 | -include /usr/share/cdbs/1/class/python-distutils.mk |
1554 | - |
1555 | -DEB_INSTALL_DOCS_python2.3-nevow := doc/* |
1556 | -DEB_INSTALL_EXAMPLES_python2.3-nevow := examples/* |
1557 | -DEB_INSTALL_DOCS_python2.4-nevow := doc/* |
1558 | -DEB_INSTALL_EXAMPLES_python2.4-nevow := examples/* |
1559 | -DEB_DH_ALWAYS_EXCLUDE := .svn |
1560 | - |
1561 | -docdir = debian/$(1)/usr/share/doc/$(1) |
1562 | -binary-post-install/%:: |
1563 | - grep -v '^# See the file LICENSE' \ |
1564 | - '$(call docdir,$*)/copyright' \ |
1565 | - >'$(call docdir,$*)/copyright.tmp' |
1566 | - cat LICENSE \ |
1567 | - >>'$(call docdir,$*)/copyright.tmp' |
1568 | - mv \ |
1569 | - '$(call docdir,$*)/copyright.tmp' \ |
1570 | - '$(call docdir,$*)/copyright' |
1571 | - |
1572 | -# see http://bugs.debian.org/295906 |
1573 | -cdbs_python_ver = $(filter-out -%,$(subst -, -,$(patsubst python%,%,$(cdbs_curpkg)))) |
1574 | - |
1575 | -$(patsubst %,binary-post-install/%,$(DEB_PYTHON_REAL_LIB_PACKAGES)):: binary-post-install/%: |
1576 | - set -e; for file in debian/$(cdbs_curpkg)/usr/bin/*; do \ |
1577 | - sed '1s|.*|#!/usr/bin/python$(cdbs_python_ver)|' $$file >\ |
1578 | - "$${file}$(cdbs_python_ver)";\ |
1579 | - rm -- "$$file";\ |
1580 | - chmod 755 "$${file}$(cdbs_python_ver)";\ |
1581 | - mv "debian/$(cdbs_curpkg)/usr/share/man/man1/$$(basename "$$file").1" \ |
1582 | - "debian/$(cdbs_curpkg)/usr/share/man/man1/$$(basename "$$file")$(cdbs_python_ver).1";\ |
1583 | - done |
1584 | - |
1585 | -binary-post-install/python2.3-nevow:: |
1586 | - set -e; for file in debian/$(cdbs_curpkg)/usr/bin/*;\ |
1587 | - do target="$$(echo "$$file" | sed 's/$(cdbs_python_ver)$$//')";\ |
1588 | - ln -s "$$(basename "$$file")" "$$target";\ |
1589 | - manname="$$(basename "$$target").1.gz";\ |
1590 | - ln -s "$$(basename "$$file").1.gz" \ |
1591 | - "debian/$(cdbs_curpkg)/usr/share/man/man1/$$manname";\ |
1592 | - done |
1593 | - |
1594 | -clean:: |
1595 | - rm -f setupcommon.pyc |
1596 | - |
1597 | - |
1598 | -ifeq (,$(findstring nocheck,$(DEB_BUILD_OPTIONS))) |
1599 | -TRIAL=trial$(cdbs_python_ver) |
1600 | -TOPMODULES:=nevow formless |
1601 | -$(patsubst %,binary-post-install/%,$(DEB_PYTHON_REAL_LIB_PACKAGES)):: binary-post-install/%: |
1602 | - PYTHONPATH='debian/$(cdbs_curpkg)/usr/lib/python$(cdbs_python_ver)/site-packages/' \ |
1603 | - '$(TRIAL)' --bwverbose -R $(TOPMODULES) |
1604 | - |
1605 | - # Importing the modules generates .pyc files, and dh_python (which |
1606 | - # normally cleans them) has already been run. Remove them manually. |
1607 | - find 'debian/$(cdbs_curpkg)' -name '*.py[co]' -print0 \ |
1608 | - | xargs -0 rm -f -- |
1609 | -endif |
1610 | - |
1611 | -clean:: |
1612 | - rm -rf _trial_temp |
1613 | - |
1614 | - |
1615 | -# distutils is sloppy and only cleans with the default python version, |
1616 | -# leaving all the other stuff still in build |
1617 | -clean:: |
1618 | - rm -rf build |
1619 | |
1620 | === removed directory 'Nevow/doc' |
1621 | === removed file 'Nevow/doc/README' |
1622 | --- Nevow/doc/README 2010-04-06 11:05:45 +0000 |
1623 | +++ Nevow/doc/README 1970-01-01 00:00:00 +0000 |
1624 | @@ -1,5 +0,0 @@ |
1625 | -This is Nevow's documentation. The preferred format is Lore XHTML. You can |
1626 | -generate the pretty version of the documentation with by running the |
1627 | -following command in the howto directory: |
1628 | - |
1629 | - lore |
1630 | |
1631 | === removed directory 'Nevow/doc/howto' |
1632 | === removed directory 'Nevow/doc/howto/chattutorial' |
1633 | === removed file 'Nevow/doc/howto/chattutorial/concepts.xhtml' |
1634 | --- Nevow/doc/howto/chattutorial/concepts.xhtml 2008-09-03 20:03:47 +0000 |
1635 | +++ Nevow/doc/howto/chattutorial/concepts.xhtml 1970-01-01 00:00:00 +0000 |
1636 | @@ -1,136 +0,0 @@ |
1637 | -<?xml version="1.0"?> |
1638 | -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" |
1639 | - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
1640 | -<html xmlns="http://www.w3.org/1999/xhtml"> |
1641 | - <head> |
1642 | - <title>Concepts</title> |
1643 | - </head> |
1644 | -<body> |
1645 | - |
1646 | -<h1>Concepts</h1> |
1647 | - |
1648 | -<h2>Servers and Clients</h2> |
1649 | - |
1650 | -<p>COMET applications can seem an almost impenetrable mess when one is first |
1651 | -learning about them, much like when writing event-based desktop |
1652 | -applications. However, there are some basic concepts that we can emphasize now |
1653 | -to circumvent or alleviate most of the confusion.</p> |
1654 | - |
1655 | -<p>In principle, the problem is very simple:</p> |
1656 | -<ul> |
1657 | -<li>We want out users to interact with a <q>web page</q> with out having to refresh |
1658 | -the page, and we want new data and/or views to be rendered in response to our |
1659 | -users' actions;</li> |
1660 | -<li>We want the ability to push updates to user pages from the server to the |
1661 | -browser, when the server has new data or views that are ready.</li> |
1662 | -</ul> |
1663 | - |
1664 | -<p>As usual, the implementation of the solution is much more complicated than |
1665 | -the statement of the problem, but hopefully the way that we have designed |
1666 | -Athena will hide those implementation details while providing powerful tools to |
1667 | -build the applications you envision. So, let's take a look at what you need to |
1668 | -know about servers and clients when building Athena web applications.</p> |
1669 | - |
1670 | -<p>It is crucial that one understands that when we write Athena applications, |
1671 | -we are doing a few different things:</p> |
1672 | -<ul> |
1673 | -<li>Writing server code in Python that performs server actions</li> |
1674 | -<li>Writing server code in Python that makes remote calls to the browser</li> |
1675 | -<li>Writing browser code in JavaScript that performs browser actions</li> |
1676 | -<li>Writing browser code in JavaScript that makes remote calls to the server</li> |
1677 | -</ul> |
1678 | - |
1679 | -<p>Since server-on-server and client-on-client are rather common place and |
1680 | -generally well understood, we will ignore those for now. As the other two |
1681 | -are the focus of AJAX/COMET and thus also the primary domain of Athena, that is |
1682 | -what we will discuss below.</p> |
1683 | - |
1684 | -<p>Browser-to-server calls are made by Athena via the now-famous |
1685 | - XMLHttpRequest. Server-to-browser calls are opened by the browser ahead of |
1686 | -time, and when the server is ready, the data is sent to the browser via that |
1687 | -connection.</p> |
1688 | - |
1689 | -<h2>JavaScript: Making Calls to the Server</h2> |
1690 | - |
1691 | -<p>When creating the JavaScript portion of our applications, we subclass |
1692 | -an Athena JavaScript widget, which has a method named |
1693 | -<code>callRemote()</code>. By utilizing this method, we can send messages from |
1694 | -our JavaScript client to the server (as long as the method we call exists in |
1695 | -the server code).</p> |
1696 | - |
1697 | -<p>For example, in the chat application we will be building in this series |
1698 | -of tutorials, we will have a JavaScript class called <code>ChatterBox</code> with a |
1699 | -<code>say()</code> method, like the following:</p> |
1700 | -<pre> |
1701 | -function say(self, msg) { |
1702 | - self.callRemote("say", msg); |
1703 | - // Now show the text to the user somehow... |
1704 | -} |
1705 | -</pre> |
1706 | -<p>This will make a remote call to the Python server code, executing the |
1707 | -<code>say()</code> method and passing the <code>msg</code> variable as a |
1708 | -parameter.</p> |
1709 | - |
1710 | -<p>In Athena, the relationship between the browser code and the server code is |
1711 | -established by declaring the JavaScript module in the Python server code, in |
1712 | -the following manner:</p> |
1713 | -<pre class="python"> |
1714 | -class ChatterBox(LiveElement): |
1715 | - jsClass = u'ChatThing.ChatterBox' |
1716 | -</pre> |
1717 | -<p>Additionally, in order for the JS to be able to make a call to remote Python |
1718 | -code, the Python method has to be exposed. This is a security feature, |
1719 | -implemented to ensure the JavaScript code can only call Python methods that |
1720 | -have been specifically marked as safe. Appropriately enough, this is done in |
1721 | -your Python class with the <code>expose</code> decorator:</p> |
1722 | - |
1723 | -<pre class="python"> |
1724 | -def say(self, text): |
1725 | - for chatter in chatRoom: |
1726 | - chatter.youHeardSomething(text) |
1727 | -say = expose(say) |
1728 | -</pre> |
1729 | - |
1730 | -<h2>Python: Making Calls to the Browser</h2> |
1731 | - |
1732 | -<p>Now what about the COMET side of the equation? If we want our server to |
1733 | -update data in the browser, we need to be able to call JavaScript code from our |
1734 | -Python server. We use a similar Python method as the JavaScript one (when |
1735 | -making calls from the browser to the server), acquired when our Python class |
1736 | -inherited from <code>nevow.athena.LiveElement</code>:</p> |
1737 | - |
1738 | -<pre class="python"> |
1739 | -def hear(self, sayer, text): |
1740 | - self.callRemote("hear", sayer, text) |
1741 | -</pre> |
1742 | - |
1743 | -<p>In order for this call to work, we need to have the <code>hear()</code> |
1744 | -method defined in our <code>ChatterBox</code> JavaScript class, and that will |
1745 | -look like this:</p> |
1746 | -<pre> |
1747 | -function hear(self, avatarName, text) { |
1748 | - // Here, you'd show the user some text. |
1749 | -} |
1750 | -</pre> |
1751 | - |
1752 | -<p>Unlike on our Python classes, no special annotations need to be made on the |
1753 | -JavaScript side: all JavaScript methods on browser-side Widget objects are |
1754 | -allowed to be called by the server. If you've sent code to the browser, you've |
1755 | -already forfeited the ability to control when it's called. There wouldn't be a |
1756 | -point to limiting the server's rights to run its code when the user can freely |
1757 | -run it herself.</p> |
1758 | - |
1759 | -<h2>Summary</h2> |
1760 | - |
1761 | -<p>With the samples above, you should have a growing sense of how Python and |
1762 | -JavaScript interact as servers and clients in the world of Athena. In |
1763 | -particular, you should be getting a sense of how JavaScript and Python will be |
1764 | -interacting in your Athena applications.</p> |
1765 | - |
1766 | -<p>This has just been a taste of Athena with a few peeks into the code we |
1767 | -will be writing. We will cover these topics in greater detail in the following |
1768 | -pages, within the context of creating a functional Athena application, |
1769 | -complete with step-by-step instructions and rationale.</p> |
1770 | - |
1771 | -</body> |
1772 | -</html> |
1773 | |
1774 | === removed file 'Nevow/doc/howto/chattutorial/env.xhtml' |
1775 | --- Nevow/doc/howto/chattutorial/env.xhtml 2008-09-03 20:03:47 +0000 |
1776 | +++ Nevow/doc/howto/chattutorial/env.xhtml 1970-01-01 00:00:00 +0000 |
1777 | @@ -1,122 +0,0 @@ |
1778 | -<?xml version="1.0"?> |
1779 | -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" |
1780 | -"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
1781 | -<html xmlns="http://www.w3.org/1999/xhtml"> |
1782 | - <head> |
1783 | - <title>Setting up an Environment</title> |
1784 | - </head> |
1785 | -<body> |
1786 | - |
1787 | -<h1>Setting up an Environment</h1> |
1788 | - |
1789 | -<h2>Install</h2> |
1790 | - |
1791 | -To run this tutorial, you need to have nevow available to python and |
1792 | -you'll need the files in the doc/howto tree. You don't even have to |
1793 | -install nevow; the examples will run within the source tree. |
1794 | - |
1795 | - |
1796 | -<h3>Combinator: The Divmod Way</h3> |
1797 | - |
1798 | -<p>Using SVN |
1799 | -with <a href="http://divmod.org/trac/wiki/DivmodCombinator">Combinator</a> |
1800 | -is the best way to try out the example code in-place (and hop between |
1801 | -other SVN branches in the future). This is how we develop and test our |
1802 | -applications at Divmod. If you have a system installation of Twisted |
1803 | -that you don't want to update or interfere with, you can use this |
1804 | -method without installing anything. |
1805 | -</p> |
1806 | - |
1807 | -<ol> |
1808 | - |
1809 | -<li>Create a projects directory or change to some other test directory |
1810 | -of your choice: |
1811 | -<pre class="shell"> |
1812 | -$ mkdir ~/Projects |
1813 | -$ cd ~/Projects |
1814 | -</pre> |
1815 | -</li> |
1816 | - |
1817 | - |
1818 | -<li>If you don't have the |
1819 | -<a href="http://twistedmatrix.com/trac/">twisted library</a>, check it out now: |
1820 | -<pre class="shell"> |
1821 | -$ svn co svn://svn.twistedmatrix.com/svn/Twisted/trunk Twisted/trunk |
1822 | -</pre> |
1823 | -</li> |
1824 | - |
1825 | -<li>Then get Combinator and Nevow (and the rest of Divmod). See the |
1826 | -<a href="http://divmod.org/trac/wiki/CombinatorTutorial">Combinator |
1827 | -Tutorial</a> for more about these special checkout paths. |
1828 | -<pre class="shell"> |
1829 | -$ svn co http://divmod.org/svn/Divmod/trunk Divmod/trunk |
1830 | -</pre> |
1831 | -</li> |
1832 | - |
1833 | -<li>Set up the Combinator environment in this shell. You'll need this |
1834 | -step in any future test shells since it adjusts PATH and PYTHONPATH: |
1835 | -<pre class="shell"> |
1836 | -$ eval `python Divmod/trunk/Combinator/environment.py` |
1837 | -(some "link:" lines are normal) |
1838 | -</pre> |
1839 | -</li> |
1840 | - |
1841 | -<li>Register both the Twisted and Divmod (and thus Nevow+Athena) codebases with |
1842 | -Combinator: |
1843 | -<pre class="shell"> |
1844 | -$ chbranch Twisted trunk |
1845 | -$ chbranch Divmod trunk |
1846 | -</pre> |
1847 | -</li> |
1848 | - |
1849 | -<li>You can check to see if your environment is ready to go by running the |
1850 | -tutorial tests (from any directory, after executing the previous command): |
1851 | -<pre class="shell"> |
1852 | -$ trial nevow.test.test_howtolistings |
1853 | -</pre> |
1854 | -If they all pass, you're ready to begin the tutorial. |
1855 | -</li> |
1856 | -</ol> |
1857 | - |
1858 | - |
1859 | - |
1860 | -<h3>Standard distutils Installation</h3> |
1861 | - |
1862 | -<p>If you don't want to manage branches and environments with |
1863 | -Combinator, you can install our code in the |
1864 | -standard <code>site-packages</code> directory. You'll still need the |
1865 | -source tree so you can use the files in doc/howto.</p> |
1866 | - |
1867 | -<p>For those that would prefer the <q>old way,</q> here's how you do it:</p> |
1868 | - |
1869 | -<ol> |
1870 | - |
1871 | -<li>Create a projects directory: |
1872 | -<pre class="shell"> |
1873 | -$ mkdir ~/Projects |
1874 | -$ cd ~/Projects |
1875 | -</pre> |
1876 | -</li> |
1877 | - |
1878 | -<li>Checkout and install the latest Twisted: |
1879 | -<pre class="shell"> |
1880 | -$ svn co svn://svn.twistedmatrix.com/svn/Twisted/trunk Twisted |
1881 | -$ cd Twisted |
1882 | -$ sudo python setup.py install |
1883 | -$ cd ../ |
1884 | -</pre> |
1885 | -</li> |
1886 | - |
1887 | -<li>Checkout and install Nevow: |
1888 | -<pre class="shell"> |
1889 | -$ svn co http://divmod.org/svn/Divmod/trunk/Nevow Nevow |
1890 | -$ cd Nevow |
1891 | -$ sudo python setup.py install |
1892 | -$ cd ../ |
1893 | -</pre> |
1894 | -</li> |
1895 | - |
1896 | -</ol> |
1897 | - |
1898 | -</body> |
1899 | -</html> |
1900 | |
1901 | === removed file 'Nevow/doc/howto/chattutorial/index.xhtml' |
1902 | --- Nevow/doc/howto/chattutorial/index.xhtml 2008-09-03 20:03:47 +0000 |
1903 | +++ Nevow/doc/howto/chattutorial/index.xhtml 1970-01-01 00:00:00 +0000 |
1904 | @@ -1,56 +0,0 @@ |
1905 | -<?xml version="1.0"?> |
1906 | -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" |
1907 | -"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
1908 | -<html xmlns="http://www.w3.org/1999/xhtml"> |
1909 | - <head> |
1910 | - <title>Nevow Athena from Scratch, or The Evolution of a Chat Application</title> |
1911 | - </head> |
1912 | -<body> |
1913 | - |
1914 | - <h1>Nevow Athena from Scratch, or The Evolution of a Chat Application</h1> |
1915 | - |
1916 | -<h2>The <q>Chat Tutorial</q> Series</h2> |
1917 | - |
1918 | -<p> |
1919 | -Athena is the JavaScript engine behind Nevow, providing a great deal of |
1920 | -resources and power to the developer of asynchronous web applications. To |
1921 | -demonstrate this, we are using a web chat application as our primary example |
1922 | -in this tutorial. The tutorial is split into several parts: a few introductory |
1923 | -pages and then independent (but related) tutorials of increasing complexity. |
1924 | -</p> |
1925 | - |
1926 | -<ol> |
1927 | - <li>Basics |
1928 | - <ul> |
1929 | - <li><a href="intro.xhtml">Introduction</a></li> |
1930 | - <li><a href="concepts.xhtml">Concepts of Athena: AJAX, COMET, and Python</a></li> |
1931 | - <li><a href="env.xhtml">Setting Up the Tutorial Environment and Running Tutorial Source Code</a></li> |
1932 | - </ul> |
1933 | - </li> |
1934 | - <li><a href="part00/index.xhtml">Toy <q>Echo</q> Application </a></li> |
1935 | - <li><a href="part01/index.xhtml">Simple Chat and Two-Way Communications</a></li> |
1936 | -</ol> |
1937 | - |
1938 | -<h2>History</h2> |
1939 | -<p> |
1940 | -Nevow's predecessor was Woven (and prior to that, WebMVC). Woven had something |
1941 | -called <code>LivePage</code> that was doing DOM manipulation as far back as |
1942 | -2002. In early 2003, Woven event handlers supported sending JavaScript back to |
1943 | -the user's browser, allowing pages to be updated in response to user-generated |
1944 | -events. The earliest publicly visible revisions of Nevow made use of XHR |
1945 | -(XMLHttpRequest) in early 2004. These facts are notable because Nevow was using |
1946 | -AJAX a year before the term was coined in 2005 and had working code in 2002 and |
1947 | -2003 that predated Netscape publishing articles on what they called <q>Inner |
1948 | -Browsing</q> where all navigation takes place withing a single page. |
1949 | -</p> |
1950 | - |
1951 | -<p> |
1952 | -Again taking the lead, Athena offers features which developers cannot find |
1953 | -elsewhere. In this series, we attempt to expose these excellent qualities |
1954 | -to the world of application |
1955 | -developers. |
1956 | -</p> |
1957 | - |
1958 | -</body> |
1959 | -</html> |
1960 | - |
1961 | |
1962 | === removed file 'Nevow/doc/howto/chattutorial/intro.xhtml' |
1963 | --- Nevow/doc/howto/chattutorial/intro.xhtml 2008-09-03 20:03:47 +0000 |
1964 | +++ Nevow/doc/howto/chattutorial/intro.xhtml 1970-01-01 00:00:00 +0000 |
1965 | @@ -1,106 +0,0 @@ |
1966 | -<?xml version="1.0"?> |
1967 | -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
1968 | -<html xmlns="http://www.w3.org/1999/xhtml"> |
1969 | - <head> |
1970 | - <title>Introduction</title> |
1971 | - </head> |
1972 | -<body> |
1973 | - |
1974 | -<h1>Introduction</h1> |
1975 | - |
1976 | -<h2>Who is this tutorial for?</h2> |
1977 | - |
1978 | -<p>This tutorial is for people who want to build interactive client-server |
1979 | -functionality where a web-browser is the client. It will show you how to build |
1980 | -a live, interactive chat application that requires nothing more than a web |
1981 | -browser that supports JavaScript.</p> |
1982 | - |
1983 | -<p>The interesting thing about a chat application, which shows why Nevow Athena |
1984 | -is special, is that it involves two-way communication. In other words, it |
1985 | -involves not only the recently-popular AJAX (the web browser sending commands |
1986 | -to the server without loading a new page) but also the trickier and, in our |
1987 | -opinion, somewhat cooler technique known as COMET (the web server |
1988 | -sending commands to the <em>browser</em>).</p> |
1989 | - |
1990 | -<h2>Who is this tutorial <em>not</em> for?</h2> |
1991 | - |
1992 | -<p>Nevow Athena is <em>not</em> for people who want a normal web application |
1993 | -framework. If you want one of those, you should use |
1994 | -non-Athena-<a href="http://divmod.org/trac/wiki/DivmodNevow">Nevow</a>, |
1995 | -<a href="http://www.djangoproject.com/">Django</a>, |
1996 | -<a href="http://turbogears.org/">TurboGears</a>, or maybe even |
1997 | -<a href="http://rubyonrails.org/">Ruby On Rails</a>. Athena doesn't work in terms |
1998 | -of pages, links, or HTTP requests and responses; it is a client-server |
1999 | -framework that works in terms of widgets, JavaScript objects, and symmetric |
2000 | -asynchronous message queues.</p> |
2001 | - |
2002 | -<p>However, as alluded to above, Athena is part of a larger framework, Nevow, |
2003 | -which can be used to build more general-purpose and <q>traditional</q> |
2004 | -web applications.</p> |
2005 | - |
2006 | -<h2>AJAX</h2> |
2007 | - |
2008 | -<p>AJAX isn't a technology in and of itself, bur rather an amalgam of |
2009 | -technologies used together in order to accomplish the goal of making web |
2010 | -applications more responsive than traditional delivery and interactive |
2011 | -mechanisms, such as HTML forms submitted to a server.</p> |
2012 | - |
2013 | -<p>In particular, AJAX consists of the following:</p> |
2014 | -<ul> |
2015 | -<li>Asynchronous communications from a user's browser to a server</li> |
2016 | -<li>JavaScript</li> |
2017 | -<li>Exchanged data (usually XML or JSON)</li> |
2018 | -</ul> |
2019 | - |
2020 | -<h2>COMET</h2> |
2021 | - |
2022 | -<p>Historically, the focus of AJAX technologies was user-event driven. However, |
2023 | -with the need to update the user's browser with events generated at the server, |
2024 | -a solution more sophisticated than AJAX was needed; this has been dubbed COMET. |
2025 | -Athena is implemented using both AJAX and COMET techniques, and therefore |
2026 | -allows two-way browser <-> server communications.</p> |
2027 | - |
2028 | -<h2>Athena Basics</h2> |
2029 | - |
2030 | -<p>We've provided brief background information on AJAX/COMET, but what is the |
2031 | -purpose of Athena? What makes Athena different than other solutions? Here are a |
2032 | -few key points that should help with these questions::</p> |
2033 | -<ul> |
2034 | -<li>Athena exists to make writing COMET web applications easy.</li> |
2035 | -<li>Athena is written in Python and JavaScript</li> |
2036 | -<li>It is written to be used with Nevow, a <a |
2037 | -href="http://twistedmatrix.com/">Twisted</a>-based web framework.</li> |
2038 | -<li>Similar to Twisted's <a |
2039 | -href="http://twistedmatrix.com/projects/core/documentation/howto/pb-intro.html">Perspective |
2040 | -Broker</a>, Athena employs remote calls.</li> |
2041 | -</ul> |
2042 | - |
2043 | -<p>Athena was written by Twisted and Divmod developers (in addition to |
2044 | -contributing members of the community) in order to bring the outdated and |
2045 | -Nevow-incompatible Woven LivePage technology to Nevow. In addition, it was an |
2046 | -opportunity to improve upon the original design and incorporate new features to |
2047 | -address the growing needs of developers.</p> |
2048 | - |
2049 | -<h2>Target Applications</h2> |
2050 | - |
2051 | -<p>Good candidates for Athena web applications would include those where the |
2052 | -application needs to respond to user input and/or updates from servers, such |
2053 | -as the following:</p> |
2054 | -<ul> |
2055 | -<li>conference software (e.g. whiteboard, shared text, chat, etc.)</li> |
2056 | -<li>mail clients</li> |
2057 | -<li>interactive, multi-player games</li> |
2058 | -<li>social networking tools</li> |
2059 | -<li>office applications (e.g., spreadsheets, word processors, etc.)</li> |
2060 | -</ul> |
2061 | - |
2062 | -<h2>Target Developers</h2> |
2063 | - |
2064 | -<p>Anyone who wants to create interactive, web-based applications is a |
2065 | -potential Nevow/Athena user. It's best to have some background in writing web |
2066 | -applications, and in addition, to know how to use Nevow. However, we hope that |
2067 | -this tutorial will be just as useful for beginners as experienced |
2068 | -developers.</p> |
2069 | - |
2070 | -</body> |
2071 | -</html> |
2072 | |
2073 | === removed directory 'Nevow/doc/howto/chattutorial/part00' |
2074 | === removed file 'Nevow/doc/howto/chattutorial/part00/index.xhtml' |
2075 | --- Nevow/doc/howto/chattutorial/part00/index.xhtml 2008-09-03 20:03:47 +0000 |
2076 | +++ Nevow/doc/howto/chattutorial/part00/index.xhtml 1970-01-01 00:00:00 +0000 |
2077 | @@ -1,230 +0,0 @@ |
2078 | -<?xml version="1.0"?> |
2079 | -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" |
2080 | -"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
2081 | -<html xmlns="http://www.w3.org/1999/xhtml"> |
2082 | - <head> |
2083 | - <title>Nevow Athena from Scratch: Echo Application</title> |
2084 | - </head> |
2085 | -<body> |
2086 | - |
2087 | -<h2>What is an "Echo Application?"</h2> |
2088 | - |
2089 | -<p> |
2090 | -Our first foray into building an Athena application will be an easy venture: |
2091 | -we want to type something in an input box and have it echoed back to us on |
2092 | -the same page, without having to reload anything. Why? Well, our eventual |
2093 | -goal is to have a working chat server, with all sorts of technical bells |
2094 | -and whistles (persistent storage, authentication, |
2095 | -etc.), but that's a bit heady for right now. Many of the same principles |
2096 | -which we will eventually employ in our chat application exist for a simple |
2097 | -case of sending textual messages between a web browser and a server. This |
2098 | -is the essence of our "Echo" application. |
2099 | -</p> |
2100 | - |
2101 | -<h2>Mental Preparation</h2> |
2102 | - |
2103 | -<p>In the |
2104 | -<a href="../intro.html">Introduction</a> and the |
2105 | -<a href="../concepts.html">Concepts</a> pages, we had a refresher on AJAX and |
2106 | -COMET and we learned a little bit about what that looks like for Athena. But |
2107 | -as we sit down to actually write an Athena application, what do we need to |
2108 | -wrap our heads around? |
2109 | -</p> |
2110 | - |
2111 | -<p>Given the introductory knowledge we have, we know that we will need to |
2112 | -write some JavaScript, some Python, and if our past experience in developing |
2113 | -web applications is any guide, some form of template. This indeed is the |
2114 | -case, but here's something big: we're not working with pages and page |
2115 | -templates; we're working with "elements", or parts of the DOM tree. We will |
2116 | -not be creating page resources; we will be creating just the parts of a |
2117 | -"traditional" page that will be dynamic and interactive. |
2118 | -</p> |
2119 | - |
2120 | -<h2>Architecture</h2> |
2121 | - |
2122 | -<p>Now that we've pumped ourselves up and before we start clacking away at the |
2123 | -keyboard, we need to get pointed in the right direction. We need a |
2124 | -plan. Here's what we know:</p> |
2125 | - |
2126 | -<ol> |
2127 | -<li>We will have a server that: |
2128 | - <ul> |
2129 | - <li>serves dynamic elements in a resource accessible via a URL;</li> |
2130 | - <li>communicates with a client.</li> |
2131 | - </ul> |
2132 | -</li> |
2133 | -<li>We will have a client that: |
2134 | - <ul> |
2135 | - <li>communicates with the server;</li> |
2136 | - <li>updates its DOM tree.</li> |
2137 | - </ul> |
2138 | -</li> |
2139 | -</ol> |
2140 | - |
2141 | -<p>The user experience of this application will be the following:</p> |
2142 | -<ol> |
2143 | -<li>they will type text in an input on a form; and</li> |
2144 | -<li>the typed text will be rendered to a different part of the page upon |
2145 | -hitting a submit button.</li> |
2146 | -</ol> |
2147 | - |
2148 | -<p>We will not simply write user input to a <code>div</code> with JavaScript |
2149 | -DOM manipulation, but will instead pass data like we expect will be necessary |
2150 | -when we write our chat application. After all, it's probably best to build |
2151 | -towards our goal. In order to accomplish this, the application will do |
2152 | -something like the following:</p> |
2153 | - |
2154 | -<ol> |
2155 | -<li>JavaScript client code will extract user input and send |
2156 | -it to our server;</li> |
2157 | -<li>Python code will receive messages from the client;</li> |
2158 | -<li>Python code will send messages to the client; and</li> |
2159 | -<li>a template file (or <code>stan</code> code) will be used for |
2160 | -presentation.</li> |
2161 | -</ol> |
2162 | - |
2163 | -<p></p> |
2164 | - |
2165 | -<h2>Let the Coding Begin</h2> |
2166 | - |
2167 | -<p>In a future installment, we will outline the development process from |
2168 | -the perspective of test-driven development, in order to not only show how |
2169 | -to write unit tests for Athena (Python and JavaScript), but to encourage |
2170 | -good programming practices while working with Athena. For now, though, we will |
2171 | -just dive right in.</p> |
2172 | - |
2173 | -<h3>Presentation</h3> |
2174 | - |
2175 | -<p>Let's start with the easy bit: what our app will look like. Here is the |
2176 | -template for our echo application:</p> |
2177 | - |
2178 | -<a href="listings/echothing/template.html" class="html-listing" /> |
2179 | - |
2180 | -<p>Things to note:</p> |
2181 | -<ul> |
2182 | -<li>This is not a complete HTML document, but is an XHTML template for an |
2183 | -"element".</li> |
2184 | -<li>The name space declarations in the top <code>div</code> tag are necessary |
2185 | -for the operation of Athena.</li> |
2186 | -<li>When we hit the "Send" button, our JavaScript class will call the |
2187 | -<code>doSay()</code> method.</li> |
2188 | -</ul> |
2189 | - |
2190 | -<h3>Writing the Client</h3> |
2191 | - |
2192 | -<p>Next up is the JavaScript. We need to send our data to the server. In a |
2193 | -full chat application, it would be necessary to send the data to the server |
2194 | -so that we could propagate the message to all connected clients. In this |
2195 | -case, with the simple echo, we're not going to do anything with the data |
2196 | -that gets sent to the server, except send it back, of course.</p> |
2197 | - |
2198 | -<p>Our JavaScript will need to do several things:</p> |
2199 | -<ol> |
2200 | -<li>import required modules;</li> |
2201 | -<li>inherit <code>callRemote</code> functionality from the base |
2202 | -<code>Widget</code> class;</li> |
2203 | -<li>setup convenience attributes;</li> |
2204 | -<li>implement the <code>doSay()</code> method we put in our template above; |
2205 | -and</li> |
2206 | -<li>implement a method for updating the DOM with data it receives from |
2207 | -the server</li> |
2208 | -</ol> |
2209 | - |
2210 | -<a href="listings/echothing/js/EchoThing.js" class="py-listing" /> |
2211 | - |
2212 | -<p>Points to note:</p> |
2213 | -<ul> |
2214 | -<li>Those import statements aren't just pretty: they are necessary! In Athena, |
2215 | -you need to treat those like you treat the import statements in Python. |
2216 | -</li> |
2217 | -<li>The attributes set in the <code>__init__()</code> method are for |
2218 | -convenience when we reference them in other methods.</li> |
2219 | -<li>Note the <code>callRemote()</code> method in <code>doSay()</code>, |
2220 | -As mentioned in the <a href="../concepts.html">Concepts</a> section, this |
2221 | -is how JavaScript is communicating with our Python server.</li> |
2222 | -<li>Another thing about <code>doSay</code>: this is the submit handler. As |
2223 | -such, it needs to return false so that the browser is prevented from doing a |
2224 | -normal form submission.</li> |
2225 | -<li><code>addText()</code> is the method that will be updating the browser |
2226 | -DOM once the server sends the data back.</li> |
2227 | -</ul> |
2228 | - |
2229 | -<p>There's not much to say about the next one. This is what sets up the |
2230 | -relationship between our module name and the actual file itself (so that |
2231 | -the JavaScript can be loaded):</p> |
2232 | - |
2233 | -<a href="listings/nevow/plugins/echothing_package.py" class="py-listing" /> |
2234 | - |
2235 | -<h3>Writing the Server</h3> |
2236 | - |
2237 | -<p>Despite what one might think, writing the server may be the easiest |
2238 | -part! If you've created Nevow applications before, then this will look |
2239 | -very familiar. The only method we need is one that will send data back to |
2240 | -the client. Besides importing the necessary modules and creating a class |
2241 | -with some boilerplate, that's about it. |
2242 | -</p> |
2243 | - |
2244 | -<p>Let's take a look at the code:</p> |
2245 | - |
2246 | -<a href="listings/echothing/echobox.py" class="py-listing" /> |
2247 | - |
2248 | -<p>As promised, simple as can be. We do make use of a Twisted utility that |
2249 | -simplifies typing the path to our template. Some very important points:</p> |
2250 | -<ul> |
2251 | -<li>The <code>jsClass</code> assignment is what connects this code to your |
2252 | -JavaScript code.</li> |
2253 | -<li>As discussed in the <a href="../concepts.html">Concepts</a> section, |
2254 | -the <code>expose</code> decorator is required if our JavaScript is going |
2255 | -to be able to call the <code>say()</code> method.</li> |
2256 | -</ul> |
2257 | - |
2258 | -<h3>Putting it All Together</h3> |
2259 | - |
2260 | -<p>Now that we've got all the code in front of us, we can trace out exactly |
2261 | -what happens:</p> |
2262 | -<ol> |
2263 | -<li>the user loads the resource in their browser, and the template is |
2264 | -rendered;</li> |
2265 | -<li>after typing a message in the input box, the user hits submit;</li> |
2266 | -<li>upon hitting submit, the client code <code>doSay()</code> method is |
2267 | -called;</li> |
2268 | -<li><code>doSay()</code> makes a remote call to the Python server method |
2269 | -<code>say()</code>;</li> |
2270 | -<li>the Python server receives the data when <code>say()</code> is called, and |
2271 | -then it passes that data to the client code's <code>addText()</code> method;</li> |
2272 | -<li>with control back in the client code and data fresh from the server, |
2273 | -JavaScript can now update the page's DOM with the new data, and this is |
2274 | -what the <code>addText()</code> method does;</li> |
2275 | -<li>when <code>addText()</code> finishes, the cycle has completed and the |
2276 | -browser now displays the latest data input by the user.</li> |
2277 | -</ol> |
2278 | - |
2279 | -<h3>The Fruits of Our Labor</h3> |
2280 | - |
2281 | -<p>Now we get to run it! This is a little different than what you may be |
2282 | -used to, if you have written Twisted applications in the past. We are using |
2283 | -the plugin architecture of Twisted and Nevow such that <code>twistd</code> |
2284 | -will publish our element in an HTTP service. To do this, we will use |
2285 | -<code>twistd</code>'s <code>athena-widget</code> command:</p> |
2286 | - |
2287 | -<pre class="shell"> |
2288 | -cd Nevow/doc/howto/chattutorial/part00/listings |
2289 | -twistd -n athena-widget --element=echothing.echobox.EchoElement |
2290 | -</pre> |
2291 | - |
2292 | -<p>If you executed this against the tutorial code on your local machine, |
2293 | -you can now visit <a href="http://localhost:8080">localhost:8080</a> and start |
2294 | -echoing to your heart's content.</p> |
2295 | - |
2296 | -<h2>Summary</h2> |
2297 | - |
2298 | -<p>As you can see, our echo application is a toy app that doesn't do |
2299 | -anything very useful. However, it has provided us with a basis for learning how |
2300 | -to write working Athena code that lets a browser and server communicate |
2301 | -with each other, both sending and receiving data. As such, we now have a |
2302 | -solid foundation upon which we can build a functional, useful <i>and</i> |
2303 | -instructional chat application.</p> |
2304 | - |
2305 | -</body> |
2306 | -</html> |
2307 | - |
2308 | |
2309 | === removed directory 'Nevow/doc/howto/chattutorial/part00/listings' |
2310 | === removed directory 'Nevow/doc/howto/chattutorial/part00/listings/echothing' |
2311 | === removed file 'Nevow/doc/howto/chattutorial/part00/listings/echothing/__init__.py' |
2312 | --- Nevow/doc/howto/chattutorial/part00/listings/echothing/__init__.py 2008-09-03 20:03:47 +0000 |
2313 | +++ Nevow/doc/howto/chattutorial/part00/listings/echothing/__init__.py 1970-01-01 00:00:00 +0000 |
2314 | @@ -1,1 +0,0 @@ |
2315 | - |
2316 | |
2317 | === removed file 'Nevow/doc/howto/chattutorial/part00/listings/echothing/echobox.py' |
2318 | --- Nevow/doc/howto/chattutorial/part00/listings/echothing/echobox.py 2008-09-03 20:03:47 +0000 |
2319 | +++ Nevow/doc/howto/chattutorial/part00/listings/echothing/echobox.py 1970-01-01 00:00:00 +0000 |
2320 | @@ -1,12 +0,0 @@ |
2321 | -from twisted.python.util import sibpath |
2322 | -from nevow.athena import LiveElement, expose |
2323 | -from nevow.loaders import xmlfile |
2324 | - |
2325 | -class EchoElement(LiveElement): |
2326 | - |
2327 | - docFactory = xmlfile(sibpath(__file__, 'template.html')) |
2328 | - jsClass = u'EchoThing.EchoWidget' |
2329 | - |
2330 | - def say(self, message): |
2331 | - self.callRemote('addText', message) |
2332 | - say = expose(say) |
2333 | |
2334 | === removed directory 'Nevow/doc/howto/chattutorial/part00/listings/echothing/js' |
2335 | === removed file 'Nevow/doc/howto/chattutorial/part00/listings/echothing/js/EchoThing.js' |
2336 | --- Nevow/doc/howto/chattutorial/part00/listings/echothing/js/EchoThing.js 2009-01-21 22:58:03 +0000 |
2337 | +++ Nevow/doc/howto/chattutorial/part00/listings/echothing/js/EchoThing.js 1970-01-01 00:00:00 +0000 |
2338 | @@ -1,22 +0,0 @@ |
2339 | -// import Nevow.Athena |
2340 | - |
2341 | -Nevow.Athena.Widget.subclass(EchoThing, 'EchoWidget').methods( |
2342 | - function __init__(self, node) { |
2343 | - EchoThing.EchoWidget.upcall(self, "__init__", node); |
2344 | - self.echoWidget = self.nodeByAttribute('name', 'echoElement'); |
2345 | - self.scrollArea = self.nodeByAttribute('name', 'scrollArea'); |
2346 | - self.message = self.nodeByAttribute('name', 'message'); |
2347 | - }, |
2348 | - |
2349 | - function doSay(self) { |
2350 | - self.callRemote("say", self.message.value); |
2351 | - self.message.value = ""; |
2352 | - return false; |
2353 | - }, |
2354 | - |
2355 | - function addText(self, text) { |
2356 | - var newNode = document.createElement('div'); |
2357 | - newNode.appendChild(document.createTextNode(text)); |
2358 | - self.scrollArea.appendChild(newNode); |
2359 | - document.body.scrollTop = document.body.scrollHeight; |
2360 | - }); |
2361 | |
2362 | === removed file 'Nevow/doc/howto/chattutorial/part00/listings/echothing/template.html' |
2363 | --- Nevow/doc/howto/chattutorial/part00/listings/echothing/template.html 2008-09-03 20:03:47 +0000 |
2364 | +++ Nevow/doc/howto/chattutorial/part00/listings/echothing/template.html 1970-01-01 00:00:00 +0000 |
2365 | @@ -1,11 +0,0 @@ |
2366 | -<div xmlns:nevow="http://nevow.com/ns/nevow/0.1" |
2367 | - xmlns:athena="http://divmod.org/ns/athena/0.7" |
2368 | - nevow:render="liveElement"> |
2369 | - <h2>Echo Element</h2> |
2370 | - <form name="echoElement"> |
2371 | - <athena:handler event="onsubmit" handler="doSay" /> |
2372 | - <div name="scrollArea"> |
2373 | - </div> |
2374 | - <input name="message" /><input type="submit" value="Send" /> |
2375 | - </form> |
2376 | -</div> |
2377 | |
2378 | === removed directory 'Nevow/doc/howto/chattutorial/part00/listings/nevow' |
2379 | === removed directory 'Nevow/doc/howto/chattutorial/part00/listings/nevow/plugins' |
2380 | === removed file 'Nevow/doc/howto/chattutorial/part00/listings/nevow/plugins/echothing_package.py' |
2381 | --- Nevow/doc/howto/chattutorial/part00/listings/nevow/plugins/echothing_package.py 2008-09-03 20:03:47 +0000 |
2382 | +++ Nevow/doc/howto/chattutorial/part00/listings/nevow/plugins/echothing_package.py 1970-01-01 00:00:00 +0000 |
2383 | @@ -1,8 +0,0 @@ |
2384 | - |
2385 | -from twisted.python import util |
2386 | - |
2387 | -from nevow import athena |
2388 | - |
2389 | -import echothing |
2390 | - |
2391 | -chatthingPkg = athena.AutoJSPackage(util.sibpath(echothing.__file__, 'js')) |
2392 | |
2393 | === removed directory 'Nevow/doc/howto/chattutorial/part01' |
2394 | === removed file 'Nevow/doc/howto/chattutorial/part01/index.xhtml' |
2395 | --- Nevow/doc/howto/chattutorial/part01/index.xhtml 2008-09-03 20:03:47 +0000 |
2396 | +++ Nevow/doc/howto/chattutorial/part01/index.xhtml 1970-01-01 00:00:00 +0000 |
2397 | @@ -1,236 +0,0 @@ |
2398 | -<?xml version="1.0"?> |
2399 | -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" |
2400 | -"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
2401 | -<html xmlns="http://www.w3.org/1999/xhtml"> |
2402 | - <head> |
2403 | - <title>Nevow Athena from Scratch: Chat Application</title> |
2404 | - </head> |
2405 | -<body> |
2406 | - |
2407 | -<h2>Architecture</h2> |
2408 | - |
2409 | -<p>We'll assume that you've read all the preceding sections of this tutorial |
2410 | -and have just finished the "Echo" application example. As such, we don't need |
2411 | -to do any more "mental preparation" and can skip straight to a description of |
2412 | -the architecture.</p> |
2413 | - |
2414 | -<p>Fundamentally, this is no different than our echo application: there is |
2415 | -a little more chatter that takes place between the client and server; |
2416 | -there's another object involved (a <code>ChatRoom</code>); and we'll have |
2417 | -to run the server a little differently. |
2418 | -</p> |
2419 | - |
2420 | -<p>Here are the new features we want to support:</p> |
2421 | -<ul> |
2422 | -<li>login form;</li> |
2423 | -<li>in-memory user storage;</li> |
2424 | -<li>the ability to send global alerts to all users; and</li> |
2425 | -<li>the ability for all users to "hear" when another user speaks in the |
2426 | -chat room;</li> |
2427 | -</ul> |
2428 | - |
2429 | -<p>A general rule we can establish about our architecture is that if something |
2430 | -has to happen for everyone, that code needs to appear on the server side, |
2431 | -since it's the server that is keeping track of all users. If something is |
2432 | -going to happen irrespective of other users or if browser DOM manipulation |
2433 | -is required, then we know the client will be the recipient of the code.</p> |
2434 | - |
2435 | -<p>As such, in the features above, the login form will be client code. The |
2436 | -user storage, global alerts, and "hearing" will be implemented in server |
2437 | -code for the data; updating the DOM with that data will be implemented in |
2438 | -client code.</p> |
2439 | - |
2440 | -<p>The user experience of this application will be the following:</p> |
2441 | -<ol> |
2442 | -<li>they will be presented with a login box (no password, only username);</li> |
2443 | -<li>upon logging in, a message will be sent to all logged in users that |
2444 | -this person has joined, they will see a message at the bottom of the |
2445 | -chat that states their login name, and the login form will be replaced with |
2446 | -a chat area and a text input field;</li> |
2447 | -<li>they will type text in the input field; and</li> |
2448 | -<li>the typed text will appear in the browser of every person who is |
2449 | -logged in.</li> |
2450 | -</ol> |
2451 | - |
2452 | -<p>Building upon our previous example, our application will do the |
2453 | -following:</p> |
2454 | - |
2455 | -<ol> |
2456 | -<li>JavaScript client code will extract user input and send |
2457 | -it to our server;</li> |
2458 | -<li>Python code will receive messages from the client;</li> |
2459 | -<li>Python code will process these messages;</li> |
2460 | -<li>Python code will send messages to the all clients; and</li> |
2461 | -<li>a template file (or <code>stan</code> code) will be used for |
2462 | -presentation.</li> |
2463 | -</ol> |
2464 | - |
2465 | -<h2>More Coding</h2> |
2466 | - |
2467 | -<h3>Presentation</h3> |
2468 | - |
2469 | -<p>The template is very similar as it was in the previous example, with |
2470 | -the differences being a new login box, a "logged in as" |
2471 | -area, and some name changes:</p> |
2472 | - |
2473 | -<a href="listings/chatthing/template.html" class="html-listing" /> |
2474 | - |
2475 | -<p>We've now got two JavaScript methods that need to be defined: |
2476 | -<code>doSetUsername()</code> and <code>doSay()</code>. We can also infer |
2477 | -from this template that elements will be hidden and shown after login |
2478 | -(note the presence of <code>style="display:none"</code> in two places). With |
2479 | -these observations in hand, let's proceed to the JavaScript code.</p> |
2480 | - |
2481 | -<h3>Writing the Client</h3> |
2482 | - |
2483 | -<p>Referring back to our thoughts in the "Architecture" section above, we |
2484 | -can establish that the JavaScript code needs the following:</p> |
2485 | - |
2486 | -<ul> |
2487 | -<li>have the same basic boilerplate as in the "echo" example (imports, |
2488 | -inheritance, attribute-setting in the constructor);</li> |
2489 | -<li>implement the <code>doSetUsername()</code> and <code>doSay()</code> |
2490 | -methods;</li> |
2491 | -<li>create a method that will send a message to all users; and</li> |
2492 | -<li>create a method that will let everyone know when someone says |
2493 | -something. Let's see how this is done.</li> |
2494 | -</ul> |
2495 | - |
2496 | -<a href="listings/chatthing/js/ChatThing.js" class="py-listing" /> |
2497 | - |
2498 | -<p>There is a little abstraction here:</p> |
2499 | -<ul> |
2500 | -<li>we need a general message-sending method (<code>displayMessage()</code>) for any |
2501 | -message that gets sent to all users;</li> |
2502 | -<li>for user chat messages, we need something that will prepend the username so |
2503 | -that everyone knows who said what (<code>displayUserMessage()</code>), and once this method |
2504 | -does its thing, it passes the adjusted message on to <code>displayMessage()</code>.</li> |
2505 | -</ul> |
2506 | - |
2507 | -<p>Other than that, this is very straight-forward code; it's pretty much |
2508 | -the same as the "Echo" tutorial. The <code>display*()</code> methods |
2509 | -are only responsible for updating the UI, just as we would expect.</p> |
2510 | - |
2511 | -We also need the same glue that we demonstrated in the "Echo" example: |
2512 | - |
2513 | -<a href="listings/nevow/plugins/chatthing_package.py" class="py-listing" /> |
2514 | - |
2515 | -<h3>Writing the Server</h3> |
2516 | - |
2517 | -<p>The server code is a bit more complicated. We |
2518 | -anticipated this above in the "Architecture" section where we noted that |
2519 | -the Python code needs to receive, process and send messages.</p> |
2520 | - |
2521 | -<a href="listings/chatthing/chatterbox.py" class="py-listing" /> |
2522 | - |
2523 | -<p>There is something in our "Chat" code that is not at all present in the |
2524 | -"Echo" application: the <code>ChatRoom</code> object. We need this object for the |
2525 | -following functionality:</p> |
2526 | -<ul> |
2527 | -<li>a means of instantiating new <code>ChatterElement</code> clients;</li> |
2528 | -<li>a "singleton" instance for keeping track of all <code>ChatterElement</code> clients;</li> |
2529 | -<li>a means sending messages to all clients;</li> |
2530 | -</ul> |
2531 | - |
2532 | -<p>Let's look at the second two reasons first. In our "Chat" application, |
2533 | -a new <code>ChatterElement</code> is created whenever a user connects, |
2534 | -so we will have potentially many of these instances. In order |
2535 | -for our chat server to function as designed, it will need a way to |
2536 | -communicate with each of these. If we create an object that can keep the |
2537 | -<code>ChatterElement</code>es in a list, then it will be able to iterate that |
2538 | -list and call methods that, in turn, make remote calls to the JavaScript. |
2539 | -</p> |
2540 | - |
2541 | -<p>Because we need the chat room to be a singleton object, it |
2542 | -can only be instantiated once. But we need many instantiations of |
2543 | -<code>ChatterElement</code> -- one for each connection, in fact. So what do |
2544 | -we do? Well, in this case, we make one of the methods |
2545 | -of <code>ChatRoom</code> a factory for instantiating a |
2546 | -<code>ChatterElement</code>. Before we return the instance, though, we |
2547 | -append it to the list of instances that the <code>ChatRoom</code> |
2548 | -is keeping track of. |
2549 | -</p> |
2550 | - |
2551 | -<h3>Putting it All Together</h3> |
2552 | - |
2553 | - |
2554 | -<p>Now that we've got all the code in front of us, we can trace out exactly what happens:</p> |
2555 | - |
2556 | -<ol> |
2557 | -<li>the user loads the resource in their browser, and the template is rendered;</li> |
2558 | -<li>after typing a message in the input box, the user hits submit;</li> |
2559 | -<li>JavaScript client code calls to the server with the text the user submitted;</li> |
2560 | -<li>the server gets the message and shares it with all the connected |
2561 | -<code>ChatterElement</code>s;</li> |
2562 | -<li>each <code>ChatterElement</code> hears this message and passes it back to the JavaScript client;</li> |
2563 | -<li>the client prepends the username to the message and then updates the display with the complete message.</li> |
2564 | -</ol> |
2565 | - |
2566 | -<p> |
2567 | -Keep in mind that <code>ChatterElement</code> entails several duties: it |
2568 | -establishes a relationship with a room object, it "registers" a user (there's a |
2569 | -one-to-one mapping between users and <code>ChatterElement</code>), it sends |
2570 | -messages to the browser, and it receives messages from the chat room. Being a |
2571 | -<code>LiveElement</code> subclass, <code>ChatterElement</code> is also |
2572 | -responsible for the view (via the document factory). |
2573 | -</p> |
2574 | - |
2575 | - |
2576 | -<h3>Running with <code>twistd</code></h3> |
2577 | - |
2578 | -<p>One last bit of code that may seem odd is the <code>chat</code> |
2579 | -variable we define right after the <code>ChatRoom</code> class. What |
2580 | -is this? This is how we make all this cleverness work as a twisted |
2581 | -plugin. </p> |
2582 | - |
2583 | -<p>If you recall, in our "Echo" application, we ran the code with |
2584 | -the following command: |
2585 | -</p> |
2586 | - |
2587 | -<pre class="shell"> |
2588 | -twistd -n athena-widget --element=echothing.echobox.EchoElement |
2589 | -</pre> |
2590 | - |
2591 | -<p>The value we pass as the <code>--element</code> argument is the dotted |
2592 | -name of the <code>LiveElement</code> object of which our "web page" |
2593 | -is primarily comprised: the <code>EchoElement</code> object. In |
2594 | -our "Chat" application, we have more moving parts: not only |
2595 | -do we have the <code>ChatterElement</code> object, but we have the |
2596 | -<code>ChatRoom</code> object which is responsible for keeping track of |
2597 | -many <code>ChatterElement</code>es. By defining the <code>chat</code> |
2598 | -variable, we are accomplishing the following all at once: |
2599 | -</p> |
2600 | - |
2601 | -<ul> |
2602 | -<li>providing a variable that can be accessed as a dotted name and thus |
2603 | -used when starting the server (<code>chatthing.chatterbox.chat</code>);</li> |
2604 | -<li>creating a singleton of <code>ChatRoom</code> (via the "magic" |
2605 | -of Python module-level instantiations);</li> |
2606 | -<li>making use of a factory, that when called, will both return a |
2607 | -new <code>ChatterElement</code> instance <i>and</i> add itself to the |
2608 | -<code>ChatRoom</code>.</li> |
2609 | -</ul> |
2610 | - |
2611 | -<p>Running this version of our code is a little bit different than the |
2612 | -"Echo" version. This is because of the <code>ChatRoom</code> code we |
2613 | -discussed above. As such, we pass a factory as our element, like so:</p> |
2614 | - |
2615 | -<pre class="shell"> |
2616 | -cd Nevow/doc/howto/chattutorial/part01/listings |
2617 | -twistd -n athena-widget --element=chatthing.chatterbox.chat |
2618 | -</pre> |
2619 | - |
2620 | -<p>If you executed this against the tutorial code on your local machine, |
2621 | -you can now visit <a href="http://localhost:8080/">http://localhost:8080/</a> |
2622 | -and start chatting to your heart's content.</p> |
2623 | - |
2624 | -<h2>Summary</h2> |
2625 | -<p> |
2626 | -Unlike our echo application, the chat application has some real functionality |
2627 | -and does some useful stuff: supporting user chats via browser/server two-way |
2628 | -communications. It should be evident now how the echo application provided a |
2629 | -basic conceptual and (partially) functional foundation upon which our chat work |
2630 | -could be based. |
2631 | -</p> |
2632 | -</body> |
2633 | -</html> |
2634 | |
2635 | === removed directory 'Nevow/doc/howto/chattutorial/part01/listings' |
2636 | === removed directory 'Nevow/doc/howto/chattutorial/part01/listings/chatthing' |
2637 | === removed file 'Nevow/doc/howto/chattutorial/part01/listings/chatthing/__init__.py' |
2638 | --- Nevow/doc/howto/chattutorial/part01/listings/chatthing/__init__.py 2008-09-03 20:03:47 +0000 |
2639 | +++ Nevow/doc/howto/chattutorial/part01/listings/chatthing/__init__.py 1970-01-01 00:00:00 +0000 |
2640 | @@ -1,1 +0,0 @@ |
2641 | - |
2642 | |
2643 | === removed file 'Nevow/doc/howto/chattutorial/part01/listings/chatthing/chatterbox.py' |
2644 | --- Nevow/doc/howto/chattutorial/part01/listings/chatthing/chatterbox.py 2008-09-03 20:03:47 +0000 |
2645 | +++ Nevow/doc/howto/chattutorial/part01/listings/chatthing/chatterbox.py 1970-01-01 00:00:00 +0000 |
2646 | @@ -1,48 +0,0 @@ |
2647 | -from twisted.python.util import sibpath |
2648 | -from nevow.loaders import xmlfile |
2649 | -from nevow.athena import LiveElement, expose |
2650 | - |
2651 | -class ChatRoom(object): |
2652 | - |
2653 | - def __init__(self): |
2654 | - self.chatters = [] |
2655 | - |
2656 | - def wall(self, message): |
2657 | - for chatter in self.chatters: |
2658 | - chatter.wall(message) |
2659 | - |
2660 | - def tellEverybody(self, who, what): |
2661 | - for chatter in self.chatters: |
2662 | - chatter.hear(who.username, what) |
2663 | - |
2664 | - def makeChatter(self): |
2665 | - elem = ChatterElement(self) |
2666 | - self.chatters.append(elem) |
2667 | - return elem |
2668 | - |
2669 | -# element to be run with twistd |
2670 | -chat = ChatRoom().makeChatter |
2671 | - |
2672 | -class ChatterElement(LiveElement): |
2673 | - |
2674 | - docFactory = xmlfile(sibpath(__file__, 'template.html')) |
2675 | - jsClass = u'ChatThing.ChatterWidget' |
2676 | - |
2677 | - def __init__(self, room): |
2678 | - self.room = room |
2679 | - |
2680 | - def setUsername(self, username): |
2681 | - self.username = username |
2682 | - message = ' * user '+username+' has joined the room' |
2683 | - self.room.wall(message) |
2684 | - setUsername = expose(setUsername) |
2685 | - |
2686 | - def say(self, message): |
2687 | - self.room.tellEverybody(self, message) |
2688 | - say = expose(say) |
2689 | - |
2690 | - def wall(self, message): |
2691 | - self.callRemote('displayMessage', message) |
2692 | - |
2693 | - def hear(self, username, what): |
2694 | - self.callRemote('displayUserMessage', username, what) |
2695 | |
2696 | === removed directory 'Nevow/doc/howto/chattutorial/part01/listings/chatthing/js' |
2697 | === removed file 'Nevow/doc/howto/chattutorial/part01/listings/chatthing/js/ChatThing.js' |
2698 | --- Nevow/doc/howto/chattutorial/part01/listings/chatthing/js/ChatThing.js 2009-01-21 22:58:03 +0000 |
2699 | +++ Nevow/doc/howto/chattutorial/part01/listings/chatthing/js/ChatThing.js 1970-01-01 00:00:00 +0000 |
2700 | @@ -1,42 +0,0 @@ |
2701 | -// import Nevow.Athena |
2702 | - |
2703 | -Nevow.Athena.Widget.subclass(ChatThing, 'ChatterWidget').methods( |
2704 | - function __init__(self, node) { |
2705 | - ChatThing.ChatterWidget.upcall(self, "__init__", node); |
2706 | - self.chooseBox = self.nodeByAttribute('name', 'chooseBox'); |
2707 | - self.scrollArea = self.nodeByAttribute('name', 'scrollArea'); |
2708 | - self.sendLine = self.nodeByAttribute('name', 'sendLine'); |
2709 | - self.usernameField = self.nodeByAttribute('name', 'username'); |
2710 | - self.userMessage = self.nodeByAttribute('name', 'userMessage'); |
2711 | - self.loggedInAs = self.nodeByAttribute('name', 'loggedInAs'); |
2712 | - }, |
2713 | - |
2714 | - function doSetUsername(self) { |
2715 | - var username = self.usernameField.value; |
2716 | - self.callRemote("setUsername", username).addCallback( |
2717 | - function (result) { |
2718 | - self.chooseBox.style.display = "none"; |
2719 | - self.sendLine.style.display = "block"; |
2720 | - self.loggedInAs.appendChild(document.createTextNode(username)); |
2721 | - self.loggedInAs.style.display = "block"; |
2722 | - }); |
2723 | - return false; |
2724 | - }, |
2725 | - |
2726 | - function doSay(self) { |
2727 | - self.callRemote("say", self.userMessage.value); |
2728 | - self.nodeByAttribute('name', 'userMessage').value = ""; |
2729 | - return false; |
2730 | - }, |
2731 | - |
2732 | - function displayMessage(self, message) { |
2733 | - var newNode = document.createElement('div'); |
2734 | - newNode.appendChild(document.createTextNode(message)); |
2735 | - self.scrollArea.appendChild(newNode); |
2736 | - document.body.scrollTop = document.body.scrollHeight; |
2737 | - }, |
2738 | - |
2739 | - function displayUserMessage(self, avatarName, text) { |
2740 | - var msg = avatarName+': '+text; |
2741 | - self.displayMessage(msg); |
2742 | - }); |
2743 | |
2744 | === removed file 'Nevow/doc/howto/chattutorial/part01/listings/chatthing/template.html' |
2745 | --- Nevow/doc/howto/chattutorial/part01/listings/chatthing/template.html 2008-09-03 20:03:47 +0000 |
2746 | +++ Nevow/doc/howto/chattutorial/part01/listings/chatthing/template.html 1970-01-01 00:00:00 +0000 |
2747 | @@ -1,20 +0,0 @@ |
2748 | -<div xmlns:nevow="http://nevow.com/ns/nevow/0.1" |
2749 | - xmlns:athena="http://divmod.org/ns/athena/0.7" |
2750 | - nevow:render="liveElement"> |
2751 | - <h2>Chatter Element</h2> |
2752 | - <form name="chatBox"> |
2753 | - <athena:handler event="onsubmit" handler="doSay" /> |
2754 | - <div name="scrollArea" |
2755 | - style="border: 1px solid gray; padding: 5; margin: 5"> |
2756 | - </div> |
2757 | - <div name="sendLine" style="display: none"> |
2758 | - <input name="userMessage" /><input type="submit" value="Send" /> |
2759 | - </div> |
2760 | - </form> |
2761 | - <form name="chooseBox"> |
2762 | - <athena:handler event="onsubmit" handler="doSetUsername" /> |
2763 | - Choose your username: <input name="username" /> |
2764 | - <input type="submit" name="GO" value="Enter"/> |
2765 | - </form> |
2766 | - <div name="loggedInAs" style="display:none"><span>Logged in as </span></div> |
2767 | -</div> |
2768 | |
2769 | === removed directory 'Nevow/doc/howto/chattutorial/part01/listings/nevow' |
2770 | === removed directory 'Nevow/doc/howto/chattutorial/part01/listings/nevow/plugins' |
2771 | === removed file 'Nevow/doc/howto/chattutorial/part01/listings/nevow/plugins/chatthing_package.py' |
2772 | --- Nevow/doc/howto/chattutorial/part01/listings/nevow/plugins/chatthing_package.py 2008-09-03 20:03:47 +0000 |
2773 | +++ Nevow/doc/howto/chattutorial/part01/listings/nevow/plugins/chatthing_package.py 1970-01-01 00:00:00 +0000 |
2774 | @@ -1,8 +0,0 @@ |
2775 | - |
2776 | -from twisted.python import util |
2777 | - |
2778 | -from nevow import athena |
2779 | - |
2780 | -import chatthing |
2781 | - |
2782 | -chatthingPkg = athena.AutoJSPackage(util.sibpath(chatthing.__file__, 'js')) |
2783 | |
2784 | === removed file 'Nevow/doc/howto/deployment.xhtml' |
2785 | --- Nevow/doc/howto/deployment.xhtml 2008-08-26 13:45:59 +0000 |
2786 | +++ Nevow/doc/howto/deployment.xhtml 1970-01-01 00:00:00 +0000 |
2787 | @@ -1,300 +0,0 @@ |
2788 | -<?xml version="1.0"?> |
2789 | -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" |
2790 | - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> |
2791 | - |
2792 | -<html xmlns="http://www.w3.org/1999/xhtml"> |
2793 | - <head> |
2794 | - <title> |
2795 | - Deployment |
2796 | - </title> |
2797 | - </head> |
2798 | - <body> |
2799 | - <h1>Deployment</h1> |
2800 | - |
2801 | - <p> |
2802 | - Nevow includes two major phases for deciding what HTML to render. <a |
2803 | - href="traversal.xhtml">Object Traversal</a> is the procedure by which a |
2804 | - URL is mapped to a Python object which will perform the HTML |
2805 | - generation. <a href="glossary.xhtml">Page Rendering</a> is the process by |
2806 | - which data objects are combined with an HTML template to produce the |
2807 | - final output. |
2808 | - </p> |
2809 | - |
2810 | - <p> |
2811 | - Before any of this can take place, however, we must have an environment |
2812 | - in which our Python code can run in response to an HTTP request, and HTML |
2813 | - can be returned to the browser for rendering. This is called the |
2814 | - <a href="glossary.xhtml">Deployment Environment</a>. |
2815 | - </p> |
2816 | - |
2817 | - <p> |
2818 | - There are various deployment options for Nevow page code: |
2819 | - </p> |
2820 | - |
2821 | - <ul> |
2822 | - <li> |
2823 | - CGI: Simple deployment in almost any HTTP server |
2824 | - </li> |
2825 | - <li> |
2826 | - WSGI: A more complete and flexible way for deploying on many HTTP |
2827 | - servers |
2828 | - </li> |
2829 | - <li> |
2830 | - Twisted.Web: A standalone application server process which includes a |
2831 | - built-in HTTP server |
2832 | - </li> |
2833 | - <li> |
2834 | - Zomne: A small CGI which hands off HTTP requests to a long-running |
2835 | - application server process, similar to FastCGI or SCGI |
2836 | - </li> |
2837 | - </ul> |
2838 | - |
2839 | - <h2>CGI</h2> |
2840 | - |
2841 | - <p> |
2842 | - You can deploy Nevow on any webserver which uses the Common Gateway |
2843 | - Interface. Using this method, your code is responsible for properly |
2844 | - formatting and outputting the HTTP response headers, and Nevow is used |
2845 | - only to generate the HTML body of your page. Here is the simplest |
2846 | - possible CGI: |
2847 | - </p> |
2848 | - |
2849 | - <pre class="python"> |
2850 | -#!/usr/bin/env python |
2851 | - |
2852 | -print "Content-type: text/plain\r\n\r\n", |
2853 | - |
2854 | -from nevow import rend, loaders |
2855 | - |
2856 | -class HelloWorld(rend.Page): |
2857 | - docFactory = loaders.stan("Hello, world!") |
2858 | - |
2859 | -print HelloWorld().renderSynchronously() |
2860 | - </pre> |
2861 | - |
2862 | - <p> |
2863 | - With this simple CGI you can use the Nevow template loaders and standard |
2864 | - nevow template interpolation techniques in your CGIs. However, you do not |
2865 | - get any <a href="traversal.xhtml">Object Traversal</a> features, and you |
2866 | - have to generate HTTP headers yourself. WSGI is a slightly higher-level |
2867 | - deployment option which does not suffer these problems. |
2868 | - </p> |
2869 | - |
2870 | - <h2>WSGI</h2> |
2871 | - |
2872 | - <p> |
2873 | - WSGI is a python interface for plugging web applications into various |
2874 | - HTTP server architectures. It is described in <a |
2875 | - href="http://www.python.org/peps/pep-0333.html">PEP 333</a>, the Python |
2876 | - Web Services Gateway Interface Python Enhancement Proposal. Nevow |
2877 | - includes the <code class="API">nevow.wsgi</code> module, which includes a |
2878 | - <code>createWSGIApplication</code> function which takes a Page and |
2879 | - returns a standard WSGI application callable. With the help of the |
2880 | - <code>run_with_cgi</code> example gateway from the PEP (which I will omit |
2881 | - here), our CGI example becomes shorter: |
2882 | - </p> |
2883 | - |
2884 | - <pre class="python"> |
2885 | -#!/usr/bin/env python |
2886 | - |
2887 | -from nevow import rend, loaders, wsgi |
2888 | - |
2889 | -class HelloWorld(rend.Page): |
2890 | - docFactory = loaders.stan("Hello, world!") |
2891 | - |
2892 | -run_with_cgi(wsgi.createWSGIApplication(HelloWorld())) |
2893 | - </pre> |
2894 | - |
2895 | - <p> |
2896 | - Of course, you can use any available WSGI gateway to publish your |
2897 | - application object, such as one of the gateways which comes with the <a |
2898 | - href="http://peak.telecommunity.com/">PEAK</a> toolkit. For example, here |
2899 | - is a simple python module which creates a WSGI application which we will |
2900 | - then deploy with PEAK's SimpleHTTPServer gateway:: |
2901 | - </p> |
2902 | - |
2903 | - <pre class="python"> |
2904 | -## helloworld.py |
2905 | - |
2906 | -from nevow import rend, loaders, wsgi |
2907 | - |
2908 | -class HelloWorld(rend.Page): |
2909 | - docFactory = loaders.stan("Hello, world!") |
2910 | - |
2911 | -application = wsgi.createWSGIApplication(HelloWorld()) |
2912 | - </pre> |
2913 | - |
2914 | - <p> |
2915 | - Save this file as "helloworld.py" somewhere on your PYTHONPATH and then |
2916 | - run the following command: |
2917 | - </p> |
2918 | - |
2919 | - <pre>peak launch WSGI import:helloworld.application</pre> |
2920 | - |
2921 | - <p> |
2922 | - This will bring up a SimpleHTTPServer running your Nevow code and launch |
2923 | - a web browser to view the output. (TODO: I couldn't get this working |
2924 | - immediately but I will seek assistance with PEAK and update the |
2925 | - instructions once I do.) |
2926 | - </p> |
2927 | - |
2928 | - <h2>Twisted.Web</h2> |
2929 | - |
2930 | - <p> |
2931 | - A convenient and powerful way to deploy Nevow applications is inside a |
2932 | - process running the twisted.web HTTP server. With Python, Twisted, and |
2933 | - Nevow installed, you have all you need to run a Web Application, with no |
2934 | - other dependencies or external HTTP servers such as Apache |
2935 | - required. Running your Nevow applications under twisted.web also gives |
2936 | - you access to some of the more advanced "Live" features of Nevow, such as |
2937 | - <code>nevow.livepage</code> and <code>nevow.canvas</code>. Currently, |
2938 | - these modules require more control over the HTTP socket than CGI or WSGI |
2939 | - can provide. (This may change in the future.) |
2940 | - </p> |
2941 | - |
2942 | - <p> |
2943 | - Deploying a Nevow application under twisted.web requires a little more |
2944 | - boilerplate, but can be considerably easier to set up than other |
2945 | - deployment options because there are no external dependencies. Note that |
2946 | - normally you should declare your Page classes in modules external to the |
2947 | - twisted configuration file, but everything is included in one file here |
2948 | - for brevity. Here is the minimal configuration file required to use |
2949 | - Nevow with twisted.web: |
2950 | - </p> |
2951 | - |
2952 | - <pre class="python"> |
2953 | -from nevow import rend, loaders, appserver |
2954 | - |
2955 | -class HelloWorld(rend.Page): |
2956 | - docFactory = loaders.stan("Hello, world!") |
2957 | - |
2958 | -from twisted.application import service, internet |
2959 | -application = service.Application("hello-world") |
2960 | -internet.TCPServer(8080, appserver.NevowSite(HelloWorld())).setServiceParent(application) |
2961 | - </pre> |
2962 | - |
2963 | - <p> |
2964 | - Save this file as "helloworld.tac" and start the server using the |
2965 | - command: |
2966 | - </p> |
2967 | - |
2968 | - <pre>twistd -noy helloworld.tac</pre> |
2969 | - |
2970 | - <p> |
2971 | - Then visit your twisted.web server by viewing the url |
2972 | - "http://localhost:8080/" in your browser. See the twistd man page for |
2973 | - more information about what twistd is capable of, including daemonizing |
2974 | - the HTTP server. |
2975 | - </p> |
2976 | - |
2977 | - <h2>Zomne</h2> |
2978 | - |
2979 | - <p> |
2980 | - <em>Warning</em> Zomne is experimental. It may blow up your computer and |
2981 | - require your first born son as a sacrifice. Zomne also only works in |
2982 | - UNIX-like environments where unix domain sockets are available, and may |
2983 | - not work on windows. |
2984 | - </p> |
2985 | - |
2986 | - <p> |
2987 | - Zomne, or "Zombie Nevow", is a CGI written in C which can start up a |
2988 | - long-running Application Server process if one is not already running. It |
2989 | - then uses a simple custom protocol to transmit information about the HTTP |
2990 | - request from the CGI process to the application server process. |
2991 | - </p> |
2992 | - |
2993 | - <p> |
2994 | - Zomne combines the ease of deployment of the CGI environment with the |
2995 | - speed and flexibility of the twisted.web long-running application server |
2996 | - process model. |
2997 | - </p> |
2998 | - |
2999 | - <p> |
3000 | - To use Zomne, you must first compile the CGI. cd into the directory |
3001 | - created when unpacking the Nevow tarball, and compile the CGI: |
3002 | - </p> |
3003 | - |
3004 | - <pre>% gcc zomne.c</pre> |
3005 | - |
3006 | - <p> |
3007 | - Move it into your cgi-bin: |
3008 | - </p> |
3009 | - |
3010 | - <pre>% mv a.out /Library/WebServer/CGI-Executables/nevow.cgi</pre> |
3011 | - |
3012 | - <p> |
3013 | - Create a file which tells the cgi where to look for the application: |
3014 | - </p> |
3015 | - |
3016 | - <pre> |
3017 | -% cat > /Library/WebServer/CGI-Executables/.nevow.cgi.dir |
3018 | -/Users/dp/zomne-test |
3019 | -^D</pre> |
3020 | - |
3021 | - <p> |
3022 | - The CGI name can be anything, as long as there is a file with a prepended |
3023 | - "." and a postfixed ".dir" in the same directory which contains the full |
3024 | - path of a zomne application directory. Next, create the application |
3025 | - directory: |
3026 | - </p> |
3027 | - |
3028 | - <pre>mkdir /Users/dp/zomne-test</pre> |
3029 | - |
3030 | - <p> |
3031 | - Finally, create the zomne.tac file which the zomne.cgi will execute to |
3032 | - start the long-running application server process: |
3033 | - </p> |
3034 | - |
3035 | - <pre class="python"> |
3036 | -from nevow import rend, loaders, zomnesrv |
3037 | - |
3038 | -class HelloWorld(rend.Page): |
3039 | - docFactory = loaders.stan("Hello, world!") |
3040 | - |
3041 | -from twisted.application import service, internet |
3042 | -application = service.Application('nevow-zomne-test') |
3043 | -internet.UNIXServer('zomne.socket', zomnesrv.ZomneFactory(HelloWorld())).setServiceParent(application) |
3044 | - </pre> |
3045 | - |
3046 | - <p> |
3047 | - Now, visiting the nevow.cgi URL through the web should render the Hello |
3048 | - World page, after a pause while the server is starting up. Subsequent |
3049 | - requests should be very fast, because the application server is already |
3050 | - running, and the CGI merely has to forward the request to it. |
3051 | - </p> |
3052 | - |
3053 | - <p> |
3054 | - Another useful capability of the zomne CGI process is the ability to |
3055 | - control environment variables the CGI will use. Create a directory named |
3056 | - "zomne_environ" in the application directory, and fill it with text files |
3057 | - whose name will be the environment key and whose contents will be the |
3058 | - environment value: |
3059 | - </p> |
3060 | - |
3061 | - <pre> |
3062 | -% cd zomne-test |
3063 | -% mkdir zomne-environ |
3064 | -% cd zomne-environ |
3065 | -% cat > PYTHONPATH |
3066 | -/Users/dp/Projects/Nevow:/Users/dp/Projects/helloworld |
3067 | -^D</pre> |
3068 | - |
3069 | - <h2>Conclusion</h2> |
3070 | - |
3071 | - <p> |
3072 | - Nevow may be deployed in a number of environments, from the most |
3073 | - restrictive to the most permissive. Writing a CGI can be an easy way to |
3074 | - try out the Nevow templating mechanism, but can be slow. A long-running |
3075 | - application server process can be a good way to get good performance as |
3076 | - well as additional features such as in-memory server-side sessions, |
3077 | - advanced automatic form handling with formless, and live page updating |
3078 | - features such as nevow.livepage and nevow.canvas. |
3079 | - </p> |
3080 | - |
3081 | - <p> |
3082 | - Which deployment option you choose will depend on the amount of control |
3083 | - you have over your deployment environment, and what advanced features |
3084 | - your application will require. |
3085 | - </p> |
3086 | - </body> |
3087 | -</html> |
3088 | |
3089 | === removed file 'Nevow/doc/howto/gettingstarted.xhtml' |
3090 | --- Nevow/doc/howto/gettingstarted.xhtml 2008-08-26 13:45:59 +0000 |
3091 | +++ Nevow/doc/howto/gettingstarted.xhtml 1970-01-01 00:00:00 +0000 |
3092 | @@ -1,110 +0,0 @@ |
3093 | -<?xml version="1.0"?> |
3094 | -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" |
3095 | - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> |
3096 | - |
3097 | -<html xmlns="http://www.w3.org/1999/xhtml"> |
3098 | - <head> |
3099 | - <title> |
3100 | - Getting Started |
3101 | - </title> |
3102 | - </head> |
3103 | - <body> |
3104 | - <h1>Getting Started</h1> |
3105 | - |
3106 | - <p> |
3107 | - Warning: This document has only just been started. It's not going to get |
3108 | - you very far right now. |
3109 | - </p> |
3110 | - |
3111 | - <p> |
3112 | - Nevow is a reasonably large library and can be quite daunting at |
3113 | - first. This document's aim is to guide the first time user in building a |
3114 | - Nevow application. |
3115 | - </p> |
3116 | - |
3117 | - <h2>Our First Application</h2> |
3118 | - |
3119 | - <p> |
3120 | - Let's dive straight in, here's the code for our first (very, very simple) |
3121 | - application. Create the following module, helloworld.py: |
3122 | - </p> |
3123 | - |
3124 | - <a href="listings/gettingstarted/helloworld.py" class="py-listing"> |
3125 | - helloworld.py |
3126 | - </a> |
3127 | - |
3128 | - <p> |
3129 | - It looks quite simple but let's walk through it anyway. |
3130 | - </p> |
3131 | - |
3132 | - <p> |
3133 | - First, we import two Nevow modules. <code |
3134 | - class="API">nevow.loaders</code> contains template loaders of which the |
3135 | - two most useful are <code class="API" base="nevow.loaders">xmlfile</code> |
3136 | - and <code class="API" base="nevow.loaders">stan</code>. |
3137 | - <code>xmlfile</code> can load any well-formed XML (i.e. XHTML) file; |
3138 | - <code>stan</code> loads a stan tree (more on these later). The other |
3139 | - module, <code class="API">nevow.rend</code>, contains all Nevow's |
3140 | - standard renders, many of which we'll meet in this document. |
3141 | - </p> |
3142 | - |
3143 | - <p> |
3144 | - We then define the <code>HelloWorld</code> class that subclasses <code |
3145 | - class="API" base="nevow">rend.Page</code>, Nevow's main resource |
3146 | - class. <code>HelloWorld</code> has two class |
3147 | - attributes. <code>addSlash</code> tells <code>rend.Page</code> to |
3148 | - redirect to a version of the request URL that ends in a <code>/</code> if |
3149 | - necessary. You generally want to set this to <code>True</code> for the |
3150 | - root resource. <code>docFactory</code> tells the page instance where to |
3151 | - get the template from. In this case we're providing a loader that parses |
3152 | - an HTML file (not shown) from disk. |
3153 | - </p> |
3154 | - |
3155 | - <p> |
3156 | - Hmm, ok I hear you say but how do I see it. Well, Twisted provides a good |
3157 | - web server which we can use. Twisted also includes a clever little |
3158 | - application for starting Twisted applications. Here's the helloworld.tac |
3159 | - file, a Twisted Application Configuration: |
3160 | - </p> |
3161 | - |
3162 | - <a href="listings/gettingstarted/helloworld.tac" class="py-listing"> |
3163 | - helloworld.tac |
3164 | - </a> |
3165 | - |
3166 | - <p> |
3167 | - Give it a go, run the following and connect to <a |
3168 | - href="http://localhost:8080/">http://localhost:8080/</a> to see your |
3169 | - application: |
3170 | - </p> |
3171 | - |
3172 | - <pre>twistd -ny helloworld.tac</pre> |
3173 | - |
3174 | - <p> |
3175 | - You'll probably notice that you get log output on the console. This is |
3176 | - just one of the good things that twistd does. It can also daemonize the |
3177 | - application, shed privileges if run as root, etc. |
3178 | - </p> |
3179 | - |
3180 | - <p> |
3181 | - TAC files are covered in more detail in the Twisted documentation but |
3182 | - let's quickly explain what all this does anyway. |
3183 | - </p> |
3184 | - |
3185 | - <p> |
3186 | - When <code class="shell">twistd</code> starts up it loads the |
3187 | - <code>.tac</code> file (it's just Python) and looks for the attribute |
3188 | - called <code>application</code>. When <code class="shell">twistd</code> |
3189 | - is all ready to go it starts the <code>application</code>. |
3190 | - </p> |
3191 | - |
3192 | - <p> |
3193 | - The application is not much use unless it actually does something so the |
3194 | - next thing we do is create a <code class="API" |
3195 | - base="nevow.appserver">NevowSite</code> instance, <code>site</code>, and |
3196 | - pass it a root resource, a <code>HelloWorld</code> instance. Finally, we |
3197 | - create a TCP server that makes the site available on port 8080 and bind |
3198 | - the server to the application to ensure the server is started when the |
3199 | - application is started. |
3200 | - </p> |
3201 | - </body> |
3202 | -</html> |
3203 | |
3204 | === removed file 'Nevow/doc/howto/glossary.xhtml' |
3205 | --- Nevow/doc/howto/glossary.xhtml 2010-04-06 11:05:45 +0000 |
3206 | +++ Nevow/doc/howto/glossary.xhtml 1970-01-01 00:00:00 +0000 |
3207 | @@ -1,82 +0,0 @@ |
3208 | -<?xml version="1.0"?> |
3209 | -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" |
3210 | - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> |
3211 | - |
3212 | -<html xmlns="http://www.w3.org/1999/xhtml"> |
3213 | - <head> |
3214 | - <title> |
3215 | - Glossary |
3216 | - </title> |
3217 | - </head> |
3218 | - <body> |
3219 | - <h1>Glossary</h1> |
3220 | - |
3221 | - <h2>Object Traversal</h2> |
3222 | - |
3223 | - <p> |
3224 | - The process by which a Python object is located to render HTML for a |
3225 | - given HTTP URL. For example, given the URL http://example.com/foo/bar, |
3226 | - Object Traversal will begin at the "Root Resource" object by asking it |
3227 | - for an object which is capable of rendering the page at ('foo', |
3228 | - 'bar'). The "Root Resource" returns an object and a list of unhandled |
3229 | - path segments, and the traversal continues across this new Resource |
3230 | - object until all path segments have been consumed. |
3231 | - </p> |
3232 | - |
3233 | - <h2>Page Rendering</h2> |
3234 | - |
3235 | - <p> |
3236 | - The process by which a Python object, usually a rend.Page subclass, turns |
3237 | - itself into HTML. Page Rendering involves locating some page data, |
3238 | - loading a template document, and applying the template to the data, in |
3239 | - the process generating HTML. |
3240 | - </p> |
3241 | - |
3242 | - <h2>Deployment Environment</h2> |
3243 | - |
3244 | - <p> |
3245 | - The environment in which a Nevow application is deployed. Generally |
3246 | - involves an HTTP server which is configured to route certain (or all) |
3247 | - HTTP requests through the Nevow Object Traversal and Page Rendering |
3248 | - process. Deployment environments include CGI, WSGI, and twisted.web. |
3249 | - </p> |
3250 | - |
3251 | - <h2>DOM</h2> |
3252 | - |
3253 | - <p> |
3254 | - Document Object Model. A tree of objects which represent the structure of |
3255 | - an XHTML document in memory. Nevow uses a nonstandard DOM named "stan", |
3256 | - which is made up of simple Python lists, dicts, strings, and |
3257 | - nevow.stan.Tag instances. |
3258 | - </p> |
3259 | - |
3260 | - <h2>Flattener</h2> |
3261 | - |
3262 | - <p> |
3263 | - A Python function which knows how to translate from a rich type to a |
3264 | - string containing HTML. For example, the integer flattener calls str() on |
3265 | - the integer. The string flattener escapes characters which are unsafe in |
3266 | - HTML, such as <, >, and &. |
3267 | - </p> |
3268 | - |
3269 | - <h2>Tag</h2> |
3270 | - |
3271 | - <p> |
3272 | - A class, defined at nevow.stan.Tag, which holds information about a |
3273 | - single HTML tag in a DOM. Tag instances have three attributes: tagName, |
3274 | - attributes, and children. tagName is a string indicating the tag |
3275 | - name. attributes is a dict indicating the HTML attributes of that |
3276 | - node. children is a list indicating the child nodes of that node. |
3277 | - </p> |
3278 | - |
3279 | - <h2>Tag Specials</h2> |
3280 | - |
3281 | - <p> |
3282 | - A Tag attribute which is "special" to nevow. Tag specials include data, |
3283 | - render, pattern, slot, and macro. Tag Specials will never be output as |
3284 | - HTML attributes of tags, but will be used by the internal Nevow rendering |
3285 | - process to influence how the Tag is rendered. |
3286 | - </p> |
3287 | - |
3288 | - </body> |
3289 | -</html> |
3290 | |
3291 | === removed file 'Nevow/doc/howto/index.xhtml' |
3292 | --- Nevow/doc/howto/index.xhtml 2008-09-20 01:06:47 +0000 |
3293 | +++ Nevow/doc/howto/index.xhtml 1970-01-01 00:00:00 +0000 |
3294 | @@ -1,49 +0,0 @@ |
3295 | -<?xml version="1.0"?> |
3296 | -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" |
3297 | - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> |
3298 | - |
3299 | -<html xmlns="http://www.w3.org/1999/xhtml"> |
3300 | - <head> |
3301 | - <title> |
3302 | - Manual |
3303 | - </title> |
3304 | - </head> |
3305 | - <body> |
3306 | - <h1> |
3307 | - Manual |
3308 | - </h1> |
3309 | - <ul class="toc"> |
3310 | - <li> |
3311 | - <a href="intro.xhtml">Introduction</a> |
3312 | - </li> |
3313 | - <li> |
3314 | - <a href="gettingstarted.xhtml">Getting Started</a> |
3315 | - <p>A basic introduction to rendering a web page in Nevow.</p> |
3316 | - </li> |
3317 | - <li> |
3318 | - <a href="traversal.xhtml">Object Traversal</a> |
3319 | - <p>Getting from an URL to a Python page object you want to render.</p> |
3320 | - </li> |
3321 | - <li> |
3322 | - <a href="publishing.xhtml">Object Publishing</a> |
3323 | - <p>Exposing Python objects as parts of a web page in Nevow.</p> |
3324 | - </li> |
3325 | - <li> |
3326 | - <a href="xmltemplates.xhtml">XML Templates</a> |
3327 | - <p>Using standard XHTML as a template for Nevow.</p> |
3328 | - </li> |
3329 | - <li> |
3330 | - <a href="deployment.xhtml">Deployment</a> |
3331 | - <p>How to get your Nevow application running on different types of |
3332 | - servers.</p> |
3333 | - </li> |
3334 | - <li> |
3335 | - <a href="chattutorial/index.xhtml">Nevow Athena</a> |
3336 | - <p>Two-way communication with JavaScript in a web browser.</p> |
3337 | - </li> |
3338 | - <li> |
3339 | - <a href="glossary.xhtml">Glossary</a> |
3340 | - </li> |
3341 | - </ul> |
3342 | - </body> |
3343 | -</html> |
3344 | |
3345 | === removed file 'Nevow/doc/howto/intro.xhtml' |
3346 | --- Nevow/doc/howto/intro.xhtml 2008-08-26 13:45:59 +0000 |
3347 | +++ Nevow/doc/howto/intro.xhtml 1970-01-01 00:00:00 +0000 |
3348 | @@ -1,294 +0,0 @@ |
3349 | -<?xml version="1.0"?> |
3350 | -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" |
3351 | - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> |
3352 | - |
3353 | -<html xmlns="http://www.w3.org/1999/xhtml"> |
3354 | - <head> |
3355 | - <title> |
3356 | - A Web Application Construction Kit |
3357 | - </title> |
3358 | - </head> |
3359 | - <body> |
3360 | - <h1>A Web Application Construction Kit</h1> |
3361 | - |
3362 | - <h2>Summary</h2> |
3363 | - |
3364 | - <p> |
3365 | - Nevow is a next-generation web application templating system, based on |
3366 | - the ideas developed in the Twisted Woven package. Its main focus is on |
3367 | - separating the HTML template from both the business logic and the display |
3368 | - logic, while allowing the programmer to write pure Python code as much as |
3369 | - possible. It separates your code into 'data' and 'render' functions, a |
3370 | - simplified implementation of traditional MVC. It has various parts which |
3371 | - can be used individually or as a whole, integrated web solution: |
3372 | - </p> |
3373 | - |
3374 | - <ul> |
3375 | - <li> |
3376 | - XHTML templates: contain no programming logic, only nodes tagged with |
3377 | - nevow attributes |
3378 | - </li> |
3379 | - <li> |
3380 | - data/render methods: simplified MVC |
3381 | - </li> |
3382 | - <li> |
3383 | - stan: An s-expression-like syntax for expressing xml in pure python |
3384 | - </li> |
3385 | - <li> |
3386 | - formless: For describing the types of objects which may be passed to |
3387 | - methods of your classes, validating and coercing string input from |
3388 | - either web or command-line sources, and calling your methods |
3389 | - automatically once validation passes |
3390 | - </li> |
3391 | - <li> |
3392 | - formless.webform: For rendering web forms based on formless type |
3393 | - descriptions, accepting form posts and passing them to formless |
3394 | - validators, and rendering error forms in the event validation fails |
3395 | - </li> |
3396 | - <li> |
3397 | - livepage: Cross-browser JavaScript glue for sending client side events |
3398 | - to the server and server side events to the client after the page has |
3399 | - loaded, without causing the entire page to refresh |
3400 | - </li> |
3401 | - </ul> |
3402 | - |
3403 | - <h2>Disk based templates</h2> |
3404 | - |
3405 | - <p> |
3406 | - Nevow includes the ability to load templates off disk. These templates |
3407 | - may have processing directives which cause the execution of python |
3408 | - methods at render time. The attribute technique was inspired by the |
3409 | - attributes used by ZPT. However, no actual code may be embedded in the |
3410 | - HTML template: |
3411 | - </p> |
3412 | - |
3413 | - <pre> |
3414 | -<html xmlns:nevow="http://nevow.com/ns/nevow/0.1"> |
3415 | - <head> |
3416 | - <title>Greetings!</title> |
3417 | - </head> |
3418 | - <body> |
3419 | - <h1 style="font-size: large">Now I will greet you:</h1> |
3420 | - <span nevow:render="greet" /> |
3421 | - </body> |
3422 | -</html></pre> |
3423 | - |
3424 | - <p> |
3425 | - This template can then be loaded and rendered like so: |
3426 | - </p> |
3427 | - |
3428 | - <pre class="python"> |
3429 | -class Greeter(rend.Page): |
3430 | - docFactory = loaders.xmlfile("Greeting.html") |
3431 | - |
3432 | - def render_greet(self, context, data): |
3433 | - return random.choice(["Hello", "Greetings", "Hi"]), " ", data |
3434 | - |
3435 | -Greeter("My name is").renderString() |
3436 | - </pre> |
3437 | - |
3438 | - <h2>data/render methods</h2> |
3439 | - |
3440 | - <p> |
3441 | - To allow clean isolation between code which fetches data from a data |
3442 | - source and code which renders the data into HTML, nevow allows you to |
3443 | - write both 'data' methods and 'render' methods. These concepts are |
3444 | - inspired by MVC, but simpler, since the framework can handle most of the |
3445 | - controller aspect. An example: |
3446 | - </p> |
3447 | - |
3448 | - <pre> |
3449 | -<html xmlns:nevow="http://nevow.com/ns/nevow/0.1"> |
3450 | - <body> |
3451 | - <span nevow:data="name" nevow:render="colorful" /> |
3452 | - <span nevow:data="fun" nevow:render="colorful" /> |
3453 | - </body> |
3454 | -</html></pre> |
3455 | - |
3456 | - <p> |
3457 | - This template can be loaded and rendered using a class such as this: |
3458 | - </p> |
3459 | - |
3460 | - <pre class="python"> |
3461 | -class Colorful(rend.Page): |
3462 | - docFactory = loaders.xmlfile("Colorful.html") |
3463 | - |
3464 | - def render_colorful(self, context, data): |
3465 | - color = random.choice(['red', 'green', 'blue']) |
3466 | - return context.tag(style="color: %s" % color) |
3467 | - |
3468 | - def data_name(self, context, data): |
3469 | - return "Your name here" |
3470 | - |
3471 | - def data_fun(self, context, data): |
3472 | - return "Are we having fun yet?" |
3473 | - </pre> |
3474 | - |
3475 | - <h2>Stan</h2> |
3476 | - |
3477 | - <p> |
3478 | - One of the most powerful things about nevow is stan, an s-expression-like |
3479 | - syntax for producing XML fragments in pure Python syntax. Stan is not |
3480 | - required for using nevow, but it is both a simple and powerful way to |
3481 | - both lay out one's XHTML templates and express one's display logic. A |
3482 | - brief example will illustrate its utility: |
3483 | - </p> |
3484 | - |
3485 | - <pre class="python"> |
3486 | -import random |
3487 | -from nevow import rend, tags |
3488 | - |
3489 | -class Greeter(rend.Page): |
3490 | - def greet(self, context, data): |
3491 | - return random.choice(["Hello", "Greetings", "Hi"]), " ", data |
3492 | - |
3493 | - docFactory = loaders.stan( |
3494 | - tags.html[ |
3495 | - tags.head[ tags.title[ "Greetings!" ]], |
3496 | - tags.body[ |
3497 | - tags.h1(style="font-size: large")[ "Now I will greet you:" ], |
3498 | - greet |
3499 | - ] |
3500 | - ]) |
3501 | - </pre> |
3502 | - |
3503 | - <p> |
3504 | - When the Greeter class is constructed, it is passed a Python object which |
3505 | - will be used as that page's data: |
3506 | - </p> |
3507 | - |
3508 | - <pre class="python"> |
3509 | -Greeter("Your name here").renderString() |
3510 | - </pre> |
3511 | - |
3512 | - <h2>Formless</h2> |
3513 | - |
3514 | - <p> |
3515 | - Python is dynamically typed, which means it has no built-in controls for |
3516 | - enforcing the types of objects which are passed to one's methods. This is |
3517 | - great for programmers, but not necessarily great if you are going to be |
3518 | - passing user-entered input to those methods. Formless is a simple way to |
3519 | - describe the types of objects that can be passed to one's methods, as |
3520 | - well as coerce from string input to those types. Other code can then |
3521 | - accept user input from a command line or from a web form, validate the |
3522 | - input against the types described using formless, and call the method |
3523 | - once validation has passed. A simple example: |
3524 | - </p> |
3525 | - |
3526 | - <pre class="python"> |
3527 | -from zope.interface import implements |
3528 | -from formless.annotate import TypedInterface, Integer, String |
3529 | - |
3530 | -class ISimpleMethod(TypedInterface): |
3531 | - def simple(self, |
3532 | - name=String(description="Your name."), |
3533 | - age=Integer(description="Your age.")): |
3534 | - """ |
3535 | - Simple |
3536 | - |
3537 | - Please enter your name and age. |
3538 | - """ |
3539 | - |
3540 | -class Implementation(object): |
3541 | - implements(ISimpleMethod) |
3542 | - |
3543 | - def simple(self, name, age): |
3544 | - print "Hello, %s, who is %s" % (name, age) |
3545 | - </pre> |
3546 | - |
3547 | - <h2>Webform</h2> |
3548 | - |
3549 | - <p> |
3550 | - Webform is a nevow module which will automatically render web forms and |
3551 | - accept form posts based on types described using the classes in |
3552 | - formless. Used in conjunction with the twisted.web HTTP server, the |
3553 | - process is almost automatic: |
3554 | - </p> |
3555 | - |
3556 | - <pre class="python"> |
3557 | -from nevow import rend, tags |
3558 | -from formless import webform |
3559 | - |
3560 | -class WebForm(rend.Page): |
3561 | - document = rend.stan( |
3562 | - tags.html[ |
3563 | - tags.body[ |
3564 | - h1["Here is the form:"], |
3565 | - webform.renderForms('original') |
3566 | - ] |
3567 | -]) |
3568 | - |
3569 | -resource = WebForm(Implementation()) |
3570 | - </pre> |
3571 | - |
3572 | - <p> |
3573 | - Exposing this resource instance to the web using twisted.web and visiting |
3574 | - it will cause a form with two input boxes to be rendered. Posting the |
3575 | - form will cause form validation to occur. Upon error, the user will be |
3576 | - returned to the original page, with the form annotated with error |
3577 | - messages. Upon success, the "simple" method of the Implementation |
3578 | - instance will be called and passed a string and an integer. |
3579 | - </p> |
3580 | - |
3581 | - <h2>LivePage</h2> |
3582 | - |
3583 | - <p> |
3584 | - LivePage was a Woven technology which allowed programmers to receive |
3585 | - server-side notification of client-side JavaScript events, and to send |
3586 | - JavaScript to the client in response to a server-side event. New for |
3587 | - Nevow 0.3, LivePage has been updated to support Mozilla, Firefox, IE6 |
3588 | - Win, and Safari. Using LivePage is very easy: |
3589 | - </p> |
3590 | - |
3591 | - <pre class="python"> |
3592 | -from nevow.liveevil import handler |
3593 | - |
3594 | -def greeter(client, nodeName): |
3595 | - client.alert("Greetings. You clicked the %s node." % nodeName) |
3596 | - |
3597 | -# Any string arguments after the event handler function will be evaluated |
3598 | -# as JavaScript in the context of the web browser and results passed to the |
3599 | -# Python event handler |
3600 | -handler = handler(greeter, 'node.name') |
3601 | - |
3602 | -class Live(rend.Page): |
3603 | - docFactory = loaders.stan( |
3604 | - tags.html[ |
3605 | - tags.body[ |
3606 | - ol[ |
3607 | - li(onclick=handler, name="one")["One"] |
3608 | - li(onclick=handler, name="two")["Two"] |
3609 | - li(onclick=handler, name="three")["Three"] |
3610 | - ] |
3611 | - ] |
3612 | - ]) |
3613 | - </pre> |
3614 | - |
3615 | - <h2>More Information</h2> |
3616 | - |
3617 | - <p> |
3618 | - The <a href="http://divmod.org/trac/wiki/DivmodNevow">Nevow website</a> |
3619 | - has more information. Starting with 0.3, it contains a simple WSGI |
3620 | - implementation and can also be used to render CGIs. However, the |
3621 | - recommended mode of operation is using the <a |
3622 | - href="http://twistedmatrix.com/trac/wiki/TwistedWeb">Twisted web</a> |
3623 | - server. Nevow is an active project, and many new bugfixes and features |
3624 | - are committed to the Nevow SVN repository. Information about Nevow |
3625 | - commits is available by subscribing to the <a |
3626 | - href="http://divmod.net/users/mailman.twistd/listinfo/divmod-commits"> |
3627 | - Divmod commits</a> mailing list. The Nevow SVN repository can be checked |
3628 | - out using: |
3629 | - </p> |
3630 | - |
3631 | - <pre>svn co svn://divmod.org/svn/Nevow/trunk Nevow</pre> |
3632 | - |
3633 | - <p> |
3634 | - Discussion of Nevow occurs on the <a |
3635 | - href="http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-web"> |
3636 | - twisted.web mailing list</a>. The Nevow developers are also often |
3637 | - available for real-time help on the <a |
3638 | - href="irc://irc.freenode.net/#twisted.web">#twisted.web channel</a> on |
3639 | - irc.freenode.net. |
3640 | - </p> |
3641 | - </body> |
3642 | -</html> |
3643 | |
3644 | === removed directory 'Nevow/doc/howto/listings' |
3645 | === removed directory 'Nevow/doc/howto/listings/gettingstarted' |
3646 | === removed file 'Nevow/doc/howto/listings/gettingstarted/helloworld.py' |
3647 | --- Nevow/doc/howto/listings/gettingstarted/helloworld.py 2008-08-26 13:45:59 +0000 |
3648 | +++ Nevow/doc/howto/listings/gettingstarted/helloworld.py 1970-01-01 00:00:00 +0000 |
3649 | @@ -1,6 +0,0 @@ |
3650 | -from nevow import loaders, rend |
3651 | - |
3652 | -class HelloWorld(rend.Page): |
3653 | - addSlash = True |
3654 | - docFactory = loaders.xmlfile('helloworld.html') |
3655 | - |
3656 | |
3657 | === removed file 'Nevow/doc/howto/listings/gettingstarted/helloworld.tac' |
3658 | --- Nevow/doc/howto/listings/gettingstarted/helloworld.tac 2008-08-26 13:45:59 +0000 |
3659 | +++ Nevow/doc/howto/listings/gettingstarted/helloworld.tac 1970-01-01 00:00:00 +0000 |
3660 | @@ -1,10 +0,0 @@ |
3661 | -from twisted.application import internet |
3662 | -from twisted.application import service |
3663 | -from nevow import appserver |
3664 | -import helloworld |
3665 | - |
3666 | -application = service.Application('helloworld') |
3667 | -site = appserver.NevowSite(helloworld.HelloWorld()) |
3668 | -webServer = internet.TCPServer(8080, site) |
3669 | -webServer.setServiceParent(application) |
3670 | - |
3671 | |
3672 | === removed file 'Nevow/doc/howto/publishing.xhtml' |
3673 | --- Nevow/doc/howto/publishing.xhtml 2008-08-26 13:45:59 +0000 |
3674 | +++ Nevow/doc/howto/publishing.xhtml 1970-01-01 00:00:00 +0000 |
3675 | @@ -1,658 +0,0 @@ |
3676 | -<?xml version="1.0"?> |
3677 | -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" |
3678 | - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> |
3679 | - |
3680 | -<html xmlns="http://www.w3.org/1999/xhtml"> |
3681 | - <head> |
3682 | - <title> |
3683 | - Object Publishing |
3684 | - </title> |
3685 | - </head> |
3686 | - <body> |
3687 | - <h1> |
3688 | - Object Publishing |
3689 | - </h1> |
3690 | - |
3691 | - <p> |
3692 | - In <a href="traversal.xhtml">Object Traversal</a>, we learned about the |
3693 | - <code class="API">nevow.inevow.IResource.renderHTTP</code> method, which |
3694 | - is the most basic way to send HTML to a browser when using |
3695 | - Nevow. However, it is not very convenient (or clean) to generate HTML |
3696 | - tags by concatenating strings in Python code. In the <a |
3697 | - href="deployment.xhtml">Deployment</a> documentation, we saw that it was |
3698 | - possible to render a <em>Hello World</em> page using a <code class="API"> |
3699 | - nevow.rend.Page</code> subclass and providing a <code>docFactory</code>: |
3700 | - </p> |
3701 | - |
3702 | - <pre class="python-interpreter"> |
3703 | ->>> from nevow import rend, loaders |
3704 | ->>> class HelloWorld(rend.Page): |
3705 | -... docFactory = loaders.stan("Hello, world!") |
3706 | -... |
3707 | ->>> HelloWorld().renderSynchronously() |
3708 | -'Hello, world!'</pre> |
3709 | - |
3710 | - <p> |
3711 | - This example does nothing interesting, but the concept of a loader is |
3712 | - important in Nevow. The <code>rend.Page.renderHTTP</code> implementation |
3713 | - always starts rendering HTML by loading a template from the |
3714 | - <code>docFactory</code>. |
3715 | - </p> |
3716 | - |
3717 | - |
3718 | - <h2>The stan DOM</h2> |
3719 | - |
3720 | - <p> |
3721 | - Nevow uses a DOM-based approach to rendering HTML. A tree of objects is |
3722 | - first constructed in memory by the template loader. This tree is then |
3723 | - processed one node at a time, applying functions which transform from |
3724 | - various Python types to HTML strings. |
3725 | - </p> |
3726 | - |
3727 | - <p> |
3728 | - Nevow uses a nonstandard DOM named "stan". Unlike the W3C DOM, stan is |
3729 | - made up of simple python lists, strings, and instances of the |
3730 | - nevow.stan.Tag class. During the rendering process, "Flattener" |
3731 | - functions convert from rich types to HTML strings. For example, we can |
3732 | - load a template made up of some nested lists and Python types, render it, |
3733 | - and see what happens: |
3734 | - </p> |
3735 | - |
3736 | - <pre class="python-interpreter"> |
3737 | ->>> class PythonTypes(rend.Page): |
3738 | -... docFactory = loaders.stan(["Hello", 1, 1.5, True, ["Goodbye", 3]]) |
3739 | -... |
3740 | ->>> PythonTypes().renderSynchronously() |
3741 | -'Hello11.5TrueGoodbye3'</pre> |
3742 | - |
3743 | - <h2>Tag instances</h2> |
3744 | - |
3745 | - <p> |
3746 | - So far, we have only rendered simple strings as output. However, the main |
3747 | - purpose of Nevow is HTML generation. In the stan DOM, HTML tags are |
3748 | - represented by instances of the <code class="API">nevow.stan.Tag</code> |
3749 | - class. <code>Tag</code> is a very simple class, whose instances have an |
3750 | - <code>attributes</code> dictionary and a <code>children</code> list. The |
3751 | - <code>Tag</code> flattener knows how to recursively flatten attributes |
3752 | - and children of the tag. To show you how <code>Tag</code>s really work |
3753 | - before you layer Nevow's convenience syntax on top, try this horrible |
3754 | - example: |
3755 | - </p> |
3756 | - |
3757 | - <pre class="python-interpreter"> |
3758 | ->>> from nevow import stan |
3759 | ->>> h = stan.Tag('html') |
3760 | ->>> d = stan.Tag('div') |
3761 | ->>> d.attributes['style'] = 'border: 1px solid black' |
3762 | ->>> h.children.append(d) |
3763 | ->>> class Tags(rend.Page): |
3764 | -... docFactory = loaders.stan(h) |
3765 | -... |
3766 | ->>> Tags().renderSynchronously() |
3767 | -'<html><div style="border: 1px solid black"></div></html>'</pre> |
3768 | - |
3769 | - <p> |
3770 | - So, we see how it is possible to programatically generate HTML by |
3771 | - constructing and nesting stan <code>Tag</code> instances. However, it is |
3772 | - far more convenient to use the overloaded operators <code>Tag</code> |
3773 | - provides to manipulate them. <code>Tag</code> implements a |
3774 | - <code>__call__</code> method which takes any keyword arguments and values |
3775 | - and updates the attributes dictionary; it also implements a |
3776 | - <code>__getitem__</code> method which takes whatever is between the square |
3777 | - brackets and appends them to the children list. A simple example should |
3778 | - clarify things: |
3779 | - </p> |
3780 | - |
3781 | - <pre class="python-interpreter"> |
3782 | ->>> class Tags2(rend.Page): |
3783 | -... docFactory = loaders.stan(stan.Tag('html')[stan.Tag('div')(style="border: 1px solid black")]) |
3784 | -... |
3785 | ->>> Tags2().renderSynchronously() |
3786 | -'<html><div style="border: 1px solid black"></div></html>'</pre> |
3787 | - |
3788 | - <p> |
3789 | - This isn't very easy to read, but luckily we can simplify the example |
3790 | - even further by using the nevow.tags module, which is full of "Tag |
3791 | - prototypes" for every tag type described by the XHTML 1.0 specification: |
3792 | - </p> |
3793 | - |
3794 | - <pre class="python-interpreter"> |
3795 | ->>> class Tags3(rend.Page): |
3796 | -... docFactory = loaders.stan(tags.html[tags.div(style="border: 1px solid black")]) |
3797 | -... |
3798 | ->>> Tags3().renderSynchronously() |
3799 | -'<html><div style="border: 1px solid black"></div></html>'</pre> |
3800 | - |
3801 | - <p> |
3802 | - Using stan syntax is not the only way to construct template DOM for use |
3803 | - by the Nevow rendering process. Nevow also includes <code class="API" |
3804 | - base="nevow">loaders.xmlfile</code> which implements a simple tag |
3805 | - attribute language similar to the Zope Page Templates (ZPT) Tag Attribute |
3806 | - Language (TAL). However, experience with the stan DOM should give you |
3807 | - insight into how the Nevow rendering process really works. Rendering a |
3808 | - template into HTML in Nevow is really nothing more than iterating a tree |
3809 | - of objects and recursively applying "Flattener" functions to objects in |
3810 | - this tree, until all HTML has been generated. |
3811 | - </p> |
3812 | - |
3813 | - <h2>Functions in the DOM</h2> |
3814 | - |
3815 | - <p> |
3816 | - So far, all of our examples have generated static HTML pages, which is |
3817 | - not terribly interesting when discussing dynamic web applications. Nevow |
3818 | - takes a very simple approach to dynamic HTML generation. If you put a |
3819 | - Python function reference in the DOM, Nevow will call it when the page is |
3820 | - rendered. The return value of the function replaces the function itself |
3821 | - in the DOM, and the results are flattened further. This makes it easy to |
3822 | - express looping and branching structures in Nevow, because normal Python |
3823 | - looping and branching constructs are used to do the job: |
3824 | - </p> |
3825 | - |
3826 | - <pre class="python-interpreter"> |
3827 | ->>> def repeat(ctx, data): |
3828 | -... return [tags.div(style="color: %s" % (color, )) |
3829 | -... for color in ['red', 'blue', 'green']] |
3830 | -... |
3831 | ->>> class Repeat(rend.Page): |
3832 | -... docFactory = loaders.stan(tags.html[repeat]) |
3833 | -... |
3834 | ->>> Repeat().renderSynchronously() |
3835 | -'<html><div style="color: red"></div><div style="color: blue"></div><div style="color: green"></div></html>'</pre> |
3836 | - |
3837 | - <p> |
3838 | - However, in the example above, the repeat function isn't even necessary, |
3839 | - because we could have inlined the list comprehension right where we |
3840 | - placed the function reference in the DOM. Things only really become |
3841 | - interesting when we begin writing parameterized render functions which |
3842 | - cause templates to render differently depending on the input to the web |
3843 | - application. |
3844 | - </p> |
3845 | - |
3846 | - <p> |
3847 | - The required signature of functions which we can place in the DOM is |
3848 | - (ctx, data). The "context" object is essentially opaque for now, and we |
3849 | - will learn how to extract useful information out of it later. The "data" |
3850 | - object is anything we want it to be, and can change during the rendering |
3851 | - of the page. By default, the data object is whatever we pass as the first |
3852 | - argument to the Page constructor, <em>or</em> the Page instance itself if |
3853 | - nothing is passed. Armed with this knowledge, we can create a Page which |
3854 | - renders differently depending on the data we pass to the Page |
3855 | - constructor: |
3856 | - </p> |
3857 | - |
3858 | - <pre class="python"> |
3859 | -class Root(rend.Page): |
3860 | - docFactory = loaders.stan(tags.html[ |
3861 | - tags.h1["Welcome."], |
3862 | - tags.a(href="foo")["Foo"], |
3863 | - tags.a(href="bar")["Bar"], |
3864 | - tags.a(href="baz")["Baz"]]) |
3865 | - |
3866 | - def childFactory(self, ctx, name): |
3867 | - return Leaf(name) |
3868 | - |
3869 | -def greet(ctx, name): |
3870 | - return "Hello. You are visiting the ", name, " page." |
3871 | - |
3872 | -class Leaf(rend.Page): |
3873 | - docFactory = loaders.stan(tags.html[greet]) |
3874 | - </pre> |
3875 | - |
3876 | - <p> |
3877 | - Armed with this knowledge and the information in the <a |
3878 | - href="traversal.xhtml">Object Traversal</a> documentation, we now have |
3879 | - enough information to create dynamic websites with arbitrary URL |
3880 | - hierarchies whose pages render dynamically depending on which URL was |
3881 | - used to access them. |
3882 | - </p> |
3883 | - |
3884 | - <h2>Accessing query parameters and form post data</h2> |
3885 | - |
3886 | - <p> |
3887 | - Before we move on to more advanced rendering techniques, let us first |
3888 | - examine how one could further customize the rendering of a Page based on |
3889 | - the URL query parameters and form post information provided to us by a |
3890 | - browser. Recall that URL parameters are expressed in the form: |
3891 | - </p> |
3892 | - |
3893 | - <pre>http://example.com/foo/bar?baz=1&quux=2</pre> |
3894 | - |
3895 | - <p> |
3896 | - And form post data can be generated by providing a form to a browser: |
3897 | - </p> |
3898 | - |
3899 | - <pre> |
3900 | -<form action="" method="POST"> |
3901 | - <input type="text" name="baz" /> |
3902 | - <input type="text" name="quux" /> |
3903 | - <input type="submit" /> |
3904 | -</form></pre> |
3905 | - |
3906 | - <p> |
3907 | - Accessing this information is such a common procedure that Nevow provides |
3908 | - a convenience method on the context to do it. Let's examine a simple page |
3909 | - whose output can be influenced by the query parameters in the URL used to |
3910 | - access it: |
3911 | - </p> |
3912 | - |
3913 | - <pre class="python"> |
3914 | -def showChoice(ctx, data): |
3915 | - choice = ctx.arg('choice') |
3916 | - if choice is None: |
3917 | - return '' |
3918 | - return "You chose ", choice, "." |
3919 | - |
3920 | -class Custom(rend.Page): |
3921 | - docFactory = loaders.stan(tags.html[ |
3922 | - tags.a(href="?choice=baz")["Baz"], |
3923 | - tags.a(href="?choice=quux")["Quux"], |
3924 | - tags.p[showChoice]]) |
3925 | - </pre> |
3926 | - |
3927 | - <p> |
3928 | - The procedure is exactly the same for simple form post information: |
3929 | - </p> |
3930 | - |
3931 | - <pre class="python"> |
3932 | -def greet(ctx, data): |
3933 | - name = ctx.arg('name') |
3934 | - if name is None: |
3935 | - return '' |
3936 | - return "Greetings, ", name, "!" |
3937 | - |
3938 | -class Form(rend.Page): |
3939 | - docFactory = loaders.stan(tags.html[ |
3940 | - tags.form(action="", method="POST")[ |
3941 | - tags.input(name="name"), |
3942 | - tags.input(type="submit")], |
3943 | - greet]) |
3944 | -</pre> |
3945 | - |
3946 | - <p> |
3947 | - Note that <code>ctx.arg</code> returns only the first argument with the |
3948 | - given name. For complex cases where multiple arguments and lists of |
3949 | - argument values are required, you can access the request argument |
3950 | - dictionary directly using the syntax: |
3951 | - </p> |
3952 | - |
3953 | - <pre class="python"> |
3954 | -def arguments(ctx, data): |
3955 | - args = inevow.IRequest(ctx).args |
3956 | - return "Request arguments are: ", str(args) |
3957 | - </pre> |
3958 | - |
3959 | - <h2>Generators in the DOM</h2> |
3960 | - |
3961 | - <p> |
3962 | - One common operation when building dynamic pages is iterating a list of |
3963 | - data and emitting some HTML for each item. Python generators are well |
3964 | - suited for expressing this sort of logic, and code which is written as a |
3965 | - python generator can perform tests (<code>if</code>) and loops of various |
3966 | - kinds (<code>while</code>, <code>for</code>) and emit a row of html |
3967 | - whenever it has enough data to do so. Nevow can handle generators in the |
3968 | - DOM just as gracefully as it can handle anything else: |
3969 | - </p> |
3970 | - |
3971 | - <pre class="python-interpreter"> |
3972 | ->>> from nevow import rend, loaders, tags |
3973 | ->>> def generate(ctx, items): |
3974 | -... for item in items: |
3975 | -... yield tags.div[ item ] |
3976 | -... |
3977 | ->>> class List(rend.Page): |
3978 | -... docFactory = loaders.stan(tags.html[ generate ]) |
3979 | -... |
3980 | ->>> List(['one', 'two', 'three']).renderSynchronously() |
3981 | -'<html><div>one</div><div>two</div><div>three</div></html>'</pre> |
3982 | - |
3983 | - <p> |
3984 | - As you can see, generating HTML inside of functions or generators can be |
3985 | - very convenient, and can lead to very rapid application |
3986 | - development. However, it is also what I would call a "template |
3987 | - abstraction violation", and we will learn how we can keep knowledge of |
3988 | - HTML out of our python code when we learn about patterns and slots. |
3989 | - </p> |
3990 | - |
3991 | - <h2>Methods in the DOM</h2> |
3992 | - |
3993 | - <p> |
3994 | - Up until now, we have been placing our template manipulation logic inside |
3995 | - of simple Python functions and generators. However, it is often |
3996 | - appropriate to use a method instead of a function. Nevow makes it just as |
3997 | - easy to use a method to render HTML: |
3998 | - </p> |
3999 | - |
4000 | - <pre class="python"> |
4001 | -class MethodRender(rend.Page): |
4002 | - def __init__(self, foo): |
4003 | - self.foo = foo |
4004 | - |
4005 | - def render_foo(self, ctx, data): |
4006 | - return self.foo |
4007 | - |
4008 | - docFactory = loaders.stan(tags.html[ render_foo ]) |
4009 | - </pre> |
4010 | - |
4011 | - <p> |
4012 | - Using render methods makes it possible to parameterize your Page class |
4013 | - with more parameters. With render methods, you can also use the Page |
4014 | - instance as a state machine to keep track of the state of the |
4015 | - render. While Nevow is designed to allow you to render the same Page |
4016 | - instance repeatedly, it can also be convenient to know that a Page |
4017 | - instance will only be used one time, and that the Page instance can be |
4018 | - used as a scratch pad to manage information about the render. |
4019 | - </p> |
4020 | - |
4021 | - <h2>Data specials</h2> |
4022 | - |
4023 | - <p> |
4024 | - Previously we saw how passing a parameter to the default Page constructor |
4025 | - makes it available as the "data" parameter to all of our render |
4026 | - methods. This "data" parameter can change as the page render proceeds, |
4027 | - and is a useful way to ensure that render functions are isolated and only |
4028 | - act upon the data which is available to them. Render functions which do |
4029 | - not pull information from sources other than the "data" parameter are |
4030 | - more easily reusable and can be composed into larger parts more easily. |
4031 | - </p> |
4032 | - |
4033 | - <p> |
4034 | - Deciding which data gets passed as the data parameter is as simple as |
4035 | - changing the "Data special" for a Tag. See the <a |
4036 | - href="glossary.xhtml">Glossary</a> under "Tag Specials" for more |
4037 | - information about specials. Assigning to the data special is as simple as |
4038 | - assigning to a tag attribute: |
4039 | - </p> |
4040 | - |
4041 | - <pre class="python-interpreter"> |
4042 | ->>> def hello(ctx, name): |
4043 | -... return "Hello, ", name |
4044 | -... |
4045 | ->>> class DataSpecial(rend.Page): |
4046 | -... docFactory = loaders.stan(tags.html[ |
4047 | -... tags.div(data="foo")[ hello ], |
4048 | -... tags.div(data="bar")[ hello ]]) |
4049 | -... |
4050 | ->>> DataSpecial().renderSynchronously() |
4051 | -'<html><div>Hello, foo</div><div>Hello, bar</div></html>'</pre> |
4052 | - |
4053 | - <p> |
4054 | - Data specials may be assigned any python value. Data specials are only in |
4055 | - scope during the rendering of the tag they are assigned to, so if the |
4056 | - "hello" renderer were placed in the DOM inside the html node directly, |
4057 | - "Hello, None" would be output. |
4058 | - </p> |
4059 | - |
4060 | - <p> |
4061 | - Before data is passed to a render function, Nevow first checks to see if |
4062 | - there is an <code class="API">IGettable</code> adapter for it. If there |
4063 | - is, it calls <code>IGettable.get()</code>, and passes the result of this |
4064 | - as the data parameter instead. Nevow includes an <code>IGettable</code> |
4065 | - adapter for python functions, which means you can set a Tag data special |
4066 | - to a function reference and Nevow will call it to obtain the data when |
4067 | - the Tag is rendered. The signature for data methods is similar to that of |
4068 | - render methods, (ctx, data). For example: |
4069 | - </p> |
4070 | - |
4071 | - <pre class="python"> |
4072 | -def getName(ctx, data): |
4073 | - return ctx.arg('name') |
4074 | - |
4075 | -def greet(ctx, name): |
4076 | - return "Greetings, ", name |
4077 | - |
4078 | -class GreetName(rend.Page): |
4079 | - docFactory = loaders.stan(tags.html[ |
4080 | - tags.form(action="")[ |
4081 | - tags.input(name="name"), |
4082 | - tags.input(type="submit")], |
4083 | - tags.div(data=getName)[ greet ]]) |
4084 | - </pre> |
4085 | - |
4086 | - <p> |
4087 | - Data specials exist mainly to allow you to construct and enforce a |
4088 | - Model-View-Controller style separation of the Model code from the |
4089 | - View. Here we see that the greet function is capable of rendering a |
4090 | - greeting view for a name model, and that the implementation of getName |
4091 | - may change without the view code changing. |
4092 | - </p> |
4093 | - |
4094 | - <h2>Render specials</h2> |
4095 | - |
4096 | - <p> |
4097 | - Previously, we have seen how render functions can be placed directly in |
4098 | - the DOM, and the return value replaces the render function in the |
4099 | - DOM. However, these free functions and methods are devoid of any |
4100 | - contextual information about the template they are living in. The |
4101 | - render special is a way to associate a render function or method with a |
4102 | - particular Tag instance, which the render function can then examine to |
4103 | - decide how to render: |
4104 | - </p> |
4105 | - |
4106 | - <pre class="python-interpreter"> |
4107 | ->>> def alignment(ctx, data): |
4108 | -... align = ctx.tag.attributes.get('align') |
4109 | -... if align == 'right': |
4110 | -... return ctx.tag["Aligned right"] |
4111 | -... elif align == 'center': |
4112 | -... return ctx.tag["Aligned center"] |
4113 | -... else: |
4114 | -... return ctx.tag["Aligned left"] |
4115 | -... |
4116 | ->>> class AlignmentPage(rend.Page): |
4117 | -... docFactory = loaders.stan(tags.html[ |
4118 | -... tags.p(render=alignment), |
4119 | -... tags.p(render=alignment, align="center"), |
4120 | -... tags.p(render=alignment, align="right")]) |
4121 | -... |
4122 | ->>> AlignmentPage().renderSynchronously() |
4123 | -'<html><p>Aligned left</p><p align="center">Aligned center</p><p align="right">Aligned right</p></html>'</pre> |
4124 | - |
4125 | - <p> |
4126 | - Note how the alignment renderer has access to the template node as |
4127 | - <code>ctx.tag</code>. It can examine and change this node, and the return value of |
4128 | - the render function replaces the original node in the DOM. Note that |
4129 | - here we are returning the template node after changing it. We will see |
4130 | - later how we can instead mutate the context and use slots so that the |
4131 | - knowledge the renderer requires about the structure of the template is |
4132 | - reduced even more. |
4133 | - </p> |
4134 | - |
4135 | - <h2>Pattern specials</h2> |
4136 | - |
4137 | - <p> |
4138 | - When writing render methods, it is easy to inline the construction of |
4139 | - Tag instances to generate HTML programatically. However, this creates a |
4140 | - template abstraction violation, where part of the HTML which will show |
4141 | - up in the final page output is hidden away inside of render methods |
4142 | - instead of inside the template. Pattern specials are designed to avoid |
4143 | - this problem. A node which has been tagged with a pattern special can |
4144 | - then be located and copied by a render method. The render method does |
4145 | - not need to know anything about the structure or location of the |
4146 | - pattern, only it's name. |
4147 | - </p> |
4148 | - |
4149 | - <p> |
4150 | - We can rewrite our previous generator example so that the generator |
4151 | - does not have to know what type of tag the template designer would like |
4152 | - repeated for each item in the list: |
4153 | - </p> |
4154 | - |
4155 | - <pre class="python-interpreter"> |
4156 | ->>> from nevow import rend, loaders, tags, inevow |
4157 | ->>> def generate(ctx, items): |
4158 | -... pat = inevow.IQ(ctx).patternGenerator('item') |
4159 | -... for item in items: |
4160 | -... ctx.tag[ pat(data=item) ] |
4161 | -... return ctx.tag |
4162 | -... |
4163 | ->>> def string(ctx, item): |
4164 | -... return ctx.tag[ str(item) ] |
4165 | -... |
4166 | ->>> class List(rend.Page): |
4167 | -... docFactory = loaders.stan(tags.html[ |
4168 | -... tags.ul(render=generate)[ |
4169 | -... tags.li(pattern="item", render=string)]]) |
4170 | -... |
4171 | ->>> List([1, 2, 3]).renderSynchronously() |
4172 | -'<html><ol><li>1</li><li>2</li><li>3</li></ol></html>'</pre> |
4173 | - |
4174 | - <p> |
4175 | - Note that we have to mutate the tag in place and repeatedly copy the |
4176 | - item pattern, applying the item as the data special to the resulting |
4177 | - Tag. It turns out that this is such a common operation that nevow comes |
4178 | - out of the box with these two render functions: |
4179 | - </p> |
4180 | - |
4181 | - <pre class="python-interpreter"> |
4182 | ->>> class List(rend.Page): |
4183 | -... docFactory = loaders.stan(tags.html[ |
4184 | -... tags.ul(render=rend.sequence)[ |
4185 | -... tags.li(pattern="item", render=rend.data)]]) |
4186 | -... |
4187 | ->>> List([1, 2, 3]).renderSynchronously() |
4188 | -'<html><ul><li>1</li><li>2</li><li>3</li></ul></html>'</pre> |
4189 | - |
4190 | - <h2>Slot specials</h2> |
4191 | - |
4192 | - <p> |
4193 | - The problem with render methods is that they are only capable of making |
4194 | - changes to their direct children. Because of the architecture of Nevow, |
4195 | - they should not attempt to change grandchildren or parent nodes. It is |
4196 | - possible to write one render method for every node you wish to change, |
4197 | - but there is a better way. A node with a slot special can be "filled" |
4198 | - with content by any renderer above the slot. Creating a slot special is |
4199 | - such a frequent task that there is a prototype in <code>nevow.tags</code> |
4200 | - which is usually used. |
4201 | - </p> |
4202 | - |
4203 | - <p> |
4204 | - Let us examine a renderer which fills a template with information about |
4205 | - a person: |
4206 | - </p> |
4207 | - |
4208 | - <pre class="python-interpreter"> |
4209 | ->>> from nevow import loaders, rend, tags |
4210 | -... |
4211 | ->>> person = ('Donovan', 'Preston', 'Male', 'California') |
4212 | -... |
4213 | ->>> def render_person(ctx, person): |
4214 | -... firstName, lastName, sex, location = person |
4215 | -... ctx.fillSlots('firstName', firstName) |
4216 | -... ctx.fillSlots('lastName', lastName) |
4217 | -... ctx.fillSlots('sex', sex) |
4218 | -... ctx.fillSlots('location', location) |
4219 | -... return ctx.tag |
4220 | -... |
4221 | ->>> class PersonPage(rend.Page): |
4222 | -... docFactory = loaders.stan(tags.html(render=render_person)[ |
4223 | -... tags.table[ |
4224 | -... tags.tr[ |
4225 | -... tags.td[tags.slot('firstName')], |
4226 | -... tags.td[tags.slot('lastName')], |
4227 | -... tags.td[tags.slot('sex')], |
4228 | -... tags.td[tags.slot('location')]]]]) |
4229 | -... |
4230 | ->>> PersonPage(person).renderSynchronously() |
4231 | -'<html><table><tr><td>Donovan</td><td>Preston</td><td>Male</td><td>California</td></tr></table></html>'</pre> |
4232 | - |
4233 | - <p> |
4234 | - Using patterns in combination with slots can lead to very powerful |
4235 | - template abstraction. Nevow also includes another standard renderer |
4236 | - called "mapping" which takes any data which responds to the "items()" |
4237 | - message and inserts the items into appropriate slots: |
4238 | - </p> |
4239 | - |
4240 | - <pre class="python-interpreter"> |
4241 | ->>> class DictPage(rend.Page): |
4242 | -... docFactory = loaders.stan(tags.html(render=rend.mapping)[ |
4243 | -... tags.span[ tags.slot('foo') ], tags.span[ tags.slot('bar') ]]) |
4244 | -... |
4245 | ->>> DictPage(dict(foo=1, bar=2)).renderSynchronously() |
4246 | -'<html><span>1</span><span>2</span></html>'</pre> |
4247 | - |
4248 | - <h2>Data directives</h2> |
4249 | - |
4250 | - <p> |
4251 | - So far, we have always placed data functions directly in the Data |
4252 | - special attribute of a Tag. Sometimes, it is preferable to look up a |
4253 | - data method from the Page class as the Page has being rendered. For |
4254 | - example, a base class may define a template and a subclass may provide |
4255 | - the implementation of the data method. We can accomplish this effect by |
4256 | - using a data directive as a Tag's data special: |
4257 | - </p> |
4258 | - |
4259 | - <pre class="python"> |
4260 | -class Base(rend.Page): |
4261 | - docFactory = loaders.stan(tags.html[ |
4262 | - tags.div(data=tags.directive('name'), render=rend.data)]) |
4263 | - |
4264 | -class Subclass(Base): |
4265 | - def data_name(self, ctx, data): |
4266 | - return "Your name" |
4267 | - </pre> |
4268 | - |
4269 | - <p> |
4270 | - The data directive is resolved by searching for the |
4271 | - <code>IContainer</code> implementation in the context. |
4272 | - <code>rend.Page</code> implements <code>IContainer.get</code> by |
4273 | - performing an attribute lookup on the Page with the prefix 'data_*'. You |
4274 | - can provide your own <code>IContainer</code> implementation if you wish, |
4275 | - and also you should know that <code>IContainer</code> implementations for |
4276 | - list and dict are included in the <code class="API">nevow.accessors</code> |
4277 | - module. |
4278 | - </p> |
4279 | - |
4280 | - <p> |
4281 | - A common gotcha is that the closest <code>IContainer</code> is used to |
4282 | - resolve data directives. This means that if a list is being used as the |
4283 | - data during the rendering process, data directives below this will be |
4284 | - resolved against the <code>IContainer</code> implementation in |
4285 | - <code>nevow.accessors.ListAccessor</code>. If you are expecting a data |
4286 | - directive to invoke a Page's data_* method but instead get a |
4287 | - <code>KeyError</code>, this is why. |
4288 | - </p> |
4289 | - |
4290 | - <h2>Render directives</h2> |
4291 | - |
4292 | - <p> |
4293 | - Render directives are almost exactly the same, except they are resolved |
4294 | - using the closest <code>IRendererFactory</code> implementation in the |
4295 | - context. Render directives can be used to allow subclasses to override |
4296 | - certain render methods, and also can be used to allow Fragments to |
4297 | - locate their own prefixed render methods. |
4298 | - </p> |
4299 | - |
4300 | - <h2>Flatteners</h2> |
4301 | - |
4302 | - <p> |
4303 | - TODO This section isn't done yet. |
4304 | - </p> |
4305 | - |
4306 | - <p> |
4307 | - Nevow's flatteners use a type/function registry to determine how to |
4308 | - render objects which Nevow encounters in the DOM during the rendering |
4309 | - process. "Explicit is better than implicit", so in most cases, |
4310 | - explicitly applying render methods to data will be better than |
4311 | - registering a flattener, but in some cases it can be useful: |
4312 | - </p> |
4313 | - |
4314 | - <pre class="python"> |
4315 | -class Person(object): |
4316 | - def __init__(self, firstName, lastName): |
4317 | - self.firstName = firstName |
4318 | - self.lastName = lastName |
4319 | - |
4320 | -def flattenPerson(person, ctx): |
4321 | - return flat.partialflatten(ctx, (person.firstName, " ", person.lastName)) |
4322 | - |
4323 | -from nevow import flat |
4324 | -flat.registerFlattener(flattenPerson, Person) |
4325 | - |
4326 | -def insertData(ctx, data): |
4327 | - return data |
4328 | - |
4329 | -class PersonPage(rend.Page): |
4330 | - docFactory = loaders.stan(tags.html[insertData]) |
4331 | - </pre> |
4332 | - </body> |
4333 | -</html> |
4334 | |
4335 | === removed file 'Nevow/doc/howto/stylesheet.css' |
4336 | --- Nevow/doc/howto/stylesheet.css 2008-09-20 01:06:47 +0000 |
4337 | +++ Nevow/doc/howto/stylesheet.css 1970-01-01 00:00:00 +0000 |
4338 | @@ -1,129 +0,0 @@ |
4339 | -body |
4340 | -{ |
4341 | - margin-left: 2em; |
4342 | - margin-right: 2em; |
4343 | - border: 0px; |
4344 | - padding: 0px; |
4345 | - font-family: sans-serif; |
4346 | -} |
4347 | - |
4348 | -pre |
4349 | -{ |
4350 | - padding: 1em; |
4351 | - font-family: Monospace, Neep Alt, Courier New, Courier; |
4352 | - font-size: 12pt; |
4353 | - border: thin black solid; |
4354 | -} |
4355 | - |
4356 | -.python |
4357 | -{ |
4358 | - background-color: #dddddd; |
4359 | -} |
4360 | - |
4361 | -.py-listing, .html-listing, .listing |
4362 | -{ |
4363 | - margin: 1ex; |
4364 | - border: thin solid black; |
4365 | - background-color: #eee; |
4366 | -} |
4367 | - |
4368 | -.py-listing pre, .html-listing pre, .listing pre |
4369 | -{ |
4370 | - margin: 0px; |
4371 | - border: none; |
4372 | - border-bottom: thin solid black; |
4373 | -} |
4374 | - |
4375 | -.py-listing .python |
4376 | -{ |
4377 | - margin-top: 0; |
4378 | - margin-bottom: 0; |
4379 | - border: none; |
4380 | - border-bottom: thin solid black; |
4381 | -} |
4382 | - |
4383 | -.py-src-comment |
4384 | -{ |
4385 | - color: #1111CC |
4386 | -} |
4387 | - |
4388 | -.py-src-keyword |
4389 | -{ |
4390 | - color: #3333CC; |
4391 | - font-weight: bold; |
4392 | -} |
4393 | - |
4394 | -.py-src-parameter |
4395 | -{ |
4396 | - color: #000066; |
4397 | - font-weight: bold; |
4398 | -} |
4399 | - |
4400 | -.py-src-identifier |
4401 | -{ |
4402 | - color: #CC0000 |
4403 | -} |
4404 | - |
4405 | -.py-src-string |
4406 | -{ |
4407 | - color: #115511 |
4408 | -} |
4409 | - |
4410 | -.py-src-endmarker |
4411 | -{ |
4412 | - display: block; /* IE hack; prevents following line from being sucked into the py-listing box. */ |
4413 | -} |
4414 | - |
4415 | -hr |
4416 | -{ |
4417 | - display: inline; |
4418 | -} |
4419 | - |
4420 | -ul |
4421 | -{ |
4422 | - padding: 0px; |
4423 | - margin: 0px; |
4424 | - margin-left: 1em; |
4425 | - padding-left: 1em; |
4426 | - border-left: 1em; |
4427 | -} |
4428 | - |
4429 | -li |
4430 | -{ |
4431 | - padding: 2px; |
4432 | -} |
4433 | - |
4434 | -dt |
4435 | -{ |
4436 | - font-weight: bold; |
4437 | - margin-left: 1ex; |
4438 | -} |
4439 | - |
4440 | -dd |
4441 | -{ |
4442 | - margin-bottom: 1em; |
4443 | -} |
4444 | - |
4445 | -div.note |
4446 | -{ |
4447 | - background-color: #FFFFCC; |
4448 | - margin-top: 1ex; |
4449 | - margin-left: 5%; |
4450 | - margin-right: 5%; |
4451 | - padding-top: 1ex; |
4452 | - padding-left: 5%; |
4453 | - padding-right: 5%; |
4454 | - border: thin black solid; |
4455 | -} |
4456 | - |
4457 | -.caption |
4458 | -{ |
4459 | - text-align: center; |
4460 | - padding-top: 0.5em; |
4461 | - padding-bottom: 0.5em; |
4462 | -} |
4463 | - |
4464 | -.filename |
4465 | -{ |
4466 | - font-style: italic; |
4467 | -} |
4468 | |
4469 | === removed file 'Nevow/doc/howto/template.tpl' |
4470 | --- Nevow/doc/howto/template.tpl 2008-08-26 13:45:59 +0000 |
4471 | +++ Nevow/doc/howto/template.tpl 1970-01-01 00:00:00 +0000 |
4472 | @@ -1,24 +0,0 @@ |
4473 | -<?xml version="1.0"?> |
4474 | -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" |
4475 | - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
4476 | - |
4477 | -<html xmlns="http://www.w3.org/1999/xhtml" lang="en"> |
4478 | - <head> |
4479 | - <title> |
4480 | - Nevow: |
4481 | - </title> |
4482 | - <link type="text/css" rel="stylesheet" href="stylesheet.css" /> |
4483 | - </head> |
4484 | - |
4485 | - <body bgcolor="white"> |
4486 | - <h1 class="title"></h1> |
4487 | - <div class="toc"></div> |
4488 | - <div class="body"> |
4489 | - |
4490 | - </div> |
4491 | - |
4492 | - <p><a href="index.html">Index</a></p> |
4493 | - <span class="version">Version: </span> |
4494 | - </body> |
4495 | -</html> |
4496 | - |
4497 | |
4498 | === removed file 'Nevow/doc/howto/traversal.xhtml' |
4499 | --- Nevow/doc/howto/traversal.xhtml 2008-09-26 16:30:04 +0000 |
4500 | +++ Nevow/doc/howto/traversal.xhtml 1970-01-01 00:00:00 +0000 |
4501 | @@ -1,448 +0,0 @@ |
4502 | -<?xml version="1.0"?> |
4503 | -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" |
4504 | - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> |
4505 | - |
4506 | -<html xmlns="http://www.w3.org/1999/xhtml"> |
4507 | - <head> |
4508 | - <title> |
4509 | - Object Traversal |
4510 | - </title> |
4511 | - </head> |
4512 | - <body> |
4513 | - <h1>Object Traversal</h1> |
4514 | - |
4515 | - <p> |
4516 | - <strong>Object traversal</strong> is the process Nevow uses to determine |
4517 | - what object to use to render HTML for a particular URL. When an HTTP |
4518 | - request comes in to the web server, the object publisher splits the URL |
4519 | - into segments, and repeatedly calls methods which consume path segments |
4520 | - and return objects which represent that path, until all segments have |
4521 | - been consumed. At the core, the Nevow traversal API is very |
4522 | - simple. However, it provides some higher level functionality layered on |
4523 | - top of this to satisfy common use cases. |
4524 | - </p> |
4525 | - |
4526 | - <h2>Object Traversal Basics</h2> |
4527 | - |
4528 | - <p> |
4529 | - The <strong>root resource</strong> is the top-level object in the URL |
4530 | - space; it conceptually represents the URI <code>/</code>. The Nevow |
4531 | - <strong>object traversal</strong> and <strong>object publishing</strong> |
4532 | - machinery uses only two methods to locate an object suitable for |
4533 | - publishing and to generate the HTML from it; these methods are described |
4534 | - in the interface <code class="API">nevow.inevow.IResource</code>: |
4535 | - </p> |
4536 | - |
4537 | - <pre class="python"> |
4538 | -class IResource(Interface): |
4539 | - def locateChild(self, ctx, segments): |
4540 | - """Locate another object which can be adapted to IResource |
4541 | - Return a tuple of resource, path segments |
4542 | - """ |
4543 | - |
4544 | - def renderHTTP(self, ctx): |
4545 | - """Render a request |
4546 | - """ |
4547 | - </pre> |
4548 | - |
4549 | - <p> |
4550 | - <code class="API" base="nevow.inevow.IResource">renderHTTP</code> can be |
4551 | - as simple as a method which simply returns a string of HTML. Let's |
4552 | - examine what happens when object traversal occurs over a very simple root |
4553 | - resource: |
4554 | - </p> |
4555 | - |
4556 | - <pre class="python"> |
4557 | -from zope.interface import implements |
4558 | - |
4559 | -class SimpleRoot(object): |
4560 | - implements(inevow.IResource) |
4561 | - |
4562 | - def locateChild(self, ctx, segments): |
4563 | - return self, () |
4564 | - |
4565 | - def renderHTTP(self, ctx): |
4566 | - return "Hello, world!" |
4567 | - </pre> |
4568 | - |
4569 | - <p> |
4570 | - This resource, when passed as the root resource to <code class="API" |
4571 | - base="nevow">appserver.NevowSite</code> or <code class="API" |
4572 | - base="nevow">wsgi.createWSGIApplication</code>, will immediately return |
4573 | - itself, consuming all path segments. This means that for every URI a user |
4574 | - visits on a web server which is serving this root resource, the text |
4575 | - <code>"Hello, world!"</code> will be rendered. Let's examine the value of |
4576 | - <code>segments</code> for various values of URI: |
4577 | - </p> |
4578 | - |
4579 | - <ul> |
4580 | - <li><code>/</code> - <code>('',)</code></li> |
4581 | - <li><code>/foo/bar</code> - <code>('foo', 'bar')</code></li> |
4582 | - <li> |
4583 | - <code>/foo/bar/baz.html</code> - |
4584 | - <code>('foo', 'bar', 'baz.html')</code> |
4585 | - </li> |
4586 | - <li> |
4587 | - <code>/foo/bar/directory/</code> - |
4588 | - <code>('foo', 'bar', 'directory', '')</code> |
4589 | - </li> |
4590 | - </ul> |
4591 | - |
4592 | - <p> |
4593 | - So we see that Nevow does nothing more than split the URI on the string |
4594 | - <code>/</code> and pass these path segments to our application for |
4595 | - consumption. Armed with these two methods alone, we already have enough |
4596 | - information to write applications which service any form of URL |
4597 | - imaginable in any way we wish. However, there are some common URL |
4598 | - handling patterns which Nevow provides higher level support for. |
4599 | - </p> |
4600 | - |
4601 | - <h2><code>locateChild</code> In Depth</h2> |
4602 | - |
4603 | - <p> |
4604 | - One common URL handling pattern involves parents which only know about |
4605 | - their direct children. For example, a ``Directory`` object may only know |
4606 | - about the contents of a single directory, but if it contains other |
4607 | - directories, it does not know about the contents of them. Let's examine a |
4608 | - simple ``Directory`` object which can provide directory listings and |
4609 | - serves up objects for child directories and files: |
4610 | - </p> |
4611 | - |
4612 | - <pre class="python"> |
4613 | -from zope.interface import implements |
4614 | - |
4615 | -class Directory(object): |
4616 | - implements(inevow.IResource) |
4617 | - |
4618 | - def __init__(self, directory): |
4619 | - self.directory = directory |
4620 | - |
4621 | - def renderHTTP(self, ctx): |
4622 | - html = ['<ul>'] |
4623 | - for child in os.listdir(self.directory): |
4624 | - fullpath = os.path.join(self.directory, child) |
4625 | - if os.path.isdir(fullpath): |
4626 | - child += '/' |
4627 | - html.extend(['<li><a href="', child, '">', child, '</a></li>']) |
4628 | - html.append('</ul>') |
4629 | - return ''.join(html) |
4630 | - |
4631 | - def locateChild(self, ctx, segments): |
4632 | - name = segments[0] |
4633 | - fullpath = os.path.join(self.directory, name) |
4634 | - if not os.path.exists(fullpath): |
4635 | - return None, () # 404 |
4636 | - |
4637 | - if os.path.isdir(fullpath): |
4638 | - return Directory(fullpath), segments[1:] |
4639 | - if os.path.isfile(fullpath): |
4640 | - return static.File(fullpath), segments[1:] |
4641 | - </pre> |
4642 | - |
4643 | - <p> |
4644 | - Because this implementation of <code>locateChild</code> only consumed one |
4645 | - segment and returned the rest of them (<code>segments[1:]</code>), the |
4646 | - object traversal process will continue by calling |
4647 | - <code>locateChild</code> on the returned resource and passing the |
4648 | - partially-consumed segments. In this way, a directory structure of any |
4649 | - depth can be traversed, and directory listings or file contents can be |
4650 | - rendered for any existing directories and files. |
4651 | - </p> |
4652 | - |
4653 | - <p> |
4654 | - So, let us examine what happens when the URI |
4655 | - <code>"/foo/bar/baz.html"</code> is traversed, where <code>"foo"</code> |
4656 | - and <code>"bar"</code> are directories, and <code>"baz.html"</code> is a |
4657 | - file. |
4658 | - </p> |
4659 | - |
4660 | - <ol> |
4661 | - <li> |
4662 | - <code> |
4663 | - Directory('/').locateChild(ctx, ('foo', 'bar', 'baz.html')) |
4664 | - </code> |
4665 | - returns |
4666 | - <code>Directory('/foo'), ('bar', 'baz.html')</code> |
4667 | - </li> |
4668 | - <li> |
4669 | - <code> |
4670 | - Directory('/foo').locateChild(ctx, ('bar', 'baz.html')) |
4671 | - </code> |
4672 | - returns |
4673 | - <code>Directory('/foo/bar'), ('baz.html, )</code> |
4674 | - </li> |
4675 | - <li> |
4676 | - <code> |
4677 | - Directory('/foo/bar').locateChild(ctx, ('baz.html')) |
4678 | - </code> |
4679 | - returns |
4680 | - <code>File('/foo/bar/baz.html'), ()</code> |
4681 | - </li> |
4682 | - <li> |
4683 | - No more segments to be consumed; |
4684 | - <code>File('/foo/bar/baz.html').renderHTTP(ctx)</code> is called, and |
4685 | - the result is sent to the browser. |
4686 | - </li> |
4687 | - </ol> |
4688 | - |
4689 | - |
4690 | - <h2><code>childFactory</code> Method</h2> |
4691 | - |
4692 | - <p> |
4693 | - Consuming one URI segment at a time by checking to see if a requested |
4694 | - resource exists and returning a new object is a very common |
4695 | - pattern. Nevow's default implementation of <code class="API" |
4696 | - base="nevow.inevow">IResource</code>, <code |
4697 | - class="API">nevow.rend.Page</code>, contains an implementation of |
4698 | - <code>locateChild</code> which provides more convenient hooks for |
4699 | - implementing object traversal. One of these hooks is |
4700 | - <code>childFactory</code>. Let us imagine for the sake of example that we |
4701 | - wished to render a tree of dictionaries. Our data structure might look |
4702 | - something like this: |
4703 | - </p> |
4704 | - |
4705 | - <pre class="python"> |
4706 | -tree = dict( |
4707 | - one=dict( |
4708 | - foo=None, |
4709 | - bar=None), |
4710 | - two=dict( |
4711 | - baz=dict( |
4712 | - quux=None))) |
4713 | - </pre> |
4714 | - |
4715 | - <p> |
4716 | - Given this data structure, the valid URIs would be: |
4717 | - </p> |
4718 | - |
4719 | - <ul> |
4720 | - <li>/</li> |
4721 | - <li>/one</li> |
4722 | - <li>/one/foo</li> |
4723 | - <li>/one/bar</li> |
4724 | - <li>/two</li> |
4725 | - <li>/two/baz</li> |
4726 | - <li>/two/baz/quux</li> |
4727 | - </ul> |
4728 | - |
4729 | - <p> |
4730 | - Let us construct a <code class="API" base="nevow">rend.Page</code> |
4731 | - subclass which uses the default <code>locateChild</code> implementation |
4732 | - and overrides the <code>childFactory</code> hook instead: |
4733 | - </p> |
4734 | - |
4735 | - <pre class="python"> |
4736 | -class DictTree(rend.Page): |
4737 | - def __init__(self, dataDict): |
4738 | - self.dataDict = dataDict |
4739 | - |
4740 | - def renderHTTP(self, ctx): |
4741 | - if self.dataDict is None: |
4742 | - return "Leaf" |
4743 | - html = ['<ul>'] |
4744 | - for key in self.dataDict.keys(): |
4745 | - html.extend(['<li><a href="', key, '">', key, '</a></li>']) |
4746 | - html.append('</ul>') |
4747 | - return ''.join(html) |
4748 | - |
4749 | - def childFactory(self, ctx, name): |
4750 | - if name not in self.dataDict: |
4751 | - return rend.NotFound # 404 |
4752 | - return DictTree(self.dataDict[name]) |
4753 | - </pre> |
4754 | - |
4755 | - <p> |
4756 | - As you can see, the <code>childFactory</code> implementation is |
4757 | - considerably shorter than the equivalent <code>locateChild</code> |
4758 | - implementation would have been. |
4759 | - </p> |
4760 | - |
4761 | - <h2><code>child_*</code> methods and attributes</h2> |
4762 | - |
4763 | - <p> |
4764 | - Often we may wish to have some hardcoded URLs which are not dynamically |
4765 | - generated based on some data structure. For example, we might have an |
4766 | - application which uses an external CSS stylesheet, an external JavaScript |
4767 | - file, and a folder full of images. The <code class="API" |
4768 | - base="nevow">rend.Page.locateChild</code> implementation provides a |
4769 | - convenient way for us to express these relationships by using |
4770 | - child-prefixed methods: |
4771 | - </p> |
4772 | - |
4773 | - <pre class="python"> |
4774 | -class Linker(rend.Page): |
4775 | - def renderHTTP(self, ctx): |
4776 | - return """<html> |
4777 | -<head> |
4778 | - <link href="css" rel="stylesheet" /> |
4779 | - <script type="text/javascript" src="scripts" /> |
4780 | - <body> |
4781 | - <img src="images/logo.png" /> |
4782 | - </body> |
4783 | -</html>""" |
4784 | - |
4785 | - def child_css(self, ctx): |
4786 | - return static.File('styles.css') |
4787 | - |
4788 | - def child_scripts(self, ctx): |
4789 | - return static.File('scripts.js') |
4790 | - |
4791 | - def child_images(self, ctx): |
4792 | - return static.File('images/') |
4793 | - </pre> |
4794 | - |
4795 | - <p> |
4796 | - One thing you may have noticed is that all of the examples so far have |
4797 | - returned new object instances whenever they were implementing a traversal |
4798 | - API. However, there is no reason these instances cannot be shared. One |
4799 | - could for example return a global resource instance, an instance which |
4800 | - was previously inserted in a dict, or lazily create and cache dynamic |
4801 | - resource instances on the fly. The <code>rend.Page.locateChild</code> |
4802 | - implementation also provides a convenient way to express that one global |
4803 | - resource instance should always be used for a particular URL, the |
4804 | - child-prefixed attribute: |
4805 | - </p> |
4806 | - |
4807 | - <pre class="python"> |
4808 | -class FasterLinker(Linker): |
4809 | - child_css = static.File('styles.css') |
4810 | - child_scripts = static.File('scripts.js') |
4811 | - child_images = static.File('images/') |
4812 | - </pre> |
4813 | - |
4814 | - <h2>Dots in child names</h2> |
4815 | - |
4816 | - <p> |
4817 | - When a URL contains dots, which is quite common in normal URLs, it is |
4818 | - simple enough to handle these URL segments in <code>locateChild</code> or |
4819 | - <code>childFactory</code> -- one of the passed segments will simply be a |
4820 | - string containing a dot. However, it is not immediately obvious how one |
4821 | - would express a URL segment with a dot in it when using child-prefixed |
4822 | - methods. The solution is really quite simple: |
4823 | - </p> |
4824 | - |
4825 | - <pre class="python"> |
4826 | -class DotChildren(rend.Page): |
4827 | - def renderHTTP(self, ctx): |
4828 | - return """ |
4829 | - <html> |
4830 | - <head> |
4831 | - <script type="text/javascript" src="scripts.js" /> |
4832 | - </head> |
4833 | - </html>""" |
4834 | - |
4835 | -setattr(DotChildren, 'child_scripts.js', static.File('scripts.js')) |
4836 | - </pre> |
4837 | - |
4838 | - <p> |
4839 | - The same technique could be used to install a child method with a dot in |
4840 | - the name. |
4841 | - </p> |
4842 | - |
4843 | - |
4844 | - <h2>children dictionary</h2> |
4845 | - |
4846 | - <p> |
4847 | - The final hook supported by the default implementation of |
4848 | - <code>locateChild</code> is the <code>rend.Page.children</code> |
4849 | - dictionary: |
4850 | - </p> |
4851 | - |
4852 | - <pre class="python"> |
4853 | -class Main(rend.Page): |
4854 | - children = { |
4855 | - 'people': People(), |
4856 | - 'jobs': Jobs(), |
4857 | - 'events': Events()} |
4858 | - |
4859 | - def renderHTTP(self, ctx): |
4860 | - return """ |
4861 | - <html> |
4862 | - <head> |
4863 | - <title>Our Site</title> |
4864 | - </head> |
4865 | - <body> |
4866 | - <p>bla bla bla</p> |
4867 | - </body> |
4868 | - </html>""" |
4869 | - </pre> |
4870 | - |
4871 | - <p> |
4872 | - Hooks are checked in the following order: |
4873 | - </p> |
4874 | - |
4875 | - <ol> |
4876 | - <li><code>self.children</code></li> |
4877 | - <li><code>self.child_*</code></li> |
4878 | - <li><code>self.childFactory</code></li> |
4879 | - </ol> |
4880 | - |
4881 | - <h2>The default trailing slash handler</h2> |
4882 | - |
4883 | - <p> |
4884 | - When a URI which is being handled ends in a slash, such as when the |
4885 | - <code>/</code> URI is being rendered or when a directory-like URI is |
4886 | - being rendered, the string <code>''</code> appears in the path segments |
4887 | - which will be traversed. Again, handling this case is trivial inside |
4888 | - either <code>locateChild</code> or <code>childFactory</code>, but it may |
4889 | - not be immediately obvious what child-prefixed method or attribute will |
4890 | - be looked up. The method or attribute name which will be used is simply |
4891 | - <code>child</code> with a single trailing underscore. |
4892 | - </p> |
4893 | - |
4894 | - <p> |
4895 | - The <code>rend.Page</code> class provides an implementation of this |
4896 | - method which can work in two different ways. If the attribute |
4897 | - <code>addSlash</code> is <code>True</code>, the default trailing slash |
4898 | - handler will return <code>self</code>. In the case when |
4899 | - <code>addSlash</code> is <code>True</code>, the default |
4900 | - <code>rend.Page.renderHTTP</code> implementation will simply perform a |
4901 | - redirect which adds the missing slash to the URL. |
4902 | - </p> |
4903 | - |
4904 | - <p> |
4905 | - The default trailing slash handler also returns self if |
4906 | - <code>addSlash</code> is <code>False</code>, but emits a warning as it |
4907 | - does so. This warning may become an exception at some point in the |
4908 | - future. |
4909 | - </p> |
4910 | - |
4911 | - <h2><code>ICurrentSegments</code> and <code>IRemainingSegments</code></h2> |
4912 | - |
4913 | - <p> |
4914 | - During the object traversal process, it may be useful to discover which |
4915 | - segments have already been handled and which segments are remaining to be |
4916 | - handled. This information may be obtained from the <code>context</code> |
4917 | - object which is passed to all the traversal APIs. The interfaces <code |
4918 | - class="API">nevow.inevow.ICurrentSegments</code> and <code |
4919 | - class="API">nevow.inevow.IRemainingSegments</code> are used to retrieve |
4920 | - this information. To retrieve a tuple of segments which have previously |
4921 | - been consumed during object traversal, use this syntax: |
4922 | - </p> |
4923 | - |
4924 | - <pre class="python"> |
4925 | -segs = ICurrentSegments(ctx) |
4926 | - </pre> |
4927 | - |
4928 | - <p> |
4929 | - The same is true of <code>IRemainingSegments</code>. |
4930 | - <code>IRemainingSegments</code> is the same value which is passed as |
4931 | - <code>segments</code> to <code>locateChild</code>, but may also be useful |
4932 | - in the implementations of <code>childFactory</code> or a child-prefixed |
4933 | - method, where this information would not otherwise be available. |
4934 | - </p> |
4935 | - |
4936 | - <h2>Conclusion</h2> |
4937 | - |
4938 | - <p> |
4939 | - Nevow makes it easy to handle complex URL hierarchies. The most basic |
4940 | - object traversal interface, <code |
4941 | - class="API">nevow.inevow.IResource.locateChild</code>, provides powerful |
4942 | - and flexible control over the entire object traversal process. Nevow's |
4943 | - canonical <code>IResource</code> implementation, <code>rend.Page</code>, |
4944 | - also includes the convenience hooks <code>childFactory</code> along with |
4945 | - child-prefixed method and attribute semantics to simplify common use |
4946 | - cases. |
4947 | - </p> |
4948 | - </body> |
4949 | -</html> |
4950 | |
4951 | === removed file 'Nevow/doc/howto/xmltemplates.xhtml' |
4952 | --- Nevow/doc/howto/xmltemplates.xhtml 2008-08-26 13:45:59 +0000 |
4953 | +++ Nevow/doc/howto/xmltemplates.xhtml 1970-01-01 00:00:00 +0000 |
4954 | @@ -1,407 +0,0 @@ |
4955 | -<?xml version="1.0"?> |
4956 | -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" |
4957 | - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> |
4958 | - |
4959 | -<html xmlns="http://www.w3.org/1999/xhtml"> |
4960 | - <head> |
4961 | - <title> |
4962 | - XML Templates |
4963 | - </title> |
4964 | - </head> |
4965 | - <body> |
4966 | - <h1>Nevow XML Templates</h1> |
4967 | - |
4968 | - <p> |
4969 | - Stan syntax is cool, but eventually you are going to want to integrate |
4970 | - your Python code with a template designed by an HTML monkey. Nevow |
4971 | - accomplishes this by providing an xmlfile loader which uses the built-in |
4972 | - Python SAX libraries to generate a tree of stan behind the scenes. The |
4973 | - general rule is anything that is possible in stan should be possible in a |
4974 | - pure XML template; of course, the XML syntax is generally going to be |
4975 | - much more verbose. |
4976 | - </p> |
4977 | - |
4978 | - <h2>loaders.xmlfile</h2> |
4979 | - |
4980 | - <p> |
4981 | - Wherever you have seen a loaders.stan being created in any of the example |
4982 | - code, a <code class="API" base="nevow">loaders.xmlfile</code> can be |
4983 | - substituted instead. At the most basic, <code>xmlfile</code> merely |
4984 | - requires the name of an xml template: |
4985 | - </p> |
4986 | - |
4987 | - <pre class="python"> |
4988 | -class HelloXML(rend.Page): |
4989 | - docFactory = loaders.xmlfile('hello.xml') |
4990 | - </pre> |
4991 | - |
4992 | - <p> |
4993 | - Placing the following xml in the <code>hello.xml</code> file will cause |
4994 | - <code>HelloXML</code> to display a static page when it is rendered: |
4995 | - </p> |
4996 | - |
4997 | - <pre><html>Hello, world!</html></pre> |
4998 | - |
4999 | - <p> |
5000 | - The following additional keyword arguments may be given to |
The diff has been truncated for viewing.