Merge lp:~divmod-dev/divmod.org/811792-remove-formless into lp:divmod.org

Proposed by Tristan Seligmann
Status: Rejected
Rejected by: Tristan Seligmann
Proposed branch: lp:~divmod-dev/divmod.org/811792-remove-formless
Merge into: lp:divmod.org
Diff against target: 8055 lines
To merge this branch: bzr merge lp:~divmod-dev/divmod.org/811792-remove-formless
Reviewer Review Type Date Requested Status
Divmod-dev Pending
Review via email: mp+69186@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Jonathan Jacobs (jjacobs) wrote :

Not everything being deleted here uses formless. I don't know how many of these Athena examples are still useful (most look either broken or at least very out of date) perhaps exarkun can weigh in on whether deleting Nevow/examples is okay.

Revision history for this message
Jean-Paul Calderone (exarkun) wrote :

> Not everything being deleted here uses formless. I don't know how many of
> these Athena examples are still useful (most look either broken or at least
> very out of date) perhaps exarkun can weigh in on whether deleting
> Nevow/examples is okay.

Wow, all of Nevow/examples? That sounds crazy, I don't see why that would be necessary as part of the removal of formless.

2676. By Tristan Seligmann

Put the other athenademo examples back.

Revision history for this message
Tristan Seligmann (mithrandi) wrote :

I was only trying to delete the examples in Nevow/examples that use formless; looks like I accidentally deleted a bit more than I needed to in the case of examples/athenademo/*.

Revision history for this message
Zooko Wilcox-O'Hearn (zooko) wrote :

I just browsed through as much of the diff as launchpad would show. It turns out I don't understand what formless is well enough to know which of the examples ought to be retained.

Unmerged revisions

2676. By Tristan Seligmann

Put the other athenademo examples back.

2675. By Tristan Seligmann

Remove formless.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== removed directory 'Nevow/examples/advanced_manualform'
2=== removed file 'Nevow/examples/advanced_manualform/__init__.py'
3=== removed file 'Nevow/examples/advanced_manualform/advanced_manualform.py'
4--- Nevow/examples/advanced_manualform/advanced_manualform.py 2006-03-08 14:28:41 +0000
5+++ Nevow/examples/advanced_manualform/advanced_manualform.py 1970-01-01 00:00:00 +0000
6@@ -1,106 +0,0 @@
7-from time import time as now
8-
9-import twisted.python.components as tpc
10-
11-from nevow import rend, inevow, url, util, loaders, tags as t
12-from nevow.rend import _CARRYOVER
13-from formless import iformless
14-
15-#
16-# This example is meant to be of some inspiration to those people
17-# who need to have some inspiration to handle forms without using
18-# formless. It _WILL_ raise an exception when you submit a form
19-# without filling all values. This example should NOT be used as-is
20-# but should be modified and enhanced to fit one's need.
21-#
22-# To sum up: it's just a starting point.
23-#
24-
25-SUBMIT="_submit"
26-BUTTON = 'post_btn'
27-
28-class WebException(Exception): pass
29-
30-class ManualFormMixin(rend.Page):
31- def locateChild(self, ctx, segments):
32- # Handle the form post
33- if segments[0].startswith(SUBMIT):
34- # Get a method name from the action in the form plus
35- # the firt word in the button name (or simply the form action if
36- # no button name is specified
37- kwargs = {}
38- args = inevow.IRequest(ctx).args
39- bindingName = ''
40- for key in args:
41- if key != BUTTON:
42- if args[key] != ['']:
43- kwargs[key] = (args[key][0], args[key])[len(args[key])>1]
44- else:
45- bindingName = args[key][0]
46- name_prefix = segments[0].split('!!')[1]
47- if bindingName == '': name = name_prefix
48- else: name = name_prefix + '_' + bindingName.split()[0].lower()
49- method = getattr(self, 'form_'+name, None)
50- if method is not None:
51- return self.onManualPost(ctx, method, bindingName, kwargs)
52- else:
53- raise WebException("You should define a form_action_button method")
54- return super(ManualFormMixin, self).locateChild(ctx, segments)
55-
56- def onManualPost(self, ctx, method, bindingName, kwargs):
57- # This is copied from rend.Page.onWebFormPost
58- def redirectAfterPost(aspects):
59- redirectAfterPost = request.getComponent(iformless.IRedirectAfterPost, None)
60- if redirectAfterPost is None:
61- ref = request.getHeader('referer') or ''
62- else:
63- ## Use the redirectAfterPost url
64- ref = str(redirectAfterPost)
65- from nevow import url
66- refpath = url.URL.fromString(ref)
67- magicCookie = str(now())
68- refpath = refpath.replace('_nevow_carryover_', magicCookie)
69- _CARRYOVER[magicCookie] = C = tpc.Componentized()
70- for k, v in aspects.iteritems():
71- C.setComponent(k, v)
72- request.redirect(str(refpath))
73- from nevow import static
74- return static.Data('You posted a form to %s' % bindingName, 'text/plain'), ()
75- request = inevow.IRequest(ctx)
76- return util.maybeDeferred(method, **kwargs
77- ).addCallback(self.onPostSuccess, request, ctx, bindingName,redirectAfterPost
78- ).addErrback(self.onPostFailure, request, ctx, bindingName,redirectAfterPost)
79-
80-
81-class Page(ManualFormMixin, rend.Page):
82-
83- addSlash = True
84- docFactory = loaders.stan(
85- t.html[
86- t.head[
87- t.title['Advanced Manualform']
88- ],
89- t.body[
90- t.p['Use the form to find out how to easily and manually handle them'],
91- t.form(action=url.here.child('_submit!!post'),
92- enctype="multipart/form-data",
93- method='post'
94- )[
95- t.input(type='text', name='what'),
96- # the name attribute must be present and must be
97- # post_btn for all the buttons in the form
98- t.input(type='submit', value='btn1', name=BUTTON),
99- t.input(type='submit', value='btn2', name=BUTTON)
100- ]
101- ]
102- ]
103- )
104-
105- def form_post_btn1(self, what=None):
106- # 'what' is a keyword argument, and must be the same name that you
107- # give to the widget.
108- print "btn1:", what
109-
110- def form_post_btn2(self, what=None):
111- # see above for 'what'.
112- print "btn2:", what
113
114=== removed file 'Nevow/examples/athenademo/typeahead.html'
115--- Nevow/examples/athenademo/typeahead.html 2006-10-06 18:48:29 +0000
116+++ Nevow/examples/athenademo/typeahead.html 1970-01-01 00:00:00 +0000
117@@ -1,103 +0,0 @@
118-<!DOCTYPE html
119-PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
120-"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
121-<html xmlns='http://www.w3.org/1999/xhtml'
122- xmlns:n='http://nevow.com/ns/nevow/0.1'>
123- <!-- vi:ft=html
124- -->
125- <head>
126- <meta http-equiv='Content-Type' content='text/html; charset=UTF-8' />
127- <n:invisible n:render="liveglue" />
128- <title>TypeAhead Demo</title>
129- <script type='text/javascript' language='javascript'>
130-// <![CDATA[
131-// add events in a cross-browser way
132-function xbAddEvent(obj, evType, fn, useCapture){
133- if (obj.addEventListener){
134- obj.addEventListener(evType, fn, useCapture);
135- return true;
136- } else if (obj.attachEvent){
137- var r = obj.attachEvent("on"+evType, fn);
138- return r;
139- } else {
140- alert("Handler could not be attached");
141- }
142-}
143-
144-function selectRange(ele, start, end)
145-{
146- var orig = ele;
147- ele = $(ele);
148- if (ele == null)
149- {
150- alert("selectRange() can't find an element with id: " + orig + ".");
151- return;
152- }
153-
154- if (ele.setSelectionRange)
155- {
156- ele.setSelectionRange(start, end);
157- }
158- else if (ele.createTextRange)
159- {
160- var range = ele.createTextRange();
161- range.moveStart("character", start);
162- range.moveEnd("character", end - ele.value.length);
163- range.select();
164- }
165-
166- ele.focus();
167-};
168-
169-//
170-function replaceDescription(result, node)
171-{
172- var animal = result[0]; var descr = result[1];
173-
174- var widget = Nevow.Athena.Widget.get(node);
175- var description = widget.nodeByAttribute('class', 'description');
176- description.innerHTML = descr;
177-
178- // fill in the text field and select the portion that was guessed
179- if (animal != null)
180- {
181- var typehere = node;
182- var current = typehere.value;
183- typehere.value = animal;
184- selectRange(typehere, current.length, animal.length);
185- }
186-}
187-
188-//
189-function loadDescription(ev)
190-{
191- // filter helpful keys like backspace
192- if (ev.keyCode < 32) return;
193- if (ev.keyCode >= 33 && ev.keyCode <= 46) return;
194- if (ev.keyCode >= 112 && ev.keyCode <= 123) return;
195-
196- var typehere = ev.target;
197- var typed = typehere.value;
198- var d = Nevow.Athena.Widget.get(typehere).callRemote('loadDescription', typed);
199- d.addCallback(replaceDescription, typehere);
200-}
201-
202-Divmod.Base.addToCallStack(window, 'onload', function() {
203- typeheres = MochiKit.DOM.getElementsByTagAndClassName('input', 'typehere');
204- for (n=0; n<typeheres.length; n++) {
205- xbAddEvent(typeheres[n], 'keyup', loadDescription, 1);
206- }
207-});
208-
209-// ]]>
210- </script>
211- </head>
212- <body>
213- <h2>Start typing an animal to see the description.</h2>
214- <n:invisible n:render="typehereField" />
215- <h2>You can also type in this one. It does the same thing, independently
216- of the other one.</h2>
217- <n:invisible n:render="typehereField" />
218- </body>
219-</html>
220-
221
222=== removed file 'Nevow/examples/athenademo/typeahead.py'
223--- Nevow/examples/athenademo/typeahead.py 2006-10-06 18:48:29 +0000
224+++ Nevow/examples/athenademo/typeahead.py 1970-01-01 00:00:00 +0000
225@@ -1,82 +0,0 @@
226-# vi:ft=python
227-from nevow import tags as T, rend, loaders, athena, url
228-from formless import annotate, webform
229-from twisted.python import util
230-
231-animals = {u'elf' : u'Pointy ears. Bad attitude regarding trees.',
232- u'chipmunk': u'Cute. Fuzzy. Sings horribly.',
233- u'chupacabra': u'It sucks goats.',
234- u'ninja': u'Stealthy and invisible, and technically an animal.',
235- }
236-
237-
238-class TypeAheadPage(athena.LivePage):
239- _tmpl = util.sibpath(__file__, "typeahead.html")
240- docFactory = loaders.xmlfile(_tmpl)
241- def render_typehereField(self, ctx, data):
242- frag = TypeAheadFieldFragment()
243- frag.page = self
244- return frag
245-
246-class TypeAheadFieldFragment(athena.LiveFragment):
247- docFactory = loaders.stan(
248- T.span(render=T.directive('liveFragment'))[ '\n',
249- T.input(type="text", _class="typehere"), '\n',
250- T.h3(_class="description"),
251- ])
252-
253- def loadDescription(self, typed):
254- if typed == u'':
255- return None, u'--'
256- matches = []
257- for key in animals:
258- if key.startswith(typed):
259- matches.append(key)
260- if len(matches) == 1:
261- return matches[0], animals[matches[0]]
262- elif len(matches) > 1:
263- return None, u"(Multiple found)"
264- else:
265- return None, u'--'
266- athena.expose(loadDescription)
267-
268-class DataEntry(rend.Page):
269- """Add Animal"""
270- addSlash = 1
271-
272- docFactory = loaders.stan(
273- T.html[T.body[T.h1[
274- "First, a Setup Form."],
275- T.h2["Enter some animals as data. Click 'Done' to test looking up these animals."],
276- T.h3["The neat stuff happens when you hit 'Done'."],
277- webform.renderForms(),
278- T.ol(data=T.directive("animals"), render=rend.sequence)[
279- T.li(pattern="item", render=T.directive("string")),
280- ],
281- T.h1[T.a(href=url.here.child('typeahead'))["Done"]],
282- ]
283- ]
284- )
285- def bind_animals(self, ctx, ):
286- """Add Animal"""
287- return annotate.MethodBinding(
288- 'animals',
289- annotate.Method(arguments=
290- [annotate.Argument('animal', annotate.String()),
291- annotate.Argument('description', annotate.Text())]),
292- action="Add Animal",
293- )
294-
295- def animals(self, animal, description):
296- """Add Animal"""
297- if not (animal and description):
298- return
299- animals[animal.decode('utf-8')] = description.decode('utf-8')
300- return url.here
301-
302- def data_animals(self, ctx, data):
303- return animals.keys()
304-
305- def child_typeahead(self, ctx):
306- return TypeAheadPage(None, None)
307-
308
309=== removed directory 'Nevow/examples/blogengine'
310=== removed file 'Nevow/examples/blogengine/atom.xml'
311--- Nevow/examples/blogengine/atom.xml 2005-10-14 17:36:24 +0000
312+++ Nevow/examples/blogengine/atom.xml 1970-01-01 00:00:00 +0000
313@@ -1,22 +0,0 @@
314-<?xml version="1.0"?>
315-<feed version="0.3" xmlns="http://purl.org/atom/ns#" xml:lang="en" xmlns:n="http://nevow.com/ns/nevow/0.1">
316- <title mode="escaped">Subbacultcha</title>
317- <link rel="alternate" type="text/html" href="http://localhost:8080" />
318- <tagline mode="escaped">Subbacultcha atom</tagline>
319- <modified n:data="getFirstPost" n:render="modified">Page modified</modified>
320- <id>tag:localhost,2004:/</id>
321- <n:invisible n:data="get_posts" n:render="sequence">
322- <entry n:pattern="item" n:render="post">
323- <title mode="escaped"><n:slot name="title">Entry Title</n:slot></title>
324- <link rel="alternate" type="text/html" href="#">
325- <n:attr name="href"> <n:slot name="link" /> </n:attr>
326- </link>
327- <id>tag:localhost,2004:/<n:slot name="id">id</n:slot></id>
328- <issued><n:slot name="created">Date created</n:slot></issued>
329- <modified><n:slot name="modified">Date modified</n:slot></modified>
330- <author>
331- <name><n:slot name="author">Author</n:slot></name>
332- </author>
333- <content type="text/plain" mode="escaped"><n:slot name="content">Content</n:slot></content>
334- </entry>
335 </n:invisible>
336-</feed>
337\ No newline at end of file
338
339=== removed file 'Nevow/examples/blogengine/axiomstore.py'
340--- Nevow/examples/blogengine/axiomstore.py 2006-04-14 17:23:46 +0000
341+++ Nevow/examples/blogengine/axiomstore.py 1970-01-01 00:00:00 +0000
342@@ -1,76 +0,0 @@
343-from iblogengine import IBlog
344-from zope.interface import implements
345-from axiom import item, store, attributes, sequence
346-from epsilon.extime import Time
347-
348-class Post(item.Item):
349- typeName = "BlogenginePost"
350- schemaVersion = 1
351-
352- id = attributes.integer(indexed=True, allowNone=False)
353- created = attributes.timestamp(indexed=True)
354- modified = attributes.timestamp(indexed=True)
355- title = attributes.text(indexed=True, allowNone=False)
356- author = attributes.text(indexed=True, allowNone=False)
357- category = attributes.text(indexed=True)
358- content = attributes.text(indexed=True)
359-
360- def __init__(self, **kw):
361- now = Time()
362- kw.update({'created':now,
363- 'modified':now})
364- super(Post, self).__init__(**kw)
365-
366- def setModified(self):
367- self.modified = Time()
368-
369-class Blog(item.Item, item.InstallableMixin):
370- implements(IBlog)
371-
372- typeName = "BlogengineBlog"
373- schemaVersion = 1
374-
375- posts = attributes.reference()
376- next_id = attributes.integer(default=0)
377-
378- def __init__(self, **kw):
379- super(Blog, self).__init__(**kw)
380- self.posts = sequence.List(store=self.store)
381- post = Post(store=self.store,
382- id=self.getNextId(),
383- author=u'mike',
384- title=u'FIRST POST!!!!',
385- category=u'Test',
386- content=u'I guess it worked.')
387- self.addNewPost(post)
388-
389- def installOn(self, other):
390- super(Blog, self).installOn(other)
391- other.powerUp(self, IBlog)
392-
393- def addNewPost(self, post):
394- # Why even let posts manage their own ids? Oh well.
395- assert post.id == self.next_id,\
396- "Bad post ID; is %r, should be %r" % (post.id, self.next_id)
397- self.posts.append(post)
398- self.next_id += 1
399-
400- def getPosts(self, how_many = None):
401- """Return the latest 'how_many' posts, in reverse database order.
402-
403- XXX Really, it should be based on modtime. Which is broken.
404- """
405- if how_many is None or how_many > self.next_id:
406- how_many = self.next_id
407- return (self.getOne(self.next_id-id-1) for id in range(how_many))
408-
409- def getOne(self, id):
410- return self.posts[id]
411-
412- def getNextId(self):
413- return self.next_id
414-
415-def initialize(storename):
416- s = store.Store(storename)
417- s.findOrCreate(Blog).installOn(s)
418- return s
419
420=== removed file 'Nevow/examples/blogengine/blogengine.tac'
421--- Nevow/examples/blogengine/blogengine.tac 2006-01-21 22:53:11 +0000
422+++ Nevow/examples/blogengine/blogengine.tac 1970-01-01 00:00:00 +0000
423@@ -1,12 +0,0 @@
424-from twisted.application import service, strports
425-from nevow import appserver
426-
427-import frontend, axiomstore as store, iblogengine
428-from smtpserver import BlogSMTPFactory
429-
430-application = service.Application('blogengine')
431-db = store.initialize('db.axiom')
432-site = appserver.NevowSite(resource = frontend.UI())
433-site.remember(db, iblogengine.IStore)
434-strports.service("8080", site).setServiceParent(application)
435-strports.service("2500", BlogSMTPFactory(db)).setServiceParent(application)
436
437=== removed file 'Nevow/examples/blogengine/email_client.py'
438--- Nevow/examples/blogengine/email_client.py 2005-10-14 17:36:24 +0000
439+++ Nevow/examples/blogengine/email_client.py 1970-01-01 00:00:00 +0000
440@@ -1,16 +0,0 @@
441-import sys, smtplib
442-
443-fromaddr = raw_input("From: ")
444-toaddrs = raw_input("To: ").split(',')
445-print "Enter message, end with ^D:"
446-msg = ''
447-while 1:
448- line = sys.stdin.readline()
449- if not line:
450- break
451- msg = msg + line
452-
453-# The actual mail send
454-server = smtplib.SMTP('localhost', 2500)
455-server.sendmail(fromaddr, toaddrs, msg)
456-server.quit()
457
458=== removed file 'Nevow/examples/blogengine/frontend.py'
459--- Nevow/examples/blogengine/frontend.py 2006-04-14 17:23:46 +0000
460+++ Nevow/examples/blogengine/frontend.py 1970-01-01 00:00:00 +0000
461@@ -1,241 +0,0 @@
462-from time import time as now
463-from zope.interface import implements, Interface
464-
465-from twisted.web import xmlrpc
466-from twisted.python.components import registerAdapter
467-
468-from nevow import rend, loaders, url, static
469-from nevow import tags as t, inevow
470-from formless import annotate, iformless, webform
471-
472-from axiomstore import Post
473-from iblogengine import IStore, IBlog
474-
475-def pptime(tt):
476- return tt.asHumanly()+" UTC"
477-def atompptime(tt):
478- return tt.asISO8601TimeAndDate()
479-class ITimer(Interface):
480- pass
481-
482-#####################################
483-categories = ['Programming', 'Test', 'Sport', 'People', 'Python',
484- 'Databases', 'bench', 'woo', 'Friends']
485-
486-class IInsert(annotate.TypedInterface):
487- def insert(
488- ctx = annotate.Context(),
489- title = annotate.String(strip=True, required=True, \
490- requiredFailMessage="Title must be provided", tabindex='1'),
491- author = annotate.String(strip=True, default="Anonymous", tabindex='2'),
492- id = annotate.String(hidden=True),
493- category = annotate.Choice(categories, tabindex='3'),
494- content = annotate.Text(required=True, \
495- requiredFailMessage="Posts with no content are not allowed", tabindex='4'),
496- ):
497- pass
498- insert = annotate.autocallable(insert)
499-
500-#####################################
501-class BaseUI(rend.Page):
502- addSlash = True
503- def renderHTTP(self, ctx):
504- return IStore(ctx).transact(rend.Page.renderHTTP, self, ctx)
505-
506- def locateChild(self, ctx, segments):
507- return IStore(ctx).transact(rend.Page.locateChild, self, ctx, segments)
508-
509-#############################
510-class UI(BaseUI):
511-
512- docFactory = loaders.xmlfile ('ui.html')
513- child_styles = static.File('styles')
514- child_images = static.File('images')
515- child_webform_css = webform.defaultCSS
516-
517- def render_starttimer(self, ctx, data):
518- ctx.remember(now(), ITimer)
519- return ctx.tag
520-
521- def render_stoptimer(self, ctx, data):
522- start = ITimer(ctx)
523- return ctx.tag['%s' % (now()-start)]
524-
525- def render_needForms(self, ctx, data):
526- action = ctx.arg('action', 'view')
527- if action == 'edit':
528- form = inevow.IQ(ctx).onePattern('frm')
529- return ctx.tag[form]
530- return ctx.tag.clear()
531-
532- def data_getEntries(self, ctx, data):
533- num = ctx.arg('num', '60')
534- return IBlog(IStore(ctx)).getPosts(int(num))
535-
536- def render_entries(self, ctx, data):
537- ctx.tag.fillSlots('modification', pptime(data.modified))
538- ctx.tag.fillSlots('category', data.category)
539- ctx.tag.fillSlots('author', data.author)
540- ctx.tag.fillSlots('title', data.title)
541- ctx.tag.fillSlots('content', data.content)
542- ctx.tag.fillSlots('permaLink', url.root.child('%s' % (data.id)))
543- return ctx.tag
544-
545- def render_insert(self, ctx, data):
546- return ctx.tag
547-
548- def render_editer(self, ctx, data):
549- ctx.tag.fillSlots('editPost', url.root.child('%s' % (data.id)
550- ).add('action','edit'))
551- return ctx.tag
552-
553- def render_insert(self, ctx, data):
554- ctx.tag.fillSlots('insert', url.root.child('insertEntry'))
555- return ctx.tag
556-
557- def child_insertEntry(self, ctx):
558- return NewEntry()
559-
560- def childFactory(self, ctx, segment):
561- id = segment.isdigit() and segment or '-1'
562- if int(id) >= 0:
563- return IBlog(IStore(ctx)).getOne(int(id))
564- elif segment == 'rpc2':
565- return BlogRPC(IStore(ctx))
566- elif segment == 'atom.xml':
567- return Atom()
568-
569- def child_thx(self, ctx):
570- return Thx()
571-
572-##################################
573-class NewEntry(BaseUI):
574- implements(IInsert)
575-
576- docFactory = loaders.stan(
577- t.html[
578- t.head[
579- t.title['Insertion form'],
580- t.link(rel='stylesheet', type='text/css', href=url.root.child('webform_css')),
581- ],
582- t.body[
583- t.h1['Insertion'],
584- t.invisible(render=t.directive("forms"))
585- ]
586- ])
587- def render_forms(self, ctx, data):
588- d = iformless.IFormDefaults(ctx).getAllDefaults('insert')
589- d['author'] = 'Anonymous'
590- d['id'] = IBlog(IStore(ctx)).getNextId()
591- return webform.renderForms()
592-
593- def insert(self, ctx, id, title, author, category, content):
594- newPost = Post(store=IStore(ctx),
595- id=int(id),
596- author=unicode(author),
597- title=unicode(title),
598- category=unicode(category),
599- content=unicode(content))
600- IBlog(IStore(ctx)).addNewPost(newPost)
601- inevow.IRequest(ctx).setComponent(iformless.IRedirectAfterPost, '/thx')
602-
603-#####################################
604-class Thx(rend.Page):
605- docFactory = loaders.stan(
606- t.html[
607- t.body[
608- t.h1['Succeeded'],
609- t.a(href=url.root)["Back to main"]
610- ]
611- ])
612-
613-####################################
614-class Entry(UI):
615- implements(IInsert)
616- def data_getEntries(self, ctx, data):
617- return [data]
618-
619- def render_forms(self, ctx, data):
620- d = iformless.IFormDefaults(ctx).getAllDefaults('insert')
621- d['author'] = self.original.author
622- d['category'] = self.original.category
623- d['title'] = self.original.title
624- d['content'] = self.original.content
625- d['id'] = self.original.id
626- return webform.renderForms()
627-
628- def insert(self, ctx, id, title, author, category, content):
629- self.original.author = unicode(author)
630- self.original.title = unicode(title)
631- self.original.category = unicode(category)
632- self.original.content = unicode(content)
633- inevow.IRequest(ctx).setComponent(iformless.IRedirectAfterPost, '/thx')
634-
635-#####################################
636-class Atom(BaseUI):
637- docFactory = loaders.xmlfile('atom.xml')
638-
639- def beforeRender(self, ctx):
640- inevow.IRequest(ctx).setHeader("Content-Type", "application/application+xml; charset=UTF-8")
641-
642- def data_getFirstPost(self, ctx, data):
643- for post in IBlog(IStore(ctx)).getPosts(1):
644- return post
645-
646- def render_modified(self, ctx, data):
647- return ctx.tag.clear()[atompptime(data.modified)]
648-
649- def data_get_posts(self, ctx, data):
650- return IBlog(IStore(ctx)).getPosts(15)
651-
652- def render_post(self, ctx, data):
653- #id = data.poolToUID[IBlog(IStore(ctx)).postsPool]
654- # mkp: ...I don't know what that means or what it's for.
655- ctx.tag.fillSlots('title', data.title)
656- ctx.tag.fillSlots('link', url.root.child(data.id))
657- ctx.tag.fillSlots('id', data.id)
658- ctx.tag.fillSlots('created', atompptime(data.created))
659- ctx.tag.fillSlots('modified', atompptime(data.modified))
660- ctx.tag.fillSlots('author', data.author)
661- ctx.tag.fillSlots('content', data.content)
662- return ctx.tag
663-
664-#####################################
665-from axiom.item import transacted
666-class BlogRPC(xmlrpc.XMLRPC):
667- """Publishes stuff"""
668-
669- def __init__(self, store):
670- xmlrpc.XMLRPC.__init__(self)
671- self.store = store
672-
673- def xmlrpc_publish(self, author, title, category, content):
674- newid = IBlog(self.store).getNextId()
675- newPost = Post(store=self.store,
676- id=newid,
677- author=unicode(author),
678- title=unicode(title),
679- category=unicode(category),
680- content=unicode(content))
681- IBlog(self.store).addNewPost(newPost)
682- return 'Successfully added post number %s' % newid
683- xmlrpc_publish = transacted(xmlrpc_publish)
684-
685- def xmlrpc_edit(self, id, author, title, category, content):
686- post = IBlog(self.store).getOne(id)
687- post.author = author
688- post.title = title
689- post.category = category
690- post.content = content
691- post.setModified()
692- return 'Successfully modified post number %s' % id
693- xmlrpc_edit = transacted(xmlrpc_edit)
694-
695- def xmlrpc_entries(self, count):
696- return [(entry.id, entry.author, entry.category, entry.title, entry.content) \
697- for entry in IBlog(self.store).getPosts(count)]
698-
699- xmlrpc_entries = transacted(xmlrpc_entries)
700-
701-registerAdapter(Entry, Post, inevow.IResource)
702-
703
704=== removed file 'Nevow/examples/blogengine/iblogengine.py'
705--- Nevow/examples/blogengine/iblogengine.py 2006-03-17 15:00:39 +0000
706+++ Nevow/examples/blogengine/iblogengine.py 1970-01-01 00:00:00 +0000
707@@ -1,17 +0,0 @@
708-from zope.interface import Interface
709-
710-class IStore(Interface):
711- """ Interface used to remember the store in the site object """
712-
713-class IBlog(Interface):
714- """ Represents the Blog Powerup in the Store """
715- def addNewPost(post):
716- """ Add the user provided post instance to the blog """
717- def getPosts(how_many = None):
718- """ Get the last X posts, if how_many is not specified, gets all of them """
719-
720- def getOne(id):
721- """ Get the post with the corresponding id from the store """
722-
723- def getNextId():
724- """ Get the next free id in the store """
725
726=== removed directory 'Nevow/examples/blogengine/images'
727=== removed file 'Nevow/examples/blogengine/images/bg-header2.jpg'
728Binary files Nevow/examples/blogengine/images/bg-header2.jpg 2005-10-14 17:36:24 +0000 and Nevow/examples/blogengine/images/bg-header2.jpg 1970-01-01 00:00:00 +0000 differ
729=== removed file 'Nevow/examples/blogengine/images/blank.gif'
730Binary files Nevow/examples/blogengine/images/blank.gif 2005-10-14 17:36:24 +0000 and Nevow/examples/blogengine/images/blank.gif 1970-01-01 00:00:00 +0000 differ
731=== removed file 'Nevow/examples/blogengine/images/geek-bullet.gif'
732Binary files Nevow/examples/blogengine/images/geek-bullet.gif 2005-10-14 17:36:24 +0000 and Nevow/examples/blogengine/images/geek-bullet.gif 1970-01-01 00:00:00 +0000 differ
733=== removed file 'Nevow/examples/blogengine/images/here-bullet.gif'
734Binary files Nevow/examples/blogengine/images/here-bullet.gif 2005-10-14 17:36:24 +0000 and Nevow/examples/blogengine/images/here-bullet.gif 1970-01-01 00:00:00 +0000 differ
735=== removed file 'Nevow/examples/blogengine/images/home-bullet.gif'
736Binary files Nevow/examples/blogengine/images/home-bullet.gif 2005-10-14 17:36:24 +0000 and Nevow/examples/blogengine/images/home-bullet.gif 1970-01-01 00:00:00 +0000 differ
737=== removed file 'Nevow/examples/blogengine/images/top.gif'
738Binary files Nevow/examples/blogengine/images/top.gif 2005-10-14 17:36:24 +0000 and Nevow/examples/blogengine/images/top.gif 1970-01-01 00:00:00 +0000 differ
739=== removed file 'Nevow/examples/blogengine/smtpserver.py'
740--- Nevow/examples/blogengine/smtpserver.py 2006-01-21 22:53:11 +0000
741+++ Nevow/examples/blogengine/smtpserver.py 1970-01-01 00:00:00 +0000
742@@ -1,148 +0,0 @@
743-
744-# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
745-# See LICENSE for details.
746-
747-"""
748-A toy email server.
749-"""
750-from zope.interface import implements
751-
752-from twisted.internet import defer
753-from twisted.mail import smtp
754-
755-from axiom.item import transacted
756-
757-from axiomstore import Post
758-from iblogengine import IBlog
759-
760-
761-# You need to set this to your real SMTP_HOST
762-SMTP_HOST = 'localhost'
763-FROM = 'user@localhost'
764-
765-__doc__ = """
766-This is the mail message format to post something via mail, no special
767-order is required, but all those fields must be present:
768-======
769-[Id: ID]
770-Author: AUTHOR_NAME
771-Category: CATEGORY_NAME
772-Title: TITLE
773-Content: CONTENT
774-"""
775-
776-class BlogMessageDelivery:
777- implements(smtp.IMessageDelivery)
778- def __init__(self, store):
779- self.store = store
780-
781- def receivedHeader(self, helo, origin, recipients):
782- return recipients
783-
784- def validateFrom(self, helo, origin):
785- # All addresses are accepted
786- return origin
787-
788- def validateTo(self, user):
789- # Only messages directed to the "console" user are accepted.
790- if user.dest.local == "blog":
791- return lambda: BlogMessage(self.store)
792- raise smtp.SMTPBadRcpt(user)
793-
794-class BlogMessage:
795- implements(smtp.IMessage)
796-
797- def __init__(self, store):
798- self.lines = []
799- self.store = store
800-
801- def lineReceived(self, line):
802- self.lines.append(line)
803-
804- def eomReceived(self):
805- post = {}
806- isContent = False
807- ctnt_buff = []
808- recipients = self.lines[0]
809- addrs = []
810-
811- for recipient in recipients:
812- if '@' not in recipient.orig.addrstr:
813- # Avoid answering to bounches
814- if not recipient.orig.addrstr == '<>':
815- addrs.append(recipient.orig.addrstr[:-1]+'@'+recipient.orig.domain+'>')
816- else:
817- # Avoid answering to bounches
818- if not recipient.orig.addrstr == '<#@[]>':
819- addrs.append(recipient.orig.addrstr)
820-
821- for line in self.lines[1:]:
822- if not isContent:
823- try:
824- field, value = line.split(':', 1)
825- except ValueError:
826- continue
827- if field.lower() != 'content':
828- post[field.lower()] = value.strip()
829- else:
830- isContent = True
831- ctnt_buff.append(value.strip())
832- else:
833- ctnt_buff.append(line.strip())
834- post['content'] = '\n'.join(ctnt_buff)
835-
836- for header in 'content author category title'.split():
837- if not post.has_key(header):
838- self.lines = []
839- return defer.fail(None)
840- if post.has_key('id'):
841- oldpost = IBlog(self.store).getOne(int(post['id']))
842- oldpost.author = unicode(post['author'])
843- oldpost.title = unicode(post['title'])
844- oldpost.category = unicode(post['category'])
845- oldpost.content = unicode(post['content'])
846- oldpost.setModified()
847- action = 'modified'
848- id = post['id']
849- else:
850- newid = IBlog(self.store).getNextId()
851- newPost = Post(store=self.store,
852- id=newid,
853- author=unicode(post['author']),
854- title=unicode(post['title']),
855- category=unicode(post['category']),
856- content=unicode(post['content']))
857- IBlog(self.store).addNewPost(newPost)
858- action = 'added'
859- id = newid
860- self.lines = []
861- msg = """From: <%s>
862-Subject: Successfull Post
863-
864-Post number %s successfully %s
865-""" % (FROM, id, action)
866- return self.sendNotify(addrs, msg)
867- eomReceived = transacted(eomReceived)
868-
869- def toLog(self, what):
870- print what
871-
872- def sendNotify(self, to_addr, msg):
873- d = smtp.sendmail(SMTP_HOST, FROM, to_addr, msg)
874- d.addCallback(self.toLog)
875- d.addErrback(self.toLog)
876- return d
877-
878- def connectionLost(self):
879- # There was an error, throw away the stored lines
880- self.lines = None
881-
882-class BlogSMTPFactory(smtp.SMTPFactory):
883- def __init__(self, store, *a, **kw):
884- smtp.SMTPFactory.__init__(self, *a, **kw)
885- self.delivery = BlogMessageDelivery(store)
886-
887- def buildProtocol(self, addr):
888- p = smtp.SMTPFactory.buildProtocol(self, addr)
889- p.delivery = self.delivery
890- return p
891
892=== removed directory 'Nevow/examples/blogengine/styles'
893=== removed file 'Nevow/examples/blogengine/styles/form.css'
894--- Nevow/examples/blogengine/styles/form.css 2005-10-14 17:36:24 +0000
895+++ Nevow/examples/blogengine/styles/form.css 1970-01-01 00:00:00 +0000
896@@ -1,78 +0,0 @@
897-form {
898- margin: 0;
899-}
900-
901-/*
902-form div {
903- margin-top: 10px;
904-}
905-*/
906-
907-form .field {
908- margin-top: 10px;
909-}
910-
911-fieldset {
912- margin: 0;
913- margin-top: 10px;
914-
915-/*border: 1px solid red;*/
916- border-style: none;
917- padding: 0;
918-}
919-
920-
921-label {
922- display: block;
923- margin-bottom: 2px;
924-}
925-
926-label span {
927- font-size: 85%;
928- color: #666;
929-}
930-
931-input, textarea {
932- /* f a t font to ease input */
933- font: bold 12px/100% "Lucida Console", Curier, monospace;
934- color: #444;
935-
936- padding: 4px 2px;
937- border: 1px solid #ccc;
938-
939- margin: 0;
940-}
941-
942-input:focus, textarea:focus {
943- border-color: #6cc;
944-}
945-
946-
947-input.btn {
948- margin: 0;
949- margin-right: 2px; /* space between the next button */
950-
951- padding: 2px 4px;
952-
953- color: #333;
954- background: #6cc;
955-
956- /* raised 3d look */
957- border-top: 2px solid #ccc;
958- border-left: 2px solid #ccc;
959- border-bottom: 2px solid #444;
960- border-right: 2px solid #444;
961-
962- font-family: Verdana, Helvetica, sans-serif;
963- line-height: 150%;
964-
965- font-size: xx-small; /* fake value for IE4/5.x */
966- voice-family: "\"}\"";
967- voice-family: inherit;
968- font-size: x-small; /* real inteded value for text size */
969-}
970-
971-blah {
972- /* fake rule for IE */
973-}
974-
975
976=== removed file 'Nevow/examples/blogengine/styles/site.css'
977--- Nevow/examples/blogengine/styles/site.css 2005-10-14 17:36:24 +0000
978+++ Nevow/examples/blogengine/styles/site.css 1970-01-01 00:00:00 +0000
979@@ -1,482 +0,0 @@
980-@import url("typo.css");
981-@import url("form.css");
982-
983-/*
984--------------------------------------------------
985-Theme by Andrea Peltrin (http://www.deelan.com)
986--------------------------------------------------
987-*/
988-
989-
990-/* basic elements */
991-/*---------------------------------------------------*/
992-
993-body, html {
994- margin: 0;
995- padding: 0;
996-}
997-
998-
999-body {
1000- color: #222;
1001-
1002- margin: 0;
1003-/* background: #903 url("images/background.gif"); */
1004- background: #fafafa;
1005-}
1006-
1007-body, p, li, td, th, dd, dt, h1, h2, h3, h4, h5, h6 /* help browser to not forget */
1008-{
1009- font-family: verdana, geneva, arial, sans-serif;
1010-/* line-height: 200%;*/
1011-
1012- font-size: x-small; /* IE5 */
1013- voice-family: "\"}\"";
1014- voice-family: inherit;
1015- font-size: small;
1016-}
1017-
1018-html>body {
1019- font-size: small;
1020-}
1021-
1022-
1023-a img {
1024- border-style: none;
1025-}
1026-
1027-/* main contents */
1028-
1029-#main {
1030- /*border: 1px solid red; */ /* debug */
1031- /*border-top: none;*/
1032-
1033-
1034-
1035- margin: 0 auto;
1036- padding: 0;
1037-
1038- position: absolute;
1039-
1040- top: 30px;
1041- left: 50%;
1042- margin-left: -380px;
1043-
1044- width: 760px;
1045-}
1046-
1047-/* header */
1048-
1049-#header {
1050- background: #069 url("/images/bg-header2.jpg") top right no-repeat;
1051-
1052- height: 235px;
1053- border: 1px solid #ccc;
1054-}
1055-
1056-
1057-#header h1 {
1058- margin: 0;
1059- margin-top: 140px;
1060- /*margin-right: 280px;*/
1061-
1062- padding: 0;
1063- padding-left:30px;
1064-
1065-
1066- font: bold italic 52px/100% georgia, times, serif;
1067- color: #fff;
1068-}
1069-
1070-#header p {
1071- margin: 0;
1072- /*margin-left: 280px;*/ /* == #header h1 */
1073-
1074- padding: 0;
1075- padding-left:30px;
1076-
1077-
1078- text-transform: lowercase;
1079- font: bold 18px/100% verdana, arial, sans-serif;
1080-
1081- color: #fff;
1082-}
1083-
1084-
1085-/*---------------------------------------------------*/
1086-
1087-#content{
1088- padding: 35px;
1089- margin: 0;
1090-
1091- /*border: 1px solid red; */ /* debug */
1092- margin-right: 245px;
1093-
1094-}
1095-
1096-#content p {
1097- /* border: 1px solid red; */ /* debug */
1098-/* text-align: justify;*/
1099- line-height: 160%;
1100-
1101- margin: 1em 0;
1102- padding: 0;
1103-}
1104-
1105-#content ul, #content ol, #content dl, #content blockquote {
1106- line-height: 160%;
1107-}
1108-
1109-
1110-#content dd {
1111- margin: 0;
1112- margin-bottom: 10px;
1113-}
1114-
1115-
1116-/* funky titles */
1117-#content h2 {
1118-
1119-/* font: bold italic 24px/100% georgia, times, serif;*/
1120- font: bold 18px/100% verdana, arial, sans-serif;
1121-
1122- color: #069;
1123-
1124- margin: 0;
1125- margin-bottom: 4px; /* space up for datetime */
1126-
1127- text-transform: lowercase;
1128-/* font-variant: small-caps;*/
1129-
1130-}
1131-
1132-#content p.dtm {
1133-
1134- margin: 0;
1135- margin-bottom: 1em;
1136-
1137- font-size: 80%;
1138-
1139- text-transform: uppercase;
1140-}
1141-
1142-
1143-div.entry {
1144-
1145-}
1146-
1147-
1148-#content hr {
1149- visibility: hidden;
1150-
1151
1152-
1153
1154- padding: 0;
1155
1156- margin: 2.5em auto;
1157
1158-
1159
1160-
1161
1162-}
1163-
1164-
1165-
1166-/* ...and finally we place the list of links */
1167-
1168-#sidebar{
1169- float: right;
1170-
1171-/* border: 1px solid #069;*/
1172-
1173- margin: 0;
1174- padding: 35px;
1175-
1176- width: 250px;
1177- voice-family: "\"}\"";
1178- voice-family: inherit;
1179- width: 180px;
1180-}
1181-
1182-#main>#sidebar {
1183- width: 180px;
1184-}
1185-
1186-
1187-#sidebar ul {
1188- list-style: none;
1189-
1190- margin: 0;
1191- margin-bottom: 25px;
1192-
1193- padding: 0;
1194-}
1195-
1196-
1197-#sidebar ul li {
1198- line-height: 150%;
1199-
1200- margin: 0;
1201- padding: 5px 0;
1202-}
1203-
1204-
1205-#sidebar ul#nav li {
1206- line-height: 160%; /* restore global value */
1207-
1208- border-style: none;
1209- background: none;
1210-
1211- margin-bottom: 10px;
1212- padding: 5px 0 5px 22px; /* space for arrow gfx */
1213-
1214- border-top: 1px solid #ccc;
1215- border-bottom: 1px solid #ccc;
1216-
1217- text-transform: lowercase;
1218-}
1219-
1220-
1221-/* funky titles */
1222-#sidebar h3 {
1223- color: #069;
1224-
1225- margin: 0;
1226- margin-bottom: 15px;
1227-
1228- padding: 0;
1229-
1230-
1231-}
1232-
1233-
1234-/* styles for in-line images/photos */
1235-/*---------------------------------------------------*/
1236-#content .image img {
1237- display: block;
1238- border: 1px solid #444;
1239-}
1240-
1241-#content .image {
1242- margin: 1em auto; /* == #content p*/
1243-
1244- width: 360px;
1245- position: relative;
1246-}
1247-
1248-#content .image span {
1249- position: absolute;
1250-
1251- background: #069;
1252- color: #fff;
1253-
1254- padding: 4px 4px;
1255-
1256- bottom: 10px;
1257- left: 10px;
1258-
1259- z-index: 1;
1260-
1261- /* verdana looks better than arial if font is small */
1262- font-family: verdana, arial, helvetica, sans-serif;
1263-
1264- /* @@ fix IE5 here */
1265- font-size: x-small;
1266-}
1267-
1268-/* hyperlink */
1269-/*---------------------------------------------------*/
1270-
1271-a:link, a:visited, a:hover, a:active {
1272- color: #099;
1273-
1274- text-decoration: none;
1275- border-bottom: 1px solid #099;
1276-}
1277-
1278-a:visited {
1279- color: #444;
1280- border-bottom-color: #444;
1281-}
1282-
1283-a:hover {
1284- color: #903;
1285- /*border-bottom: 1px solid #903;*/
1286- border-bottom: none;
1287-}
1288-
1289-
1290-#footer {
1291- margin: 0;
1292- margin-top: 20px;
1293- padding: 15px 0;
1294-
1295-/* background: #903;*/
1296-
1297- clear: both; /* float reset */
1298- text-align: center;
1299-
1300-
1301- border-top: 1px solid #ccc;
1302-
1303- font-size: 85%;
1304-}
1305-
1306-
1307-
1308-/* utilities */
1309-/*---------------------------------------------------*/
1310-
1311-.cut {clear: both; height: 1px;}
1312-.hidden {display: none;}
1313-
1314-/*---------------------------------------------------*/
1315-
1316-ul#breadcrumb {
1317- list-style: none;
1318-
1319- /* reset both on Mozilla and IE */
1320- padding: 0;
1321-
1322- margin: 0;
1323- margin-bottom: 35px;
1324-}
1325-
1326-ul#breadcrumb li {
1327- display: inline;
1328- margin-right: 5px;
1329-
1330- /*text-transform: lowercase;*/
1331-}
1332-
1333-ul#breadcrumb li:last-child {
1334- font-weight: bold;
1335-}
1336-
1337-/*
1338-#searchBtn {
1339- margin-left: 5px;
1340-}
1341-
1342-
1343-*/
1344-/* -------------------------------------------------- */
1345-
1346-.photo {
1347-
1348- float: left;
1349-
1350- margin: 5px 0;
1351- margin-right: 10px;
1352-
1353- padding: 0;
1354-}
1355-
1356-.photo a:link, .photo a:visited {
1357- border: 1px solid #0099CC;
1358-
1359- display: block;
1360-}
1361-
1362-.photo a:link:hover, .photo a:visited:hover {
1363- border: 1px solid #903;
1364-}
1365-
1366-.photo img {
1367- display: block;
1368-
1369- margin:0;
1370-
1371- padding: 5px;
1372- background: #fff;
1373-}
1374-
1375-
1376-
1377-.transport {
1378-
1379-
1380- width: auto;
1381-
1382- /*border: 2px solid #069;*/
1383- text-align: center;
1384-
1385- padding: 5px 0;
1386-}
1387-
1388-
1389-
1390-#alert {
1391- background: #069;
1392- color: white;
1393-
1394- font-weight: bold;
1395-
1396- margin-bottom: 20px;
1397-}
1398-
1399-
1400-
1401-#alert ul {
1402- list-style: none;
1403-
1404- padding: 0;
1405- margin: 0;
1406-}
1407-
1408-
1409-#alert ul li {
1410- margin: 5px 10px;
1411-}
1412-
1413-
1414-/* @@ fix, it's ugly looking */
1415-.comment:target {
1416- border: 1px solid #099;
1417-
1418-}
1419-
1420-
1421-
1422-
1423-
1424-#moblog{
1425- text-align: center;
1426- background: #ddd;
1427- border: 1px solid #999999;
1428- padding: 5px;
1429-}
1430-
1431-
1432-
1433-#moblog {
1434- margin: 5px 0;
1435- padding: 10px;
1436-
1437-}
1438-
1439-#moblog a:link, #moblog a:visited {
1440- border: 1px solid #0099CC;
1441-
1442- display: block;
1443- width: 85px;
1444-
1445- margin: 5px auto;
1446-}
1447-
1448-#moblog a:link:hover, #moblog a:visited:hover {
1449- border: 1px solid #903;
1450-}
1451-
1452-#moblog img {
1453- display: block;
1454-
1455- margin:0;
1456- padding: 5px;
1457-
1458- background: #fff;
1459-}
1460-
1461-
1462-#moblog p {
1463- padding: 0;
1464- margin: 0;
1465-
1466- text-align: center;
1467-}
1468
1469=== removed file 'Nevow/examples/blogengine/styles/typo.css'
1470--- Nevow/examples/blogengine/styles/typo.css 2005-10-14 17:36:24 +0000
1471+++ Nevow/examples/blogengine/styles/typo.css 1970-01-01 00:00:00 +0000
1472@@ -1,103 +0,0 @@
1473-/* --------------------
1474-definition list
1475----------------------*/
1476-
1477-dl {
1478-
1479-}
1480-
1481-dd {
1482- margin-left: 1em;
1483-}
1484-
1485-dt {
1486-
1487-}
1488-
1489-/* --------------------
1490-phrase elements
1491----------------------*/
1492-
1493-abbr, acronym
1494-{
1495- cursor: help;
1496- border-bottom: dotted 1px;
1497-}
1498-
1499-
1500-ins, del
1501-{
1502-
1503-}
1504-
1505-ins
1506-{
1507- text-decoration: none; /* some UAs reder as underlined, hence reset */
1508-}
1509-
1510-ins:before
1511-{
1512- /* content: '[' */
1513-}
1514-
1515-ins:after
1516-{
1517- /* content: ']' */
1518-}
1519-
1520-
1521-/* --------------------
1522-block/inline quotations,
1523-check: http://diveintomark.org/archives/2002/05/04/the_q_tag.html
1524----------------------*/
1525-
1526-blockquote {
1527- border-left: 4px double #6cc;
1528-
1529- padding: 0;
1530- padding-left: 10px;
1531-
1532- margin: 0.5em 5%;
1533-}
1534-
1535-cite, q {
1536- font-style: italic;
1537-}
1538-
1539-p>q, li>q, p>cite, li>cite { /* reset for mozilla, opera */
1540- font-style: normal;
1541-}
1542-
1543-cite, q {
1544- quotes: '\201C' '\201D' '\2018' '\2019'; /* quote and quote within quote */
1545-}
1546-
1547-cite:before, q:before {
1548- content: open-quote;
1549-}
1550-
1551-cite:after, q:after {
1552- content: close-quote;
1553-}
1554-
1555-
1556-/* --------------------
1557-geeks' markup codes
1558----------------------*/
1559-
1560-pre, code {
1561- font-size: 100%; /* reset size for IE */
1562-}
1563-
1564-
1565-#content>pre {
1566- width: auto; /* reset value for moz, opera */
1567-}
1568-
1569-
1570-
1571-/* mostly used to indicate markup/language keywords*/
1572-code {
1573- color: #6cc;
1574- font-weight: bold;
1575-}
1576
1577=== removed file 'Nevow/examples/blogengine/ui.html'
1578--- Nevow/examples/blogengine/ui.html 2005-10-14 17:36:24 +0000
1579+++ Nevow/examples/blogengine/ui.html 1970-01-01 00:00:00 +0000
1580@@ -1,79 +0,0 @@
1581-<?xml version="1.0" encoding="UTF-8"?>
1582-<!DOCTYPE html
1583- PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
1584- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
1585-
1586-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" xmlns:nevow="http://nevow.com/ns/nevow/0.1" nevow:render="starttimer">
1587-
1588- <head>
1589- <title>Subbacultcha</title>
1590- <style type="text/css">@import url('/styles/site.css');</style>
1591- <style type="text/css">@import url('/webform_css');</style>
1592- </head>
1593-
1594- <body>
1595-
1596- <div id="main">
1597-
1598- <div id="header">
1599- <h1>Subbacultcha</h1>
1600- <p>not offending anyone</p>
1601- </div>
1602-
1603- <div id="sidebar">
1604- <ul id="nav">
1605- <li><a id="a_home" href="/">Home</a></li>
1606- <!-- <li><a id="a_archives" title="" href="#">Archives</a></li> -->
1607- <li nevow:render="insert"><a href="#">
1608- <nevow:attr name="href"><nevow:slot name="insert" /></nevow:attr>
1609- Insert a new entry
1610- </a>
1611- </li>
1612- </ul>
1613- </div>
1614-
1615- <div id="content">
1616- <div nevow:data="getEntries" nevow:render="sequence">
1617-
1618- <div nevow:pattern="item" nevow:render="entries">
1619- <h2><nevow:slot name="title" /></h2>
1620-
1621- <!-- <p><nevow:slot name="modification"></nevow:slot></p> -->
1622-
1623- <p><nevow:slot name="content"></nevow:slot></p>
1624- <p>
1625- <a href="#">
1626- <nevow:attr name="href"><nevow:slot name="permaLink" /></nevow:attr>
1627- PermaLink
1628- </a>
1629- &bull;
1630- <nevow:invisible nevow:render="editer">
1631- <a href="#">
1632- <nevow:attr name="href"><nevow:slot name="editPost" /></nevow:attr>
1633- Edit
1634- </a>
1635- </nevow:invisible>
1636- </p>
1637-
1638- <p>Posted by <nevow:slot name="author"></nevow:slot> on <nevow:slot name="modification" />, filed under <nevow:slot name="category" /></p>
1639- </div>
1640-
1641- </div>
1642-
1643- <!-- /content -->
1644- <nevow:invisible nevow:render="needForms">
1645- <p>Edit Entry</p>
1646- <div nevow:pattern="frm" nevow:render="forms" />
1647- </nevow:invisible>
1648- </div>
1649-
1650- <div id="footer">
1651- <p>Served in <span nevow:render="stoptimer" /></p>
1652- <p>CSS by Andrea 'deelan' Peltrin, <a href="http://www.deelan.com/">website</a></p>
1653- </div>
1654-
1655- <!-- /main -->
1656- </div>
1657- </body>
1658-</html>
1659-
1660
1661=== modified file 'Nevow/examples/children/children.py'
1662--- Nevow/examples/children/children.py 2005-10-14 17:36:24 +0000
1663+++ Nevow/examples/children/children.py 2011-07-27 23:02:31 +0000
1664@@ -82,10 +82,6 @@
1665 """
1666
1667 # Let parent class have a go first
1668- # WARNING: This 3 lines work well until you use formless in this page
1669- # because formless will make locateChild return only one return value
1670- # (a deferred) on which you should add a callback that accepts a resource and
1671- # an empty tuple that represents no remaining segments.
1672 child, remainingSegments = rend.Page.locateChild(self, ctx, segments)
1673 if child:
1674 return child, remainingSegments
1675
1676=== removed directory 'Nevow/examples/customform'
1677=== removed file 'Nevow/examples/customform/__init__.py'
1678=== removed file 'Nevow/examples/customform/customform.py'
1679--- Nevow/examples/customform/customform.py 2006-03-17 15:00:39 +0000
1680+++ Nevow/examples/customform/customform.py 1970-01-01 00:00:00 +0000
1681@@ -1,159 +0,0 @@
1682-#################################################################################
1683-# Example of using patterns to change the appearance of a webform.
1684-
1685-#from twisted.application import internet, service
1686-#from twisted.web import static
1687-
1688-from zope.interface import implements
1689-
1690-from nevow import rend
1691-from nevow import url
1692-from nevow import loaders
1693-from nevow import tags as T
1694-
1695-from formless import annotate
1696-from formless import webform
1697-
1698-
1699-#################################################################################
1700-# This beasty defines how I want the form to look. It's a table (eek!).
1701-# webform looks for patterns to use when rendering parts of the form and fills
1702-# slots with key information.
1703-#
1704-# Key patterns are:
1705-# freeform-form -- the form itself, mostly just the structure
1706-# argument -- the pattern to use for arguments when nothing better
1707-# is found
1708-# argument!!fo -- the pattern to use for the 'fo' argument
1709-#
1710-# Inside the patterns the following slots are filled:
1711-# freeform-form:
1712-# form-action -- action attribute, where the form will be posted
1713-# form-id -- id of the form
1714-# form-name -- name of the form
1715-# form-label -- form label, extracted from the docstring
1716-# form-description -- description, also extracted from the docstring
1717-# form-error -- "global" error
1718-# form-arguments -- insertion point for the arguments' HTML
1719-# argument:
1720-# label -- label
1721-# input -- the form element (input, textarea, etc)
1722-# error -- error message (if any)
1723-# description -- description of argument
1724-#
1725-# Note that you do not have to provide slots for all of the above. For
1726-# instance, you may not want to display the descriptions.
1727-#
1728-# Chances are that this block of text would be in a disk template or
1729-# perhaps defined using stan in a taglib module.
1730-
1731-
1732-FORM_LAYOUT = loaders.xmlstr(
1733- """<?xml version="1.0"?>
1734- <form xmlns:n="http://nevow.com/ns/nevow/0.1" n:pattern="freeform-form">
1735-
1736- <!-- Replace/fill the form attributes -->
1737- <n:attr name="action"><n:slot name="form-action"/></n:attr>
1738- <n:attr name="id"><n:slot name="form-id"/></n:attr>
1739- <n:attr name="name"><n:slot name="form-name"/></n:attr>
1740-
1741- <!-- General form information -->
1742- <p><strong><n:slot name="form-label"/></strong></p>
1743- <p><em><n:slot name="form-description"/></em></p>
1744- <p><strong><em><n:slot name="form-error"/></em></strong></p>
1745-
1746- <!-- Start of the form layout table -->
1747- <table style="background: #eee; border: 1px solid #bbb; padding: 1em;" >
1748- <!-- Mark location arguments will be added -->
1749- <n:slot name="form-arguments"/>
1750- <!-- General argument layout pattern -->
1751- <n:invisible n:pattern="argument" n:render="remove">
1752- <tr>
1753- <th><n:slot name="label"/>:</th>
1754- <td><n:slot name="input"/><span class="freeform-error"><n:slot name="error"/></span></td>
1755- </tr>
1756- <tr>
1757- <th></th>
1758- <td><n:slot name="description"/></td>
1759- </tr>
1760- </n:invisible>
1761- <!-- Argument layout, just for fum -->
1762- <n:invisible n:pattern="argument!!fo" n:render="remove">
1763- <tr>
1764- <th><n:slot name="label"/>:</th>
1765- <td>
1766- <textarea cols="40" rows="5"><n:attr name="id"><n:slot name="id"/></n:attr><n:attr name="name"><n:slot name="name"/></n:attr><n:slot name="value"/></textarea>
1767- <span class="freeform-error"><n:slot name="error"/></span></td>
1768- </tr>
1769- <tr>
1770- <th></th>
1771- <td><n:slot name="description"/></td>
1772- </tr>
1773- </n:invisible>
1774- <!-- Button row -->
1775- <tr>
1776- <td colspan="2">
1777- <n:slot name="form-button"/>
1778- </td>
1779- </tr>
1780- </table>
1781- </form>
1782- """).load()
1783-
1784-
1785-#################################################################################
1786-# ISomething and Page are just something to test the form rendering on.
1787-
1788-class ISomething(annotate.TypedInterface):
1789-
1790- def doSomething(
1791- ctx = annotate.Context(),
1792- fee = annotate.String(required=True, description="Wee!"),
1793- fi = annotate.Integer(description="Tra-la-la"),
1794- fo = annotate.Text(),
1795- fum = annotate.String(),
1796- ):
1797- """Do Something Really Exciting
1798-
1799- Normally you would put a useful description of the interface here but,
1800- since the inteface is useless anyway, I cannot think of anything
1801- useful to say about it. Although ... did I mention it is useless?"""
1802- doSomething = annotate.autocallable(doSomething)
1803-
1804-
1805-class Root(rend.Page):
1806- """Render a custom and normal form for an ISomething.
1807- """
1808- implements(ISomething)
1809- addSlash = True
1810-
1811- child_webform_css = webform.defaultCSS
1812-
1813- def render_normalForm(self, ctx, data):
1814- return webform.renderForms()
1815-
1816- def render_customForm(self, ctx, data):
1817- return webform.renderForms()[FORM_LAYOUT]
1818-
1819- def doSomething(self, ctx, **kwargs):
1820- print '***** doSomething called with:', kwargs
1821-
1822- docFactory = loaders.stan(
1823- T.html[
1824- T.head[
1825- T.title['Example :: Custom Form Layout'],
1826- T.link(rel='stylesheet', type='text/css', href=url.here.child("webform_css")),
1827- ],
1828- T.body[
1829- T.h1['Custom'],
1830- render_customForm,
1831- T.h1['Default'],
1832- render_normalForm,
1833- ]
1834- ]
1835- )
1836-
1837-
1838-#application = service.Application('hellostan')
1839-#webServer = internet.TCPServer(8080, appserver.NevowSite(Root()))
1840-#webServer.setServiceParent(application)
1841
1842=== removed directory 'Nevow/examples/db'
1843=== removed file 'Nevow/examples/db/__init__.py'
1844=== removed file 'Nevow/examples/db/db.py'
1845--- Nevow/examples/db/db.py 2006-04-14 17:23:46 +0000
1846+++ Nevow/examples/db/db.py 1970-01-01 00:00:00 +0000
1847@@ -1,132 +0,0 @@
1848-
1849-from zope.interface import implements
1850-
1851-from nevow import inevow
1852-from nevow import loaders
1853-from nevow import rend
1854-from nevow import tags
1855-from nevow.url import here
1856-
1857-from formless import annotate
1858-from formless import webform
1859-
1860-
1861-whole = [(1, 'one'), (2, 'two'), (3, 'buckle'), (4, 'my'), (5, 'shoe')]
1862-
1863-
1864-def doQuery(q, *args):
1865- """Pretend like we have a database and we are accessing it through this hypothetical interface.
1866- Ignore this. Use dbapi or adbapi instead, and build a real sql table. I hope that's obvious.
1867- """
1868- matchid = 'select * from foo where id ='
1869- setsql = 'update foo set subject = '
1870- insertsql = 'insert into foo values'
1871- if q == 'select * from foo':
1872- return whole
1873- elif q.startswith(matchid):
1874- theId = args[0]
1875- for dbid, subj in whole:
1876- if dbid == theId:
1877- return [(dbid, subj)]
1878- raise KeyError, theId
1879- elif q.startswith(setsql):
1880- newsubj, theId = args
1881- for index, (dbid, subj) in enumerate(whole):
1882- if dbid == theId:
1883- whole[index] = (dbid, newsubj)
1884- elif q.startswith(insertsql):
1885- max = whole[-1][0]
1886- subject, = args
1887- whole.append((max + 1, subject))
1888-
1889-
1890-class IAddItem(annotate.TypedInterface):
1891- def addItem(newSubject=annotate.String()):
1892- pass
1893- addItem = annotate.autocallable(addItem)
1894-
1895-
1896-class DBBrowser(rend.Page):
1897- implements(IAddItem)
1898- addSlash = True
1899-
1900- def addItem(self, newSubject):
1901- doQuery('insert into foo values subject = "%s"', newSubject)
1902-
1903- def data_queryDatabase(self, context, data):
1904- return doQuery('select * from foo')
1905-
1906- def render_row(self, context, data):
1907- theId, theSubj = data
1908- return context.tag[ # put our anchor in the li provided by the template
1909- tags.a(href=theId)[ theSubj ]
1910- ]
1911-
1912- docFactory = loaders.stan(
1913- tags.html[
1914- tags.body[
1915- tags.h1["Welcome, user"],
1916- tags.ul(data=tags.directive("queryDatabase"), render=tags.directive("sequence"))[
1917- tags.li(pattern="item", render=render_row)
1918- ],
1919- webform.renderForms()
1920- ]
1921- ]
1922- )
1923-
1924- def childFactory(self, ctx, name):
1925- """Since we created anchor tags linking to children of this resource
1926- directly by id, when the anchor is clicked, childFactory will be called
1927- with the appropriate id as the name argument."""
1928- try:
1929- ## Pass the id of the database item we want to be rendered on this page
1930- ## to the DBItem constructor. This integer will be used as the default data
1931- ## for this page.
1932- return DBItem(int(name))
1933- except ValueError:
1934- pass
1935- ## returning None results in a 404
1936-
1937-
1938-class IItemWithSubject(annotate.TypedInterface):
1939- def setSubject(newSubject=annotate.String(label="Change Subject")):
1940- pass
1941- setSubject = annotate.autocallable(setSubject)
1942-
1943-
1944-class DBItem(rend.Page):
1945- implements(IItemWithSubject)
1946- addSlash=True
1947-
1948- def setSubject(self, newSubject):
1949- ## Self.original is the data that was passed to the DBItem constructor above; the id of this record
1950- doQuery('update foo set subject = "%s" where id = %s', newSubject, self.original)
1951-
1952- def render_viewSelector(self, context, data):
1953- args = inevow.IRequest(context).args
1954- view = args.get('view', ['view'])[0]
1955- if view == 'view':
1956- selector = "View | ", tags.a(href=here.add('view','edit'))[ "Edit" ]
1957- editor = ''
1958- else:
1959- selector = tags.a(href=here.add('view','view'))["View"], " | Edit"
1960- editor = context.onePattern('edit')() # get one copy of the edit pattern
1961- viewer = context.onePattern('view')() # get one copy of the view pattern
1962- return selector, viewer, editor
1963-
1964- def render_itemDetail(self, context, data):
1965- theId, theSubject = doQuery('select * from foo where id = %s', self.original)[0]
1966- return tags.h2["Object ", theId], tags.span["Subject: ", theSubject]
1967-
1968- docFactory = loaders.stan(
1969- tags.html[
1970- tags.body[
1971- tags.p[tags.a(href=here.parent())["Up"]],
1972- tags.div(render=render_viewSelector)[
1973- tags.p(pattern="edit")[webform.renderForms()],
1974- tags.p(pattern="view")[render_itemDetail]
1975- ]
1976- ]
1977- ]
1978- )
1979-
1980
1981=== modified file 'Nevow/examples/examples.tac'
1982--- Nevow/examples/examples.tac 2009-07-06 12:22:09 +0000
1983+++ Nevow/examples/examples.tac 2011-07-27 23:02:31 +0000
1984@@ -22,22 +22,15 @@
1985 import sys
1986
1987 try:
1988- from advanced_manualform import advanced_manualform
1989- from customform import customform
1990 from disktemplates import disktemplates
1991 from disktemplates import disktemplates_stan
1992 from simple import simple
1993 from simple import simplehtml
1994- from tree import tree
1995- from formpost import formpost2
1996- from formpost import formpost
1997 from children import children
1998 from children import childrenhtml
1999 from table import tablehtml
2000 from irenderer import irenderer
2001 from irenderer import simple_irenderer
2002- from formbuilder import formbuilder
2003- from db import db
2004 from hello import hellohtml
2005 from hello import hellostan
2006 from canvas import canvas
2007@@ -58,11 +51,10 @@
2008 from cal import cal
2009 from tabbed import tabbed
2010 from progress import progress
2011- from tests import testformless, testexamples
2012+ from tests import testexamples
2013 from nevow import livetest
2014
2015 from athenademo import calculator
2016- from athenademo import typeahead
2017 from athenademo import widgets
2018 from athenademo import benchmark
2019 except ImportError, e:
2020@@ -127,21 +119,15 @@
2021 child_sources.contentTypes = {}
2022 child_cssfile = static.File('index.css')
2023 children = dict(
2024- customform=customform.Root(),
2025 disktemplates=disktemplates.Mine(),
2026 disktemplates_stan=disktemplates_stan.Mine(),
2027 simple=simple.Simple(),
2028 simplehtml=simplehtml.Simple(),
2029- tree=tree.Tree('base', 'base'),
2030- formpost2=formpost2.FormPage(formpost2.Implementation()),
2031- formpost=formpost.FormPage(),
2032 children=children.RootPage(),
2033 childrenhtml=childrenhtml.RootPage(),
2034 tablehtml=tablehtml.Table(),
2035 irenderer=irenderer.Page(),
2036 simple_irenderer=simple_irenderer.Page(),
2037- formbuilder=formbuilder.FormBuilder(),
2038- db=db.DBBrowser(),
2039 hellohtml=hellohtml.Page(),
2040 hellostan=hellostan.Page(),
2041 canvas=canvas.createResource(),
2042@@ -149,7 +135,6 @@
2043 guarded=guarded.createResource(),
2044 guarded2=guarded2.createResource(),
2045 xul_nevow=xul_nevow.createResource(),
2046- advanced_manualform=advanced_manualform.Page(),
2047 liveanimal=liveanimal.createResource(),
2048 http_auth=http_auth.AuthorizationRequired(),
2049 most_basic=most_basic.root,
2050@@ -165,12 +150,8 @@
2051 tests=testexamples.createResource(),
2052 livetests=testexamples.createLiveSuite(),
2053 testtests=livetest.createResource(),
2054- testformless=testformless.NameWizard(),
2055- formless_redirector=testformless.Redirector(),
2056- formless_tests=testformless.formless_tests,
2057 fragments=fragments.Root(),
2058 macros=macros.Root(),
2059- typeahead=typeahead.DataEntry(),
2060 )
2061
2062 def child_calculator(self, ctx):
2063
2064=== removed directory 'Nevow/examples/formbuilder'
2065=== removed file 'Nevow/examples/formbuilder/__init__.py'
2066=== removed file 'Nevow/examples/formbuilder/formbuilder.py'
2067--- Nevow/examples/formbuilder/formbuilder.py 2006-04-14 17:23:46 +0000
2068+++ Nevow/examples/formbuilder/formbuilder.py 1970-01-01 00:00:00 +0000
2069@@ -1,98 +0,0 @@
2070-## formbuilder
2071-
2072-from zope.interface import implements
2073-
2074-from nevow import rend
2075-from nevow import loaders
2076-from nevow import tags as T
2077-from nevow import util
2078-
2079-from formless import annotate
2080-from formless import webform
2081-from formless import configurable
2082-
2083-from twisted.python import reflect
2084-
2085-
2086-class BuilderCore(configurable.Configurable):
2087- def __init__(self):
2088- configurable.Configurable.__init__(self, None)
2089- self.formElements = []
2090-
2091- def getBindingNames(self, ctx):
2092- return ['form']
2093-
2094- def bind_form(self, ctx):
2095- return annotate.MethodBinding(
2096- 'action',
2097- annotate.Method(arguments=self.formElements))
2098-
2099- def action(self, **kw):
2100- print "ACTION!", kw
2101-
2102- def addElement(self, name, type):
2103- self.formElements.append(
2104- annotate.Argument(name, type()))
2105-
2106-
2107-allTypes = [annotate.String, annotate.Text, annotate.Integer, annotate.Real, annotate.Password]
2108-typeChoice = annotate.Choice(choices=allTypes, valueToKey=reflect.qual, keyToValue=reflect.namedAny, stringify=lambda x: x.__name__)
2109-
2110-
2111-class IFormBuilder(annotate.TypedInterface):
2112- def addElement(name=annotate.String(required=True), type=typeChoice):
2113- """Add Element
2114-
2115- Add an element to this form.
2116- """
2117- pass
2118- addElement = annotate.autocallable(addElement)
2119-
2120- def clearForm():
2121- """Clear Form
2122-
2123- Clear this form.
2124- """
2125- clearForm = annotate.autocallable(clearForm)
2126-
2127-
2128-class FormBuilder(rend.Page):
2129- implements(IFormBuilder)
2130- addSlash = True
2131-
2132- def __init__(self):
2133- rend.Page.__init__(self)
2134- self.clearForm()
2135-
2136- def configurable_formBuilder(self, ctx):
2137- return configurable.TypedInterfaceConfigurable(self)
2138-
2139- def configurable_dynamicForm(self, ctx):
2140- return self.builderCore
2141-
2142- def addElement(self, name, type):
2143- self.builderCore.addElement(name, type)
2144-
2145- def clearForm(self):
2146- self.builderCore = BuilderCore()
2147-
2148- docFactory = loaders.stan(T.html[
2149- T.head[
2150- T.title["Form builder!"]],
2151- T.style(type="text/css")[
2152- open(util.resource_filename('formless', 'freeform-default.css')).read()],
2153- T.body[
2154- T.h1["Welcome to form builder"],
2155- webform.renderForms('formBuilder'),
2156- T.h2["Here is your form:"],
2157- webform.renderForms('dynamicForm')]])
2158-
2159-
2160-## Startup glue
2161-from nevow import appserver
2162-from twisted.application import service
2163-from twisted.application import internet
2164-
2165-application = service.Application('formbuilder')
2166-internet.TCPServer(8080, appserver.NevowSite(FormBuilder())).setServiceParent(application)
2167-
2168
2169=== removed directory 'Nevow/examples/formpost'
2170=== removed file 'Nevow/examples/formpost/__init__.py'
2171=== removed file 'Nevow/examples/formpost/formpost.py'
2172--- Nevow/examples/formpost/formpost.py 2005-10-14 17:36:24 +0000
2173+++ Nevow/examples/formpost/formpost.py 1970-01-01 00:00:00 +0000
2174@@ -1,41 +0,0 @@
2175-# -*- python -*-
2176-
2177-from zope.interface import implements
2178-
2179-from nevow import loaders
2180-from nevow import rend
2181-from nevow import tags
2182-from nevow import url
2183-
2184-from formless import annotate
2185-from formless import webform
2186-
2187-class IMyForm(annotate.TypedInterface):
2188- foo = annotate.Integer()
2189-
2190-
2191-class FormPage(rend.Page):
2192- implements(IMyForm)
2193-
2194- addSlash = True
2195-
2196- child_webform_css = webform.defaultCSS
2197-
2198- # We need this to implement IMyForm
2199- foo = 5
2200-
2201- docFactory = loaders.stan(
2202- tags.html[
2203- tags.head[
2204- tags.link(rel='stylesheet', type='text/css', href=url.here.child('webform_css')),
2205- ],
2206- tags.body[
2207- "Hello! Here is a form:",
2208-
2209- # We want to render the "default" configurable.
2210- # This is located in Page.configurable_() and is going to be
2211- # 'self' (which, as you see above, implements IMyForm).
2212- webform.renderForms(),
2213- ],
2214- ],
2215- )
2216
2217=== removed file 'Nevow/examples/formpost/formpost2.py'
2218--- Nevow/examples/formpost/formpost2.py 2006-03-22 18:03:26 +0000
2219+++ Nevow/examples/formpost/formpost2.py 1970-01-01 00:00:00 +0000
2220@@ -1,83 +0,0 @@
2221-# -*- python -*-
2222-
2223-from zope.interface import implements
2224-
2225-from nevow import loaders
2226-from nevow import rend
2227-from nevow import tags
2228-from nevow import inevow
2229-from nevow import url
2230-
2231-from formless import annotate
2232-from formless import webform
2233-
2234-from twisted.internet import defer
2235-
2236-
2237-#oldChoicesWay = annotate.Choice(choicesAttribute='theChoices') # Doing this gives you a DeprecationWarning now
2238-
2239-# If you still want to use an attribute or method of some other object, you should use a function as shown below,
2240-# but look up IResource(ctx) or IConfigurable(ctx), whichever is more appropriate.
2241-newChoicesWay = annotate.Choice(lambda c, d: range(30))
2242-deferChoicesWay = annotate.Choice(lambda c, d: defer.succeed(['abcd', 'efgh', 'ijkl']))
2243-radioChoices = annotate.Radio(["Old", "Tyme", "Radio"])
2244-
2245-## An example of using custom valueToKey and keyToValue functions to serialize/deserialize items
2246-values = {0: dict(name="Zero", stuff=1234), 1: dict(name="One", stuff=1234), 2: dict(name="Two", stuff=2345435)}
2247-customValueToKey = annotate.Choice(
2248- [0, 1, 2], # Perhaps these are primary keys in a database
2249- stringify=lambda x: values[x]['name'], # Do a database lookup to render a nice label in the ui
2250- valueToKey=str, # Convert the primary key to a value suitable for sending across the web
2251- keyToValue=lambda x: values[int(x)]) # Do a database lookup to get the actual value to pass to the binding
2252-
2253-
2254-class IMyForm(annotate.TypedInterface):
2255- foo = annotate.Integer()
2256-
2257- def bar(baz=annotate.Integer(),
2258- slam=newChoicesWay, ham=deferChoicesWay, radio=radioChoices, custom=customValueToKey):
2259- pass
2260- bar = annotate.autocallable(bar)
2261-
2262-
2263-class Implementation(object):
2264- implements(IMyForm)
2265-
2266- foo = 5
2267-
2268- def bar(self, baz, slam, ham, radio, custom):
2269- return "You called bar! %s %s %s %s %r" % (baz, slam, ham, radio, custom)
2270-
2271- theChoices = [1, 2, 3]
2272-
2273-
2274-class FormPage(rend.Page):
2275-
2276- addSlash = True
2277-
2278- child_webform_css = webform.defaultCSS
2279-
2280- def render_hand(self, ctx, data):
2281- hand = inevow.IHand(ctx, None)
2282- if hand is not None:
2283- return ctx.tag[hand]
2284- return ''
2285-
2286- docFactory = loaders.stan(
2287- tags.html[
2288- tags.head[
2289- tags.link(rel='stylesheet', type='text/css', href=url.here.child('webform_css')),
2290- ],
2291- tags.body[
2292- tags.h3(render=render_hand, style="color: red; font-size: xx-large"),
2293- "Hello! Here is a form:",
2294-
2295- # We want to render forms defined by the Implementation instance.
2296- # When we pass the Implementation instance to FormPage below,
2297- # rend.Page sets it as the .original attribute. To tell webform to render
2298- # forms described by this object, we use the configurable name "original".
2299- webform.renderForms('original'),
2300- ],
2301- ],
2302- )
2303-
2304
2305=== removed directory 'Nevow/examples/image_uploader'
2306=== removed file 'Nevow/examples/image_uploader/images.py'
2307--- Nevow/examples/image_uploader/images.py 2006-01-22 00:10:42 +0000
2308+++ Nevow/examples/image_uploader/images.py 1970-01-01 00:00:00 +0000
2309@@ -1,35 +0,0 @@
2310-from zope.interface import implements, Interface
2311-
2312-from axiom import store, item
2313-from axiom.attributes import text, bytes
2314-
2315-class IImages(Interface):
2316- pass
2317-
2318-class Image(item.Item):
2319- title = text()
2320- author = text()
2321- image = bytes()
2322- hash = text()
2323-
2324-class Application(item.Item, item.InstallableMixin):
2325- implements(IImages)
2326-
2327- name = text()
2328-
2329- def installOn(self, other):
2330- super(Application, self).installOn(other)
2331- other.powerUp(self, IImages)
2332-
2333- def getImages(self, how_many=None):
2334- return self.store.query(Image, limit=how_many, sort=Image.storeID.descending)
2335-
2336- def getOne(self, hash):
2337- return self.store.findUnique(Image, Image.hash==hash)
2338-
2339-def initialize():
2340- s = store.Store('imagination.axiom')
2341- images = IImages(s, None)
2342- if not images:
2343- Application(store=s, name=u'Imagination').installOn(s)
2344- return s
2345
2346=== removed file 'Nevow/examples/image_uploader/imagination.py'
2347--- Nevow/examples/image_uploader/imagination.py 2006-03-17 15:00:39 +0000
2348+++ Nevow/examples/image_uploader/imagination.py 1970-01-01 00:00:00 +0000
2349@@ -1,85 +0,0 @@
2350-from zope.interface import implements
2351-
2352-from nevow import loaders, rend, tags as t, static, url
2353-from formless import webform, annotate
2354-
2355-from images import Image, IImages
2356-
2357-import random
2358-from string import ascii_letters as alpha # ohhh...
2359-
2360-alphaDigit = alpha + '0123456789'
2361-
2362-def label(length=None):
2363- """
2364- Return one of 183,123,959,522,816 possible labels.
2365- """
2366-
2367- first = random.choice(alpha)
2368- rest = [random.choice(alphaDigit) for i in xrange(length or 7)]
2369- newLabel = first + ''.join(rest)
2370- return newLabel
2371-
2372-class IInsert(annotate.TypedInterface):
2373- def insert(ctx = annotate.Context(),
2374- title = annotate.String(),
2375- author = annotate.String(),
2376- image = annotate.FileUpload(required=True,
2377- requiredFailMessage="Must upload something")
2378- ):
2379- """ Insert a new image """
2380- insert = annotate.autocallable(insert, action="New Image")
2381-
2382-class TransactionalPage(rend.Page):
2383- adaptsToStore = False
2384- def __init__(self, store, *args, **kwargs):
2385- super(TransactionalPage, self).__init__(*args, **kwargs)
2386- self.store = store
2387-
2388- def locateChild(self, ctx, segments):
2389- return self.store.transact(super(TransactionalPage, self).locateChild, ctx, segments)
2390-
2391- def renderHTTP(self, ctx):
2392- return self.store.transact(super(TransactionalPage, self).renderHTTP, ctx)
2393-
2394-
2395-class Root(TransactionalPage):
2396- child_webform_css = webform.defaultCSS
2397- implements(IInsert)
2398-
2399- docFactory = loaders.stan(
2400- t.html[
2401- t.head[
2402- t.title['Imagination'],
2403- t.link(rel='stylesheet', type='text/css', href=url.root.child('webform_css'))
2404- ],
2405- t.body[
2406- webform.renderForms(),
2407- t.ul(render=t.directive("sequence"),
2408- data=t.directive("images"))[
2409- t.li(pattern="item", render=t.directive("image")),
2410- t.li(pattern="empty")["No images yet"]
2411- ]
2412- ]
2413- ]
2414- )
2415-
2416- def data_images(self, ctx, data):
2417- return IImages(self.store).getImages(15)
2418-
2419- def render_image(self, ctx, data):
2420- return t.a(href=url.root.child('fs').child(data.hash))[data.title]
2421-
2422- def insert(self, ctx, title, author, image):
2423- img = Image(store=self.store,
2424- image=image.value,
2425- title=title.decode('utf-8'),
2426- author=author.decode('utf-8'),
2427- hash=label().decode('utf-8'))
2428-
2429- def locateChild(self, ctx, segments):
2430- if segments[0] == 'fs':
2431- data = IImages(self.store).getOne(segments[1].decode('utf-8'))
2432- return static.Data(data.image, 'image/jpeg'), ()
2433- return super(Root, self).locateChild(ctx, segments)
2434-
2435
2436=== removed file 'Nevow/examples/image_uploader/imagination.tac'
2437--- Nevow/examples/image_uploader/imagination.tac 2006-01-22 00:10:42 +0000
2438+++ Nevow/examples/image_uploader/imagination.tac 1970-01-01 00:00:00 +0000
2439@@ -1,9 +0,0 @@
2440-from twisted.application import service, strports
2441-from nevow import appserver
2442-
2443-import imagination, images
2444-
2445-application = service.Application('image_uploader')
2446-db = images.initialize()
2447-site = appserver.NevowSite(resource = imagination.Root(db))
2448-strports.service("8080", site).setServiceParent(application)
2449
2450=== modified file 'Nevow/examples/index.html'
2451--- Nevow/examples/index.html 2009-07-06 12:22:09 +0000
2452+++ Nevow/examples/index.html 2011-07-27 23:02:31 +0000
2453@@ -69,17 +69,11 @@
2454 <ol>
2455 <li><a href="/tests/">Run basic tests</a></li>
2456
2457- <li><a href="/formless_tests/">Run formless tests</a></li>
2458-
2459 <li><a href="/livetests/">Run livepage example tests</a></li>
2460
2461 <li><a href="/testtests/tests/">Test test harness</a></li>
2462 </ol>
2463
2464- <p>Athena also has <a href="/athenatest/">some tests</a>, although
2465- there is not yet a fancy test runner like the one demonstrated
2466- above.</p>
2467-
2468 <h1 id="examples">Examples Listing</h1>
2469
2470 <ol>
2471@@ -427,122 +421,6 @@
2472 </li>
2473
2474 <li>
2475- <span>Advanced manual form example</span>
2476-
2477- <div class="source">
2478- <table border="0" cellpadding="0" cellspacing="0" width=
2479- "100%">
2480- <tbody>
2481- <tr>
2482- <td>Stan Source</td>
2483-
2484- <td width="100%"><a href=
2485- "sources/advanced_manualform/advanced_manualform.py">
2486- advanced_manualform.py</a></td>
2487- </tr>
2488- </tbody>
2489- </table>Live example: <a href=
2490- "advanced_manualform/">form</a>
2491- </div>
2492- </li>
2493-
2494- <li>
2495- <span>Formless example</span>
2496-
2497- <div class="source">
2498- <table border="0" cellpadding="0" cellspacing="0" width=
2499- "100%">
2500- <tbody>
2501- <tr>
2502- <td>Stan Source</td>
2503-
2504- <td width="100%"><a href=
2505- "sources/formpost/formpost.py">formpost.py</a></td>
2506- </tr>
2507- </tbody>
2508- </table>Live example: <a href="formpost/">formpost</a>
2509- </div>
2510- </li>
2511-
2512- <li>
2513- <span>Another formless example, but a little bit more
2514- complex</span>
2515-
2516- <div class="source">
2517- <table border="0" cellpadding="0" cellspacing="0" width=
2518- "100%">
2519- <tbody>
2520- <tr>
2521- <td>Stan Source</td>
2522-
2523- <td width="100%"><a href=
2524- "sources/formpost/formpost2.py">formpost2.py</a></td>
2525- </tr>
2526- </tbody>
2527- </table>Live example: <a href="formpost2/">formpost2</a>
2528- </div>
2529- </li>
2530-
2531- <li>
2532- <span><b>[0.5]</b>Using formless to create multi-step
2533- wizards by returning Page instances from
2534- autocallables</span>
2535-
2536- <div class="source">
2537- <table border="0" cellpadding="0" cellspacing="0" width=
2538- "100%">
2539- <tbody>
2540- <tr>
2541- <td>Stan Source</td>
2542-
2543- <td width="100%"><a href=
2544- "sources/tests/testformless.py">tests/testformless.py</a></td>
2545- </tr>
2546- </tbody>
2547- </table>Live example: <a href=
2548- "testformless">testformless</a>
2549- </div>
2550- </li>
2551-
2552- <li>
2553- <span><b>[0.5]</b>Using formless, return a URL instance
2554- from an autocallable to redirect to it</span>
2555-
2556- <div class="source">
2557- <table border="0" cellpadding="0" cellspacing="0" width=
2558- "100%">
2559- <tbody>
2560- <tr>
2561- <td>Stan Source</td>
2562-
2563- <td width="100%"><a href=
2564- "sources/tests/testformless.py">tests/testformless.py</a></td>
2565- </tr>
2566- </tbody>
2567- </table>Live example: <a href=
2568- "formless_redirector">formless_redirector</a>
2569- </div>
2570- </li>
2571-
2572- <li>
2573- <span>Example of interacting with a database</span>
2574-
2575- <div class="source">
2576- <table border="0" cellpadding="0" cellspacing="0" width=
2577- "100%">
2578- <tbody>
2579- <tr>
2580- <td>Stan Source:</td>
2581-
2582- <td width="100%"><a href=
2583- "sources/db/db.py">db.py</a></td>
2584- </tr>
2585- </tbody>
2586- </table>Live examples: <a href="db/">db</a>
2587- </div>
2588- </li>
2589-
2590- <li>
2591 <span>An example of using HTTP Basic Auth for simple
2592 authentication</span>
2593
2594@@ -637,25 +515,6 @@
2595 </li>
2596
2597 <li>
2598- <span>Dynamically build your forms</span>
2599-
2600- <div class="source">
2601- <table border="0" cellpadding="0" cellspacing="0" width=
2602- "100%">
2603- <tbody>
2604- <tr>
2605- <td>Stan Source</td>
2606-
2607- <td width="100%"><a href=
2608- "sources/formbuilder/formbuilder.py">formbuilder.py</a></td>
2609- </tr>
2610- </tbody>
2611- </table>Live example: <a href=
2612- "formbuilder/">formbuilder</a>
2613- </div>
2614- </li>
2615-
2616- <li>
2617 <span>Adapting an object to the IRenderer interface in
2618 order to make it render itself</span>
2619
2620@@ -695,24 +554,6 @@
2621 </li>
2622
2623 <li>
2624- <span>Handling and building a Tree structure dynamically on
2625- yor site</span>
2626-
2627- <div class="source">
2628- <table border="0" cellpadding="0" cellspacing="0">
2629- <tbody>
2630- <tr>
2631- <td>Stan Source</td>
2632-
2633- <td width="100%"><a href=
2634- "sources/tree/tree.py">tree.py</a></td>
2635- </tr>
2636- </tbody>
2637- </table>Live example: <a href="tree/">tree</a>
2638- </div>
2639- </li>
2640-
2641- <li>
2642 <span>Simple example of text localisation</span>
2643
2644 <div class="source">
2645@@ -961,22 +802,6 @@
2646 </li>
2647
2648 <li>
2649- <span>Pastebin example with nevow</span>
2650-
2651- <div class="source">
2652- Source: <a href="sources/pastebin">pastebin</a>
2653- </div>
2654- </li>
2655-
2656- <li>
2657- <span>Blog engine</span>
2658-
2659- <div class="source">
2660- Source: <a href="sources/blogengine">blogengine</a>
2661- </div>
2662- </li>
2663-
2664- <li>
2665 <span>Link storage webservice (uses Twisted's
2666 XML-RPC)</span>
2667
2668@@ -984,23 +809,6 @@
2669 Source: <a href="sources/postit">postit</a>
2670 </div>
2671 </li>
2672-
2673- <li>
2674- <span>Todo list with rails like file structure (requires
2675- pgasync 1.3b and postgres)</span>
2676-
2677- <div class="source">
2678- Source: <a href="sources/todo">todo</a>
2679- </div>
2680- </li>
2681-
2682- <li>
2683- <span>Image uploader that uses axiom</span>
2684-
2685- <div class="source">
2686- Source: <a href="sources/image_uploader">imagination</a>
2687- </div>
2688- </li>
2689 </ul>
2690 </div>
2691 </body>
2692
2693=== removed directory 'Nevow/examples/pastebin'
2694=== removed file 'Nevow/examples/pastebin/TODO'
2695--- Nevow/examples/pastebin/TODO 2005-10-14 17:36:24 +0000
2696+++ Nevow/examples/pastebin/TODO 1970-01-01 00:00:00 +0000
2697@@ -1,11 +0,0 @@
2698-Syntax highlighting: Python, HTML, diff etc
2699-Coloured diff view
2700-Cookie to save author
2701-UI - move menu etc to right
2702-View | Edit when viewing latest revision
2703-Line numbers
2704-Wrap the syntax highlighted bit.
2705-
2706-Syntax highligh options:
2707-t.p.htmlizer, enscript, webcpp, SilverCity
2708-copy source code highlight code from viewcvs
2709
2710=== removed directory 'Nevow/examples/pastebin/data'
2711=== removed directory 'Nevow/examples/pastebin/pastebin'
2712=== removed file 'Nevow/examples/pastebin/pastebin.tac'
2713--- Nevow/examples/pastebin/pastebin.tac 2005-10-14 17:36:24 +0000
2714+++ Nevow/examples/pastebin/pastebin.tac 1970-01-01 00:00:00 +0000
2715@@ -1,25 +0,0 @@
2716-from twisted.application import strports
2717-from twisted.application import service
2718-
2719-from twisted.web import static
2720-
2721-from nevow import appserver
2722-from nevow import vhost
2723-
2724-from pastebin import interfaces
2725-from pastebin.service import FSPasteBinService
2726-from pastebin.web import pages
2727-
2728-
2729-application = service.Application('pastebin')
2730-
2731-pastebin = FSPasteBinService('data')
2732-pastebin.setServiceParent(application)
2733-
2734-appResource = pages.RootPage(pastebin)
2735-appResource.putChild('robots.txt', static.File('static/robots.txt'))
2736-vResource = vhost.VHostMonsterResource()
2737-appResource.putChild('vhost', vResource)
2738-
2739-
2740-strports.service("8080", appserver.NevowSite(appResource)).setServiceParent(application)
2741
2742=== removed file 'Nevow/examples/pastebin/pastebin/__init__.py'
2743=== removed file 'Nevow/examples/pastebin/pastebin/interfaces.py'
2744--- Nevow/examples/pastebin/pastebin/interfaces.py 2006-03-08 14:28:41 +0000
2745+++ Nevow/examples/pastebin/pastebin/interfaces.py 1970-01-01 00:00:00 +0000
2746@@ -1,18 +0,0 @@
2747-from zope.interface import Interface
2748-
2749-class IPasteBin(Interface):
2750-
2751- def getListOfPastings(limit=None):
2752- """
2753- (oid, author, time) tuples
2754- """
2755- pass
2756-
2757- def getPasting(oid):
2758- pass
2759-
2760- def addPasting(author, text):
2761- pass
2762-
2763- def updatePasting(oid, author, text):
2764- pass
2765
2766=== removed file 'Nevow/examples/pastebin/pastebin/pasting.py'
2767--- Nevow/examples/pastebin/pastebin/pasting.py 2006-03-08 14:28:41 +0000
2768+++ Nevow/examples/pastebin/pastebin/pasting.py 1970-01-01 00:00:00 +0000
2769@@ -1,25 +0,0 @@
2770-from zope.interface import Interface
2771-
2772-
2773-class IPasting(Interface):
2774-
2775- def getLatestVersion():
2776- """Return the latest version"""
2777-
2778- def getVersion(version):
2779- """Get a specific version"""
2780-
2781- def getHistory():
2782- """Get the history of the pasting as a list of (version, author, time) tuples."""
2783-
2784-
2785-class IVersion(Interface):
2786-
2787- def getAuthor():
2788- pass
2789-
2790- def getText():
2791- pass
2792-
2793- def getTime():
2794- pass
2795
2796=== removed file 'Nevow/examples/pastebin/pastebin/service.py'
2797--- Nevow/examples/pastebin/pastebin/service.py 2005-10-14 17:36:24 +0000
2798+++ Nevow/examples/pastebin/pastebin/service.py 1970-01-01 00:00:00 +0000
2799@@ -1,120 +0,0 @@
2800-import cPickle as pickle
2801-import os.path
2802-import time
2803-from zope.interface import implements
2804-
2805-from twisted.application import service
2806-from twisted.python import log
2807-
2808-from pastebin import interfaces
2809-from pastebin import pasting
2810-
2811-
2812-class Record(object):
2813-
2814- def __init__(self, oid, author, time):
2815- self.oid = oid
2816- self.author = author
2817- self.time = time
2818- self.version = 0
2819-
2820-
2821-class FSPasteBinService(service.Service):
2822-
2823- implements(interfaces.IPasteBin)
2824-
2825- def __init__(self, storageDir):
2826- self._dir = storageDir
2827-
2828- def getListOfPastings(self, limit=None):
2829- if limit is None:
2830- limited = self._index
2831- else:
2832- limited = self._index[0:limit]
2833- return [(r.oid, r.author, r.time) for r in limited]
2834-
2835- def _makeFilename(self, name):
2836- return os.path.join(self._dir, name)
2837-
2838- def _loadPastingData(self, oid):
2839- f = file(self._makeFilename(str(oid)), 'rb')
2840- return pickle.load(f)
2841-
2842- def _savePastingData(self, oid, data):
2843- f = file(self._makeFilename(str(oid)), 'wb')
2844- pickle.dump(data, f, pickle.HIGHEST_PROTOCOL)
2845-
2846- def getPasting(self, oid):
2847- data = self._loadPastingData(oid)
2848- return Pasting(data)
2849-
2850- def addPasting(self, author, text):
2851- oid = self._nextOid
2852- now = time.gmtime()
2853- data = [{'author':author, 'time':now, 'text':text}]
2854- self._savePastingData(oid, data)
2855- self._index.insert(0, Record(oid, author, now))
2856- self._nextOid += 1
2857- return oid
2858-
2859- def updatePasting(self, oid, author, text):
2860- now = time.gmtime()
2861- data = self._loadPastingData(oid)
2862- data.append({'author':author, 'time':now, 'text':text})
2863- self._savePastingData(oid, data)
2864- for i, r in enumerate(self._index):
2865- if r.oid == oid:
2866- r.time = now
2867- self._index.insert(0,self._index.pop(i))
2868-
2869- def startService(self):
2870- log.msg('Loading index')
2871- try:
2872- f = file(self._makeFilename('index'), 'rb')
2873- d = pickle.load(f)
2874- self._index = d['index']
2875- self._nextOid = d['nextOid']
2876- except IOError:
2877- self._index = []
2878- self._nextOid = 1
2879-
2880- def stopService(self):
2881- log.msg('Storing index')
2882- d = {'index':self._index, 'nextOid':self._nextOid}
2883- f = file(self._makeFilename('index'), 'wb')
2884- pickle.dump(d, f, pickle.HIGHEST_PROTOCOL)
2885-
2886-class Pasting(object):
2887-
2888- implements(pasting.IPasting)
2889-
2890- def __init__(self, data):
2891- self._data = data
2892-
2893- def getLatestVersion(self):
2894- return self.getVersion(-1)
2895-
2896- def getVersion(self, version):
2897- return Version(self._data[version])
2898-
2899- def getHistory(self):
2900- history = [(i,d['author'],d['time']) for i,d in enumerate(self._data)]
2901- history.reverse()
2902- return history
2903-
2904-
2905-class Version:
2906-
2907- implements(pasting.IVersion)
2908-
2909- def __init__(self, data):
2910- self._data = data
2911-
2912- def getAuthor(self):
2913- return self._data['author']
2914-
2915- def getText(self):
2916- return self._data['text']
2917-
2918- def getTime(self):
2919- return self._data['time']
2920
2921=== removed directory 'Nevow/examples/pastebin/pastebin/web'
2922=== removed file 'Nevow/examples/pastebin/pastebin/web/__init__.py'
2923=== removed file 'Nevow/examples/pastebin/pastebin/web/pages.py'
2924--- Nevow/examples/pastebin/pastebin/web/pages.py 2006-04-14 17:23:46 +0000
2925+++ Nevow/examples/pastebin/pastebin/web/pages.py 1970-01-01 00:00:00 +0000
2926@@ -1,212 +0,0 @@
2927-from cStringIO import StringIO
2928-import time
2929-from zope.interface import implements
2930-
2931-from twisted.python import htmlizer
2932-from twisted.web import static
2933-
2934-from nevow import loaders
2935-from nevow import rend
2936-from nevow import tags
2937-from nevow import url
2938-
2939-from formless import annotate
2940-from formless import iformless
2941-from formless import webform
2942-
2943-ANONYMOUS = 'anonymous'
2944-
2945-
2946-##
2947-# Text colourisers (aka syntax highlighting)
2948-##
2949-
2950-def _python_colouriser(text):
2951- out = StringIO()
2952- try:
2953- htmlizer.filter(StringIO(text), out)
2954- except AttributeError:
2955- out = StringIO("""Starting after Nevow 0.4.1 Twisted
2956-2.0 is a required dependency. Please install it""")
2957- return out.getvalue()
2958-
2959-_colourisers = {
2960- 'python': _python_colouriser
2961- }
2962-
2963-
2964-##
2965-# Formless
2966-##
2967-
2968-class IAddPasting(annotate.TypedInterface):
2969- def addPasting(
2970- request=annotate.Request(),
2971- author=annotate.String(strip=True),
2972- text=annotate.Text(strip=True, required=True)):
2973- pass
2974- addPasting = annotate.autocallable(addPasting)
2975-
2976-
2977-class IEditPasting(annotate.TypedInterface):
2978- def editPasting(
2979- request=annotate.Request(),
2980- postedBy=annotate.String(immutable=1),
2981- author=annotate.String(strip=True),
2982- text=annotate.Text(strip=True, required=True)):
2983- pass
2984- editPasting = annotate.autocallable(editPasting)
2985-
2986-
2987-##
2988-# "Standard" renderers
2989-##
2990-
2991-def render_time(theTime):
2992- def _(context, data):
2993- return time.strftime('%Y-%m-%d %H:%M:%S %Z', theTime)
2994- return _
2995-
2996-def render_pastingText(text):
2997- def _(context, data):
2998- colouriser = _colourisers.get('python')
2999- if colouriser:
3000- return tags.xml(colouriser(text))
3001- return tags.pre[tags.xml(text)]
3002- return _
3003-
3004-def render_pasting(version):
3005- def _(context, data):
3006- context.fillSlots('author', version.getAuthor() or ANONYMOUS)
3007- time = context.fillSlots('time', render_time(version.getTime()))
3008- text = context.fillSlots('text', render_pastingText(version.getText()))
3009- return context.tag
3010- return _
3011-
3012-
3013-class BasePage(rend.Page):
3014-
3015- docFactory = loaders.htmlfile(templateDir='templates', template='site.html')
3016-
3017- child_css = static.File('static/css')
3018- child_images = static.File('static/images')
3019-
3020- def data_pastings(self, context, data):
3021- return self.pastebin.getListOfPastings(20)
3022-
3023- def render_pasting(self, context, data):
3024- oid, author, time = data
3025- context.tag.fillSlots('url', url.root.child(str(oid)))
3026- context.tag.fillSlots('id', oid)
3027- context.tag.fillSlots('author', author or ANONYMOUS)
3028- return context.tag
3029-
3030- def render_content(self, context, data):
3031- tag = context.tag.clear()
3032- tag[loaders.htmlfile(templateDir='templates', template=self.contentTemplateFile)]
3033- return tag
3034-
3035-
3036-class RootPage(BasePage):
3037- implements(IAddPasting)
3038-
3039- addSlash = True
3040-
3041- def __init__(self, pastebin):
3042- BasePage.__init__(self)
3043- self.pastebin = pastebin
3044-
3045- def locateChild(self, context, segments):
3046- try:
3047- return Pasting(self.pastebin, int(segments[0])), segments[1:]
3048- except ValueError:
3049- pass
3050- return BasePage.locateChild(self, context, segments)
3051-
3052- def render_content(self, context, data):
3053- tag = context.tag.clear()
3054- return tag[webform.renderForms()]
3055-
3056- def addPasting(self, request, author, text):
3057- oid = self.pastebin.addPasting(author, text)
3058- request.setComponent(iformless.IRedirectAfterPost, '/'+str(oid))
3059-
3060-
3061-class Pasting(BasePage):
3062-
3063- implements(IEditPasting)
3064- contentTemplateFile = 'pasting.html'
3065-
3066- def __init__(self, pastebin, pastingOid, version=-1):
3067- BasePage.__init__(self)
3068- self.pastebin = pastebin
3069- self.pastingOid = pastingOid
3070- self.version = version
3071- self.pasting = self.pastebin.getPasting(self.pastingOid)
3072-
3073- def locateChild(self, context, segments):
3074- try:
3075- return Pasting(self.pastebin, self.pastingOid, int(segments[0])), segments[1:]
3076- except:
3077- pass
3078- return BasePage.locateChild(self, context, segments)
3079-
3080- def data_history(self, context, data):
3081- return self.pasting.getHistory()
3082-
3083- def render_aPasting(self, context, data):
3084- return render_pasting(self.pasting.getVersion(self.version))
3085-
3086- def render_form(self, context, data):
3087- if self.version != -1:
3088- return ''
3089- version = self.pasting.getVersion(self.version)
3090- formDefaults = context.locate(iformless.IFormDefaults)
3091- formDefaults.setDefault('editPasting.text', version.getText())
3092- formDefaults.setDefault('editPasting.postedBy', version.getAuthor())
3093- return webform.renderForms()
3094-
3095- def render_version(self, context, data):
3096- version, author, theTime = data
3097- if self.version == -1:
3098- u = url.here.child
3099- else:
3100- u = url.here.sibling
3101- context.tag.fillSlots('url', u(version))
3102- context.tag.fillSlots('time', render_time(theTime))
3103- context.tag.fillSlots('author', author or ANONYMOUS)
3104-## context.fillSlots('link', a(href=[u(version)])[
3105-## render_time(theTime), ' (',author or ANONYMOUS,')'
3106-## ])
3107- return context.tag
3108-
3109- def editPasting(self, request, postedBy, author, text):
3110- self.pastebin.updatePasting(self.pastingOid, author, text)
3111- request.setComponent(iformless.IRedirectAfterPost, '/%s'%self.pastingOid)
3112-
3113-
3114-class Version(BasePage):
3115-
3116- contentTemplateFile = "pasting.html"
3117-
3118- child_ = rend.FourOhFour()
3119-
3120- def __init__(self, pastebin, pasting, version):
3121- BasePage.__init__(self)
3122- self.pastebin = pastebin
3123- self.pasting = pasting
3124- self.version = version
3125-
3126- def data_history(self, context, data):
3127- return self.pasting.getHistory()
3128-
3129- def render_aPasting(self, context, data):
3130- return render_pasting(self.pasting.getVersion(self.version))
3131-
3132- def render_version(self, context, data):
3133- version, author, theTime = data
3134- context.fillSlots('link', tags.a(href=[url.here.sibling(str(version))])[
3135- render_time(theTime), ' (',author,')'
3136- ])
3137- return context.tag
3138-
3139
3140=== removed directory 'Nevow/examples/pastebin/static'
3141=== removed directory 'Nevow/examples/pastebin/static/css'
3142=== removed file 'Nevow/examples/pastebin/static/css/default.css'
3143--- Nevow/examples/pastebin/static/css/default.css 2005-10-14 17:36:24 +0000
3144+++ Nevow/examples/pastebin/static/css/default.css 1970-01-01 00:00:00 +0000
3145@@ -1,100 +0,0 @@
3146-body
3147-{
3148- margin: 0;
3149- padding: 1em 1em;
3150- color: #330033;
3151- font-size: 10pt;
3152-}
3153-
3154-a
3155-{
3156- color: inherit;
3157-}
3158-
3159-a:visited
3160-{
3161- color: #996699;
3162-}
3163-
3164-#header
3165-{
3166- border-bottom: 1px solid #cccc99;
3167-}
3168-
3169-#header h1
3170-{
3171- padding: 0;
3172- margin: 0;
3173- color: #cccc66;
3174-}
3175-
3176-#footer
3177-{
3178- padding: 0.1em 0.5em;
3179- margin-top: 1em;
3180- clear: both;
3181- border-top: 1px solid #cccc99;
3182- font-size: 77%;
3183- color: #666699;
3184-}
3185-
3186-#content-container
3187-{
3188- margin: 2em 0.5em;
3189-}
3190-
3191-#nav
3192-{
3193- position: relative;
3194- float: left;
3195- width: 10em;
3196-}
3197-
3198-#menu, #pastings
3199-{
3200- list-style: url(/images/pasting.gif);
3201- padding: 0 0 0 18px;
3202- margin-top: 0;
3203-}
3204-
3205-#content
3206-{
3207- margin-left: 10em;
3208-}
3209-
3210-div.pastingText
3211-{
3212- padding: 0.5em;
3213- background-color: #fafafa;
3214- color: #333;
3215- border: 1px solid #ccc;
3216- overflow: auto;
3217-}
3218-
3219-div.pastingText pre
3220-{
3221- margin: 0;
3222-}
3223-
3224-.revision-history
3225-{
3226- font-size: 86%;
3227-}
3228-
3229-.view-menu
3230-{
3231- list-style: none;
3232- margin: 1em 0;
3233- padding: 0;
3234-}
3235-
3236-.view-menu li
3237-{
3238- display: inline;
3239- margin-right: 1em;
3240-}
3241-
3242-.view-menu li a
3243-{
3244- color: inherit;
3245-}
3246
3247=== removed file 'Nevow/examples/pastebin/static/css/freeform.css'
3248--- Nevow/examples/pastebin/static/css/freeform.css 2005-10-14 17:36:24 +0000
3249+++ Nevow/examples/pastebin/static/css/freeform.css 1970-01-01 00:00:00 +0000
3250@@ -1,27 +0,0 @@
3251-
3252-.freeform-typed { clear: both; }
3253-.freeform-property-binding { clear: both; border: 1px solid blue; padding: 0.5em; width: auto }
3254-.freeform-method-binding { clear: both; border: 1px solid black; padding: 0.5em; width: auto }
3255-.freeform-argument-binding { clear: both; border: 1px solid blue; padding: 0.5em; width: auto }
3256-.freeform-binding-content { border-top: 1px dashed #bdedfe; margin-top: 0.5em; padding-top: 0.5em }
3257-.freeform-label { float: left; width: 200px; }
3258-.freeform-input { float: left; width: 200px; }
3259-.freeform-error { color: red; }
3260-.freeform-description { clear: both; border-bottom: 1px dashed #bdedfe; margin-bottom: 0.5em; padding-bottom: 0.5em }
3261-.freeform-list-item { clear: both; width: auto }
3262-.freeform-form-label { color: #666666 }
3263-
3264-.freeform-textarea { width: 5in; height: 3in }
3265-
3266-.freeform-success { padding: 0.5em; border: 1px dashed green; }
3267-.freeform-failure { padding: 0.5em; color: red; border: 1px dashed red; }
3268-
3269-.freeform-list { border: 1px dashed #cdcdcd; }
3270-.freeform-dictionary { border: 1px dashed #dedede; }
3271-.freeform-action-group { margin: 0px }
3272-.freeform-action { color: green }
3273-.freeform-action-selection { background-color: red; height: 1em; width: 1em; }
3274-
3275-.freeform-group-binding { border: 1px dashed #efabab }
3276-.freeform-grouped-property-binding {}
3277-.freeform-grouped-method-binding {}
3278
3279=== removed file 'Nevow/examples/pastebin/static/css/python.css'
3280--- Nevow/examples/pastebin/static/css/python.css 2005-10-14 17:36:24 +0000
3281+++ Nevow/examples/pastebin/static/css/python.css 1970-01-01 00:00:00 +0000
3282@@ -1,32 +0,0 @@
3283-.py-src-comment
3284-{
3285- color: #1111CC
3286-}
3287-
3288-.py-src-keyword
3289-{
3290- color: #3333CC;
3291- font-weight: bold;
3292-}
3293-
3294-.py-src-parameter
3295-{
3296- color: #000066;
3297- font-weight: bold;
3298-}
3299-
3300-.py-src-identifier
3301-{
3302- color: #CC0000
3303-}
3304-
3305-.py-src-string
3306-{
3307-
3308- color: #115511
3309-}
3310-
3311-.py-src-endmarker
3312-{
3313- display: block; /* IE hack; prevents following line from being sucked into the py-listing box. */
3314-}
3315
3316=== removed file 'Nevow/examples/pastebin/static/css/standard.css'
3317--- Nevow/examples/pastebin/static/css/standard.css 2005-10-14 17:36:24 +0000
3318+++ Nevow/examples/pastebin/static/css/standard.css 1970-01-01 00:00:00 +0000
3319@@ -1,25 +0,0 @@
3320-body
3321-{
3322- font-family: Verdana, Geneva, "Bitstream Vera Sans", Helvetica;
3323- /* font-family: Georgia, "Bitstream Vera Serif", "New York", Palatino; */
3324- font-size: 103%;
3325-}
3326-
3327-th, td /* Needed for NN4 as its tables do not inherit styles */
3328-{
3329- font-family: Verdana, Geneva, "Bitstream Vera Sans", Helvetica;
3330- /* font-family: Georgia, "Bitstream Vera Serif", "New York", Palatino; */
3331- font-size: 103%;
3332-}
3333-
3334-/* Headers */
3335-h1 { font-size: 160%; }
3336-h2 { font-size: 130%; }
3337-h3 { font-size: 116%; }
3338-
3339-
3340-/* Standard sizes */
3341-.normal-size { font-size: 103%; }
3342-.small { font-size: 88%; }
3343-.smaller { font-size: 77%; }
3344-.smallest { font-size: 68%; }
3345
3346=== removed directory 'Nevow/examples/pastebin/static/images'
3347=== removed file 'Nevow/examples/pastebin/static/images/pasting.gif'
3348Binary files Nevow/examples/pastebin/static/images/pasting.gif 2005-10-14 17:36:24 +0000 and Nevow/examples/pastebin/static/images/pasting.gif 1970-01-01 00:00:00 +0000 differ
3349=== removed file 'Nevow/examples/pastebin/static/robots.txt'
3350--- Nevow/examples/pastebin/static/robots.txt 2005-10-14 17:36:24 +0000
3351+++ Nevow/examples/pastebin/static/robots.txt 1970-01-01 00:00:00 +0000
3352@@ -1,2 +0,0 @@
3353-User-agent: *
3354-Disallow: /
3355
3356=== removed directory 'Nevow/examples/pastebin/templates'
3357=== removed file 'Nevow/examples/pastebin/templates/pasting.html'
3358--- Nevow/examples/pastebin/templates/pasting.html 2005-10-14 17:36:24 +0000
3359+++ Nevow/examples/pastebin/templates/pasting.html 1970-01-01 00:00:00 +0000
3360@@ -1,14 +0,0 @@
3361-<div nevow:render="aPasting">
3362-
3363- <p>Pasted by <nevow:slot name="author">author</nevow:slot> at <nevow:slot name="time">time</nevow:slot>.</p>
3364- <div class="pastingText"><nevow:slot name="text">Pasting goes here</nevow:slot></div>
3365- <div class="revision-history">
3366- <p>Revision history:</p>
3367- <ul nevow:render="sequence" nevow:data="history">
3368- <li nevow:pattern="item" nevow:render="version"><a href=""><nevow:attr name="href"><nevow:slot name="url"/></nevow:attr><nevow:slot name="time"/> (<nevow:slot name="author"/>)</a></li>
3369- </ul>
3370- </div>
3371-
3372- <form nevow:render="form"/>
3373-
3374-</div>
3375
3376=== removed file 'Nevow/examples/pastebin/templates/site.html'
3377--- Nevow/examples/pastebin/templates/site.html 2005-10-14 17:36:24 +0000
3378+++ Nevow/examples/pastebin/templates/site.html 1970-01-01 00:00:00 +0000
3379@@ -1,50 +0,0 @@
3380-<?xml version="1.0"?>
3381-
3382-<html xmlns="http://www.w3.org/1999/xhtml">
3383-
3384- <head>
3385- <title>Twisted Pastebin</title>
3386- <link rel="stylesheet" type="text/css" href="/css/standard.css"/>
3387- <link rel="stylesheet" type="text/css" href="/css/default.css"/>
3388- <link rel="stylesheet" type="text/css" href="/css/freeform.css"/>
3389- <link rel="stylesheet" type="text/css" href="/css/python.css"/>
3390- </head>
3391-
3392- <body>
3393-
3394- <div id="header">
3395- <h1>Twisted Pastebin</h1>
3396- </div>
3397-
3398- <div id="content-container">
3399-
3400- <div id="nav">
3401-
3402- Menu:
3403- <ul id="menu">
3404- <li><a href="/">Add pasting</a></li>
3405- </ul>
3406-
3407- Recent pastings:
3408- <ul id="pastings" nevow:data="pastings" nevow:render="sequence">
3409- <li nevow:pattern="empty"><em>none</em></li>
3410- <li nevow:pattern="item" nevow:render="pasting">
3411- <a href="#"><nevow:attr name="href"><nevow:slot name="url"/></nevow:attr><nevow:slot name="id" /> (<nevow:slot name="author"/>)</a>
3412- </li>
3413- </ul>
3414-
3415- </div>
3416-
3417- <div id="content" nevow:render="content">
3418- </div>
3419-
3420- </div>
3421-
3422- <div id="footer">
3423- Powered by <a href="http://www.twistedmatrix.com/">Twisted</a> and
3424- <a href="http://divmod.org/users/wiki.twistd/nevow/moin.cgi">Nevow</a>.
3425- </div>
3426-
3427- </body>
3428-
3429-</html>
3430
3431=== removed file 'Nevow/examples/tests/testformless.py'
3432--- Nevow/examples/tests/testformless.py 2006-04-14 17:23:46 +0000
3433+++ Nevow/examples/tests/testformless.py 1970-01-01 00:00:00 +0000
3434@@ -1,105 +0,0 @@
3435-
3436-from twisted.internet import defer
3437-
3438-from formless import annotate, webform
3439-
3440-from nevow import rend, loaders, tags, livetest, url, livepage
3441-
3442-
3443-"""WWWWizard functionality!
3444-"""
3445-
3446-
3447-test_suite = [
3448- ('visit', '/formpost/', ''),
3449- ('value', 'foo-foo', '5'),
3450- ('post', 'foo', {'foo-foo': 'asdf'}),
3451- ('assert', livetest.xpath('//form[@id="foo"]//div[@class="freeform-form-error"]'), "'asdf' is not an integer."),
3452- ## Check to make sure we repopulate the user's input with the erronious input
3453- ('value', 'foo-foo', 'asdf'),
3454- ('post', 'foo', {'foo-foo': '10'}),
3455- ('value', 'foo-foo', '10'),
3456- ]
3457-
3458-
3459-test_suite += [
3460- ('visit', '/formpost2/', ''),
3461- ('post', 'bar', {'bar-baz': '5', 'bar-slam': '5', 'bar-ham': 'efgh', 'bar-custom': '1'}),
3462- ## XXX TODO: Can't post a radio button, so there is "None" below
3463- ('assert', livetest.xpath('//h3'), "You called bar! 5 5 efgh None {'stuff': 1234, 'name': 'One'}")
3464-]
3465-
3466-test_suite += [
3467- ('visit', '/testformless', ''),
3468- ('post', 'name', {'name-name': 'Fred'}),
3469- ('post', 'quest', {'quest-quest': 'Find the Grail'}),
3470- ('post', 'speed', {'speed-speed': '123'}),
3471- ('assert', 'body', "Thanks for taking our survey! You said: 'Fred' 'Find the Grail' 123")]
3472-
3473-
3474-class NameWizard(rend.Page):
3475- docFactory = loaders.stan(tags.html[tags.h1["What is your name"], webform.renderForms()])
3476-
3477- def bind_name(self, ctx):
3478- return [('name', annotate.String())]
3479-
3480- def name(self, name):
3481- return QuestWizard(name)
3482-
3483-
3484-class QuestWizard(rend.Page):
3485- docFactory = loaders.stan(tags.html[tags.h1["What is your quest"], webform.renderForms()])
3486-
3487- def bind_quest(self, ctx):
3488- return [('quest', annotate.Choice(['Find the Grail', 'Get laid', 'Earn twenty bucks', 'Destroy the sun']))]
3489-
3490- def quest(self, quest):
3491- return FinalWizard((self.original, quest))
3492-
3493-
3494-class FinalWizard(rend.Page):
3495- docFactory = loaders.stan(tags.html[tags.h1["What is the airspeed velocity of an unladen swallow"], webform.renderForms()])
3496-
3497- def bind_speed(self, ctx):
3498- return [('speed', annotate.Integer())]
3499-
3500- def speed(self, speed):
3501- return rend.Page(
3502- docFactory=loaders.stan(
3503- tags.html[
3504- tags.body(id='body')[
3505- "Thanks for taking our survey! You said: %r %r %r" % (
3506- self.original[0], self.original[1], speed)]]))
3507-
3508-
3509-def checkLocation(client):
3510- d = defer.Deferred()
3511- def gotResult(ctx, location):
3512- from urlparse import urlparse
3513- if urlparse(location)[2] == '/':
3514- d.callback(None)
3515- else:
3516- d.errback(None)
3517- client.send(client.transient(gotResult, livepage.js.testFrameNode.contentDocument.location))
3518- return d
3519-
3520-
3521-test_suite += [
3522- ('visit', '/formless_redirector', ''),
3523- ('post', 'goHome', {}),
3524- ('call', checkLocation, ())]
3525-
3526-
3527-class Redirector(rend.Page):
3528- docFactory = loaders.stan(tags.html[tags.body[webform.renderForms()]])
3529-
3530- def bind_goHome(self, ctx):
3531- return []
3532-
3533- def goHome(self):
3534- return url.root
3535-
3536-
3537-formless_tests = livetest.Tester(test_suite)
3538-
3539-
3540
3541=== removed directory 'Nevow/examples/todo'
3542=== removed file 'Nevow/examples/todo/controller.py'
3543--- Nevow/examples/todo/controller.py 2006-03-17 15:00:39 +0000
3544+++ Nevow/examples/todo/controller.py 1970-01-01 00:00:00 +0000
3545@@ -1,83 +0,0 @@
3546-from zope.interface import implements
3547-
3548-from nevow import rend, loaders, tags as t
3549-from formless import annotate, webform
3550-from time import time as now
3551-import itodo
3552-
3553-class ITodo(annotate.TypedInterface):
3554- def insert(ctx=annotate.Context(),
3555- description=annotate.String(required=True,
3556- requiredFailMessage="Description Missing")
3557- ):
3558- pass
3559- insert = annotate.autocallable(insert, action="New Todo")
3560- def delete(ctx=annotate.Context(), id=annotate.Integer()):
3561- pass
3562- delete = annotate.autocallable(delete, invisible=True)
3563- def update(ctx=annotate.Context(),
3564- id=annotate.Integer(),
3565- oldstate=annotate.Integer()):
3566- pass
3567- update = annotate.autocallable(update, invisible=True)
3568-
3569-class Root(rend.Page):
3570- implements(ITodo)
3571-
3572- child_css = webform.defaultCSS
3573-
3574- docFactory = loaders.stan(
3575- t.html(render=t.directive("time"))[
3576- t.head[
3577- t.title['todo'],
3578- t.style(type="text/css")[".done { color: #dddddd; }"],
3579- t.style(type="text/css")["@import url(/css);"]
3580- ],
3581- t.body[
3582- webform.renderForms(),
3583- t.ul(data=t.directive("findAll"),
3584- render=t.directive("sequence"))[
3585- t.li(pattern="item",render=t.directive('todo')),
3586- t.li(pattern="empty",render=t.directive('empty')),
3587- ],
3588- t.p(render=t.directive("end"))
3589- ]
3590- ]
3591- )
3592-
3593- def insert(self, ctx, description):
3594- return itodo.ITodos(ctx).add(description, 0)
3595-
3596- def delete(self, ctx, id):
3597- return itodo.ITodos(ctx).delete(id)
3598-
3599- def update(self, ctx, id, oldstate):
3600- newstate = [1, 0][oldstate]
3601- return itodo.ITodos(ctx).update(id, newstate)
3602-
3603- def data_findAll(self, ctx, data):
3604- return itodo.ITodos(ctx).findAll()
3605-
3606- def render_todo(self, ctx, data):
3607- deluri = "freeform_post!!delete?id="+str(data[0])
3608- updateuri = "freeform_post!!update?id="+str(data[0])+"&oldstate="+str(data[2])
3609- state = [" Done", " To Do"][int(data[2])==0]
3610- tag = ctx.tag
3611- if data[2]:
3612- tag = ctx.tag(_class="done")
3613- return tag[data[1]+" - ",
3614- t.a(href=deluri)["Delete"], " / ",
3615- t.a(href=updateuri)[("Mark Done", "Mark Undone")[data[2]]],
3616- state]
3617-
3618- def render_empty(self, ctx, data):
3619- return ctx.tag["No Todos"]
3620-
3621- def render_time(self, ctx, data):
3622- ctx.remember(now(), itodo.ITimer)
3623- return ctx.tag
3624-
3625- def render_end(self, ctx, data):
3626- return ctx.tag["%.3f"%(now()-itodo.ITimer(ctx))]
3627-
3628-root = Root()
3629
3630=== removed file 'Nevow/examples/todo/database.sql'
3631--- Nevow/examples/todo/database.sql 2005-10-14 17:36:24 +0000
3632+++ Nevow/examples/todo/database.sql 1970-01-01 00:00:00 +0000
3633@@ -1,5 +0,0 @@
3634-CREATE TABLE todos (
3635- id serial primary key,
3636- description varchar(100) not null,
3637- done int not null
3638-)
3639\ No newline at end of file
3640
3641=== removed file 'Nevow/examples/todo/dispatcher.py'
3642--- Nevow/examples/todo/dispatcher.py 2005-10-14 17:36:24 +0000
3643+++ Nevow/examples/todo/dispatcher.py 1970-01-01 00:00:00 +0000
3644@@ -1,13 +0,0 @@
3645-from nevow import rend
3646-import itodo
3647-import controller
3648-
3649-# All this is only useful to dynamically update the web page code
3650-# without restarting the server each time. As you can see below, you can
3651-# disable this by putting a false value in the Env object.
3652-
3653-class Dispatch(rend.Page):
3654- def locateChild(self, ctx, segments):
3655- if itodo.IEnv(ctx).development:
3656- reload(controller)
3657- return controller.root.locateChild(ctx,segments)
3658
3659=== removed file 'Nevow/examples/todo/environment.py'
3660--- Nevow/examples/todo/environment.py 2005-10-14 17:36:24 +0000
3661+++ Nevow/examples/todo/environment.py 1970-01-01 00:00:00 +0000
3662@@ -1,8 +0,0 @@
3663-class Env(object):
3664- user='test'
3665- password='test'
3666- port=5432
3667- host='localhost'
3668- dbname='todo'
3669- development=False
3670-env = Env()
3671
3672=== removed file 'Nevow/examples/todo/itodo.py'
3673--- Nevow/examples/todo/itodo.py 2006-03-08 14:28:41 +0000
3674+++ Nevow/examples/todo/itodo.py 1970-01-01 00:00:00 +0000
3675@@ -1,16 +0,0 @@
3676-from zope.interface import Interface
3677-
3678-class ITimer(Interface):
3679- """ """
3680-
3681-class IEnv(Interface):
3682- """ """
3683-
3684-class ITodos(Interface):
3685- """ """
3686- def add(description, done):
3687- pass
3688- def delete(id):
3689- pass
3690- def edit(id, description, done):
3691- pass
3692
3693=== removed file 'Nevow/examples/todo/store.py'
3694--- Nevow/examples/todo/store.py 2005-10-14 17:36:24 +0000
3695+++ Nevow/examples/todo/store.py 1970-01-01 00:00:00 +0000
3696@@ -1,29 +0,0 @@
3697-from zope.interface import implements
3698-import pgasync
3699-import itodo
3700-
3701-class Todos(object):
3702- implements(itodo.ITodos)
3703- def __init__(self, dbname, user, password, host):
3704- self.original = pgasync.ConnectionPool("pgasync", dbname=dbname,
3705- user=user, password=password, host=host)
3706-
3707- def add(self, description, done):
3708- query = "INSERT INTO todos (description, done) VALUES (%(description)s,%(done)s)"
3709- args = dict(description=description, done=done)
3710- return self.original.runOperation(query, args)
3711-
3712- def delete(self, id):
3713- query="DELETE FROM todos WHERE id=%(id)s"
3714- args = dict(id=id)
3715- return self.original.runOperation(query, args)
3716-
3717- def update(self, id, state):
3718- query = "UPDATE todos SET done=%(done)s WHERE id=%(id)s"
3719- args = dict(id=id, done=state)
3720- return self.original.runOperation(query, args)
3721-
3722- def findAll(self):
3723- query = "SELECT * FROM todos"
3724- return self.original.runQuery(query)
3725-
3726
3727=== removed file 'Nevow/examples/todo/todo.tac'
3728--- Nevow/examples/todo/todo.tac 2005-10-14 17:36:24 +0000
3729+++ Nevow/examples/todo/todo.tac 1970-01-01 00:00:00 +0000
3730@@ -1,18 +0,0 @@
3731-from twisted.application import service, strports
3732-from nevow import appserver
3733-
3734-from environment import env as e
3735-import store
3736-import dispatcher
3737-import itodo
3738-
3739-application = service.Application('todo')
3740-db = store.Todos(e.dbname, e.user, e.password, e.host)
3741-disp = dispatcher.Dispatch()
3742-
3743-site = appserver.NevowSite(resource=disp)
3744-site.remember(db, itodo.ITodos)
3745-site.remember(e, itodo.IEnv)
3746-
3747-webserver = strports.service("tcp:8080", site)
3748-webserver.setServiceParent(application)
3749
3750=== removed directory 'Nevow/examples/tree'
3751=== removed file 'Nevow/examples/tree/__init__.py'
3752=== removed file 'Nevow/examples/tree/tree.py'
3753--- Nevow/examples/tree/tree.py 2006-03-17 15:00:39 +0000
3754+++ Nevow/examples/tree/tree.py 1970-01-01 00:00:00 +0000
3755@@ -1,73 +0,0 @@
3756-from zope.interface import implements
3757-
3758-from twisted.python.components import registerAdapter
3759-
3760-from nevow import loaders, rend, inevow, tags as T
3761-from formless import annotate, webform
3762-
3763-class Tree(dict):
3764- def __init__(self, name, description, *children):
3765- self.name = name
3766- self.description = description
3767- for child in children:
3768- self.add(child)
3769- def add(self, child):
3770- self[child.name] = child
3771- def __nonzero__(self):
3772- return True
3773-
3774-class ITreeEdit(annotate.TypedInterface):
3775- def setDescription(description=annotate.String()):
3776- pass
3777- setDescription = annotate.autocallable(setDescription)
3778- def deleteChild(name=annotate.String(required=True)):
3779- pass
3780- deleteChild = annotate.autocallable(deleteChild, invisible=True)
3781- def addChild(name=annotate.String(required=True),
3782- description=annotate.String()):
3783- pass
3784- addChild = annotate.autocallable(addChild)
3785-
3786-class TreeRenderer(rend.Page):
3787- implements(ITreeEdit)
3788- addSlash = True
3789- docFactory = loaders.htmlstr("""
3790-<html>
3791-<head><title>Tree Editor</title></head>
3792-<body><h1><span nevow:data="description"
3793- nevow:render="string">Tree Description</span></h1>
3794-<span nevow:render="descriptionForm"/>
3795-<ol nevow:data="children" nevow:render="sequence">
3796-<li nevow:pattern="item"><span nevow:render="childLink"/>
3797-<span nevow:render="childDel"/>
3798-</li>
3799-</ol>
3800-<a href="..">Up</a>
3801-</body>
3802-</html>
3803- """)
3804- def setDescription(self, description):
3805- self.original.description = description
3806- def addChild(self, name, description):
3807- self.original.add(Tree(name, description))
3808- def deleteChild(self, name):
3809- del self.original[name]
3810- def data_description(self, context, data):
3811- return self.original.description
3812- def data_children(self, context, data):
3813- return self.original.items()
3814- def render_childLink(self, context, data):
3815- return T.a(href='subtree_%s/'%data[0])[data[1].description]
3816- def childFactory(self, ctx, name):
3817- if name.startswith('subtree_'):
3818- return self.original[name[len('subtree_'):]]
3819- def render_descriptionForm(self, context, data):
3820- return webform.renderForms()
3821- def render_childDel(self, context, (name, _)):
3822- ret = T.form(action="./freeform_post!!deleteChild",
3823- enctype="multipart/form-data", method="POST")[
3824- T.input(type="hidden", name="name", value=name),
3825- T.input(type="submit", value="Delete")]
3826- return ret
3827-
3828-registerAdapter(TreeRenderer, Tree, inevow.IResource)
3829
3830=== removed directory 'Nevow/formless'
3831=== removed file 'Nevow/formless/__init__.py'
3832--- Nevow/formless/__init__.py 2005-10-14 17:36:24 +0000
3833+++ Nevow/formless/__init__.py 1970-01-01 00:00:00 +0000
3834@@ -1,10 +0,0 @@
3835-# Copyright (c) 2004 Divmod.
3836-# See LICENSE for details.
3837-
3838-# FIXME: remove next two lines after fixing compyCompat to have lazy importing.
3839-# or else moving formless' adapter registration here.
3840-import nevow
3841-del nevow
3842-
3843-from formless.annotate import *
3844-from formless.processors import process
3845
3846=== removed file 'Nevow/formless/annotate.py'
3847--- Nevow/formless/annotate.py 2010-02-06 04:33:05 +0000
3848+++ Nevow/formless/annotate.py 1970-01-01 00:00:00 +0000
3849@@ -1,852 +0,0 @@
3850-# -*- test-case-name: formless.test -*-
3851-# Copyright (c) 2004 Divmod.
3852-# See LICENSE for details.
3853-
3854-
3855-"""And the earth was without form, and void; and darkness was upon the face of the deep.
3856-"""
3857-
3858-import os
3859-import sys
3860-import inspect
3861-import warnings
3862-from zope.interface import implements
3863-from zope.interface.interface import InterfaceClass, Attribute
3864-
3865-from nevow import util
3866-
3867-
3868-from formless import iformless
3869-
3870-
3871-class count(object):
3872- def __init__(self):
3873- self.id = 0
3874- def next(self):
3875- self.id += 1
3876- return self.id
3877-
3878-nextId = count().next
3879-
3880-
3881-class InputError(Exception):
3882- """A Typed instance was unable to coerce from a string to the
3883- appropriate type.
3884- """
3885- def __init__(self, reason):
3886- self.reason = reason
3887-
3888- def __str__(self):
3889- return self.reason
3890-
3891-
3892-class ValidateError(Exception):
3893- """A Binding instance was unable to coerce all it's arguments from a
3894- dictionary of lists of strings to the appropriate types.
3895-
3896- One use of this is to raise from an autocallable if an input is invalid.
3897- For example, a password is incorrect.
3898-
3899- errors must be a dictionary mapping argument names to error messages
3900- to display next to the arguments on the form.
3901-
3902- formErrorMessage is a string to display at the top of the form, not tied to
3903- any specific argument on the form.
3904-
3905- partialForm is a dict mapping argument name to argument value, allowing
3906- you to have the form save values that were already entered in the form.
3907- """
3908- def __init__(self, errors, formErrorMessage=None, partialForm=None):
3909- self.errors = errors
3910- self.formErrorMessage = formErrorMessage
3911- if partialForm is None:
3912- self.partialForm = {}
3913- else:
3914- self.partialForm = partialForm
3915-
3916- def __str__(self):
3917- return self.formErrorMessage
3918-
3919-
3920-
3921-class Typed(Attribute):
3922- """A typed value. Subclasses of Typed are constructed inside of
3923- TypedInterface class definitions to describe the types of properties,
3924- the parameter types to method calls, and method return types.
3925-
3926- @ivar label: The short label which will describe this
3927- parameter/proerties purpose to the user.
3928-
3929- @ivar description: A long description which further describes the
3930- sort of input the user is expected to provide.
3931-
3932- @ivar default: A default value that may be used as an initial
3933- value in the form.
3934-
3935- @ivar required: Whether the user is required to provide a value
3936-
3937- @ivar null: The value which will be produced if required is False
3938- and the user does not provide a value
3939-
3940- @ivar unicode: Iff true, try to determine the character encoding
3941- of the data from the browser and pass unicode strings to
3942- coerce.
3943- """
3944- implements(iformless.ITyped)
3945-
3946- complexType = False
3947- strip = False
3948- label = None
3949- description = None
3950- default = ''
3951- required = False
3952- requiredFailMessage = 'Please enter a value'
3953- null = None
3954- unicode = False
3955-
3956- __name__ = ''
3957-
3958- def __init__(
3959- self,
3960- label=None,
3961- description=None,
3962- default=None,
3963- required=None,
3964- requiredFailMessage=None,
3965- null=None,
3966- unicode=None,
3967- **attributes):
3968-
3969- self.id = nextId()
3970- if label is not None:
3971- self.label = label
3972- if description is not None:
3973- self.description = description
3974- if default is not None:
3975- self.default = default
3976- if required is not None:
3977- self.required = required
3978- if requiredFailMessage is not None:
3979- self.requiredFailMessage = requiredFailMessage
3980- if null is not None:
3981- self.null = null
3982- if unicode is not None:
3983- self.unicode = unicode
3984- self.attributes = attributes
3985-
3986- def getAttribute(self, name, default=None):
3987- return self.attributes.get(name, default)
3988-
3989- def coerce(self, val, configurable):
3990- raise NotImplementedError, "Implement in %s" % util.qual(self.__class__)
3991-
3992-
3993-#######################################
3994-## External API; your code will create instances of these objects
3995-#######################################
3996-
3997-class String(Typed):
3998- """A string that is expected to be reasonably short and contain no
3999- newlines or tabs.
4000-
4001- strip: remove leading and trailing whitespace.
4002- """
4003-
4004- requiredFailMessage = 'Please enter a string.'
4005- # iff true, return the stripped value.
4006- strip = False
4007-
4008- def __init__(self, *args, **kwargs):
4009- try:
4010- self.strip = kwargs['strip']
4011- del kwargs['strip']
4012- except KeyError:
4013- pass
4014- Typed.__init__(self, *args, **kwargs)
4015-
4016- def coerce(self, val, configurable):
4017- if self.strip:
4018- val = val.strip()
4019- return val
4020-
4021-
4022-class Text(String):
4023- """A string that is likely to be of a significant length and
4024- probably contain newlines and tabs.
4025- """
4026-
4027-
4028-class Password(String):
4029- """Password is used when asking a user for a new password. The renderer
4030- user interface will possibly ask for the password multiple times to
4031- ensure it has been entered correctly. Typical use would be for
4032- registration of a new user."""
4033- requiredFailMessage = 'Please enter a password.'
4034-
4035-
4036-class PasswordEntry(String):
4037- """PasswordEntry is used to ask for an existing password. Typical use
4038- would be for login to an existing account."""
4039- requiredFailMessage = 'Please enter a password.'
4040-
4041-
4042-class FileUpload(Typed):
4043- requiredFailMessage = 'Please enter a file name.'
4044-
4045- def coerce(self, val, configurable):
4046- return val.filename
4047-
4048-
4049-class Integer(Typed):
4050-
4051- requiredFailMessage = 'Please enter an integer.'
4052-
4053- def coerce(self, val, configurable):
4054- if val is None:
4055- return None
4056- try:
4057- return int(val)
4058- except ValueError:
4059- if sys.version_info < (2,3): # Long/Int aren't integrated
4060- try:
4061- return long(val)
4062- except ValueError:
4063- raise InputError("'%s' is not an integer." % val)
4064-
4065- raise InputError("'%s' is not an integer." % val)
4066-
4067-
4068-class Real(Typed):
4069-
4070- requiredFailMessage = 'Please enter a real number.'
4071-
4072- def coerce(self, val, configurable):
4073- # TODO: This shouldn't be required; check.
4074- # val should never be None, but always a string.
4075- if val is None:
4076- return None
4077- try:
4078- return float(val)
4079- except ValueError:
4080- raise InputError("'%s' is not a real number." % val)
4081-
4082-
4083-class Boolean(Typed):
4084- def coerce(self, val, configurable):
4085- if val == 'False':
4086- return False
4087- elif val == 'True':
4088- return True
4089- raise InputError("'%s' is not a boolean" % val)
4090-
4091-
4092-class FixedDigitInteger(Integer):
4093-
4094- def __init__(self, digits = 1, *args, **kw):
4095- Integer.__init__(self, *args, **kw)
4096- self.digits = digits
4097- self.requiredFailMessage = \
4098- 'Please enter a %d digit integer.' % self.digits
4099-
4100- def coerce(self, val, configurable):
4101- v = Integer.coerce(self, val, configurable)
4102- if len(str(v)) != self.digits:
4103- raise InputError("Number must be %s digits." % self.digits)
4104- return v
4105-
4106-
4107-class Directory(Typed):
4108-
4109- requiredFailMessage = 'Please enter a directory name.'
4110-
4111- def coerce(self, val, configurable):
4112- # TODO: This shouldn't be required; check.
4113- # val should never be None, but always a string.
4114- if val is None:
4115- return None
4116- if not os.path.exists(val):
4117- raise InputError("The directory '%s' does not exist." % val)
4118- return val
4119-
4120-
4121-class Choice(Typed):
4122- """Allow the user to pick from a list of "choices", presented in a drop-down
4123- menu. The elements of the list will be rendered by calling the function
4124- passed to stringify, which is by default "str".
4125- """
4126-
4127- requiredFailMessage = 'Please choose an option.'
4128-
4129- def __init__(self, choices=None, choicesAttribute=None, stringify=str,
4130- valueToKey=str, keyToValue=None, keyAndConfigurableToValue=None,
4131- *args, **kw):
4132- """
4133- Create a Choice.
4134-
4135- @param choices: an object adaptable to IGettable for an iterator (such
4136- as a function which takes (ctx, data) and returns a list, a list
4137- itself, a tuple, a generator...)
4138-
4139- @param stringify: a pretty-printer. a function which takes an object
4140- in the list of choices and returns a label for it.
4141-
4142- @param valueToKey: a function which converts an object in the list of
4143- choices to a string that can be sent to a client.
4144-
4145- @param keyToValue: a 1-argument convenience version of
4146- keyAndConfigurableToValue
4147-
4148- @param keyAndConfigurableToValue: a 2-argument function which takes a string such as
4149- one returned from valueToKey and a configurable, and returns an object
4150- such as one from the list of choices.
4151- """
4152-
4153- Typed.__init__(self, *args, **kw)
4154- self.choices = choices
4155- if choicesAttribute:
4156- self.choicesAttribute = choicesAttribute
4157- if getattr(self, 'choicesAttribute', None):
4158- warnings.warn(
4159- "Choice.choicesAttribute is deprecated. Please pass a function to choices instead.",
4160- DeprecationWarning,
4161- stacklevel=2)
4162- def findTheChoices(ctx, data):
4163- return getattr(iformless.IConfigurable(ctx).original, self.choicesAttribute)
4164- self.choices = findTheChoices
4165-
4166- self.stringify = stringify
4167- self.valueToKey=valueToKey
4168-
4169- if keyAndConfigurableToValue is not None:
4170- assert keyToValue is None, 'This should be *obvious*'
4171- self.keyAndConfigurableToValue = keyAndConfigurableToValue
4172- elif keyToValue is not None:
4173- self.keyAndConfigurableToValue = lambda x,y: keyToValue(x)
4174- else:
4175- self.keyAndConfigurableToValue = lambda x,y: str(x)
4176-
4177-
4178- def coerce(self, val, configurable):
4179- """Coerce a value with the help of an object, which is the object
4180- we are configuring.
4181- """
4182- return self.keyAndConfigurableToValue(val, configurable)
4183-
4184-
4185-class Radio(Choice):
4186- """Type influencing presentation! horray!
4187-
4188- Show the user radio button choices instead of a picklist.
4189- """
4190-
4191-
4192-class Any(object):
4193- """Marker which indicates any object type.
4194- """
4195-
4196-
4197-class Object(Typed):
4198- complexType = True
4199- def __init__(self, interface=Any, *args, **kw):
4200- Typed.__init__(self, *args, **kw)
4201- self.iface = interface
4202-
4203- def __repr__(self):
4204- if self.iface is not None:
4205- return "%s(interface=%s)" % (self.__class__.__name__, util.qual(self.iface))
4206- return "%s(None)" % (self.__class__.__name__,)
4207-
4208-
4209-
4210-class List(Object):
4211- implements(iformless.IActionableType)
4212-
4213- complexType = True
4214- def __init__(self, actions=None, header='', footer='', separator='', *args, **kw):
4215- """Actions is a list of action methods which may be invoked on one
4216- or more of the elements of this list. Action methods are defined
4217- on a TypedInterface and declare that they take one parameter
4218- of type List. They do not declare themselves to be autocallable
4219- in the traditional manner. Instead, they are passed in the actions
4220- list of a list Property to declare that the action may be taken on
4221- one or more of the list elements.
4222- """
4223- if actions is None:
4224- actions = []
4225- self.actions = actions
4226- self.header = header
4227- self.footer = footer
4228- self.separator = separator
4229- Object.__init__(self, *args, **kw)
4230-
4231- def coerce(self, data, configurable):
4232- return data
4233-
4234- def __repr__(self):
4235- if self.iface is not None:
4236- return "%s(interface=%s)" % (self.__class__.__name__, util.qual(self.iface))
4237- return self.__class__.__name__ + "()"
4238-
4239- def attachActionBindings(self, possibleActions):
4240- ## Go through and replace self.actions, which is a list of method
4241- ## references, with the MethodBinding instance which holds
4242- ## metadata about this function.
4243- act = self.actions
4244- for method, binding in possibleActions:
4245- if method in act:
4246- act[act.index(method)] = binding
4247-
4248- def getActionBindings(self):
4249- return self.actions
4250-
4251-class Dictionary(List):
4252- pass
4253-
4254-
4255-class Table(Object):
4256- pass
4257-
4258-
4259-class Request(Typed):
4260- """Marker that indicates that an autocallable should be passed the
4261- request when called. Including a Request arg will not affect the
4262- appearance of the rendered form.
4263-
4264- >>> def doSomething(request=formless.Request(), name=formless.String()):
4265- ... pass
4266- >>> doSomething = formless.autocallable(doSomething)
4267- """
4268- complexType = True ## Don't use the regular form
4269-
4270-
4271-class Context(Typed):
4272- """Marker that indicates that an autocallable should be passed the
4273- context when called. Including a Context arg will not affect the
4274- appearance of the rendered form.
4275-
4276- >>> def doSomething(context=formless.Context(), name=formless.String()):
4277- ... pass
4278- >>> doSomething = formless.autocallable(doSomething)
4279- """
4280- complexType = True ## Don't use the regular form
4281-
4282-
4283-class Button(Typed):
4284- def coerce(self, data, configurable):
4285- return data
4286-
4287-
4288-class Compound(Typed):
4289- complexType = True
4290- def __init__(self, elements=None, *args, **kw):
4291- assert elements, "What is the sound of a Compound type with no elements?"
4292- self.elements = elements
4293- Typed.__init__(self, *args, **kw)
4294-
4295- def __len__(self):
4296- return len(self.elements)
4297-
4298- def coerce(self, data, configurable):
4299- return data
4300-
4301-
4302-class Method(Typed):
4303- def __init__(self, returnValue=None, arguments=(), *args, **kw):
4304- Typed.__init__(self, *args, **kw)
4305- self.returnValue = returnValue
4306- self.arguments = arguments
4307-
4308-
4309-class Group(Object):
4310- pass
4311-
4312-
4313-def autocallable(method, action=None, visible=False, **kw):
4314- """Describe a method in a TypedInterface as being callable through the
4315- UI. The "action" paramter will be used to label the action button, or the
4316- user interface element which performs the method call.
4317-
4318- Use this like a method adapter around a method in a TypedInterface:
4319-
4320- >>> class IFoo(TypedInterface):
4321- ... def doSomething():
4322- ... '''Do Something
4323- ...
4324- ... Do some action bla bla'''
4325- ... return None
4326- ... doSomething = autocallable(doSomething, action="Do it!!")
4327- """
4328- method.autocallable = True
4329- method.id = nextId()
4330- method.action = action
4331- method.attributes = kw
4332- return method
4333-
4334-
4335-#######################################
4336-## Internal API; formless uses these objects to keep track of
4337-## what names are bound to what types
4338-#######################################
4339-
4340-
4341-class Binding(object):
4342- """Bindings bind a Typed instance to a name. When TypedInterface is subclassed,
4343- the metaclass looks through the dict looking for all properties and methods.
4344-
4345- If a properties is a Typed instance, a Property Binding is constructed, passing
4346- the name of the binding and the Typed instance.
4347-
4348- If a method has been wrapped with the "autocallable" function adapter,
4349- a Method Binding is constructed, passing the name of the binding and the
4350- Typed instance. Then, getargspec is called. For each keyword argument
4351- in the method definition, an Argument is constructed, passing the name
4352- of the keyword argument as the binding name, and the value of the
4353- keyword argument, a Typed instance, as the binding typeValue.
4354-
4355- One more thing. When an autocallable method is found, it is called with
4356- None as the self argument. The return value is passed the Method
4357- Binding when it is constructed to keep track of what the method is
4358- supposed to return.
4359- """
4360- implements(iformless.IBinding)
4361-
4362- label = None
4363- description = ''
4364-
4365- def __init__(self, name, typedValue, id=0):
4366- self.id = id
4367- self.name = name
4368- self.typedValue = iformless.ITyped(typedValue)
4369-
4370- # pull these out to remove one level of indirection...
4371- if typedValue.description is not None:
4372- self.description = typedValue.description
4373- if typedValue.label is not None:
4374- self.label = typedValue.label
4375- if self.label is None:
4376- self.label = nameToLabel(name)
4377- self.default = typedValue.default
4378- self.complexType = typedValue.complexType
4379-
4380- def __repr__(self):
4381- return "<%s %s=%s at 0x%x>" % (self.__class__.__name__, self.name, self.typedValue.__class__.__name__, id(self))
4382-
4383- def getArgs(self):
4384- """Return a *copy* of this Binding.
4385- """
4386- return (Binding(self.name, self.original, self.id), )
4387-
4388- def getViewName(self):
4389- return self.original.__class__.__name__.lower()
4390-
4391- def configure(self, boundTo, results):
4392- raise NotImplementedError, "Implement in %s" % util.qual(self.__class__)
4393-
4394- def coerce(self, val, configurable):
4395- if hasattr(self.original, 'coerce'):
4396- return self.original.coerce(val)
4397- return val
4398-
4399-class Argument(Binding):
4400- pass
4401-
4402-
4403-class Property(Binding):
4404- action = 'Change'
4405- def configure(self, boundTo, results):
4406- ## set the property!
4407- setattr(boundTo, self.name, results[self.name])
4408-
4409-
4410-class MethodBinding(Binding):
4411- typedValue = None
4412- def __init__(self, name, typeValue, id=0, action="Call", attributes = {}):
4413- Binding.__init__(self, name, typeValue, id)
4414- self.action = action
4415- self.arguments = typeValue.arguments
4416- self.returnValue = typeValue.returnValue
4417- self.attributes = attributes
4418-
4419- def getAttribute(self, name):
4420- return self.attributes.get(name, None)
4421-
4422- def configure(self, boundTo, results):
4423- bound = getattr(boundTo, self.name)
4424- return bound(**results)
4425-
4426- def getArgs(self):
4427- """Make sure each form post gets a unique copy of the argument list which it can use to keep
4428- track of values given in partially-filled forms
4429- """
4430- return self.typedValue.arguments[:]
4431-
4432-
4433-class ElementBinding(Binding):
4434- """An ElementBinding binds a key to an element of a container.
4435- For example, ElementBinding('0', Object()) indicates the 0th element
4436- of a container of Objects. When this ElementBinding is bound to
4437- the list [1, 2, 3], resolving the binding will result in the 0th element,
4438- the object 1.
4439- """
4440- pass
4441-
4442-
4443-class GroupBinding(Binding):
4444- """A GroupBinding is a way of naming a group of other Bindings.
4445- The typedValue of a GroupBinding should be a Configurable.
4446- The Bindings returned from this Configurable (usually a TypedInterface)
4447- will be rendered such that all fields must/may be filled out, and all
4448- fields will be changed at once upon form submission.
4449- """
4450- def __init__(self, name, typedValue, id=0):
4451- """Hack to prevent adaption to ITyped while the adapters are still
4452- being registered, because we know that the typedValue should be
4453- a Group when we are constructing a GroupBinding.
4454- """
4455- self.id = id
4456- self.name = name
4457- self.typedValue = Group(typedValue)
4458-
4459- # pull these out to remove one level of indirection...
4460- self.description = typedValue.description
4461- if typedValue.label:
4462- self.label = typedValue.label
4463- else:
4464- self.label = nameToLabel(name)
4465- self.default = typedValue.default
4466- self.complexType = typedValue.complexType
4467-
4468- def configure(self, boundTo, group):
4469- print "CONFIGURING GROUP BINDING", boundTo, group
4470-
4471-
4472-def _sorter(x, y):
4473- return cmp(x.id, y.id)
4474-
4475-
4476-class _Marker(object):
4477- pass
4478-
4479-
4480-def caps(c):
4481- return c.upper() == c
4482-
4483-
4484-def nameToLabel(mname):
4485- labelList = []
4486- word = ''
4487- lastWasUpper = False
4488- for letter in mname:
4489- if caps(letter) == lastWasUpper:
4490- # Continuing a word.
4491- word += letter
4492- else:
4493- # breaking a word OR beginning a word
4494- if lastWasUpper:
4495- # could be either
4496- if len(word) == 1:
4497- # keep going
4498- word += letter
4499- else:
4500- # acronym
4501- # we're processing the lowercase letter after the acronym-then-capital
4502- lastWord = word[:-1]
4503- firstLetter = word[-1]
4504- labelList.append(lastWord)
4505- word = firstLetter + letter
4506- else:
4507- # definitely breaking: lower to upper
4508- labelList.append(word)
4509- word = letter
4510- lastWasUpper = caps(letter)
4511- if labelList:
4512- labelList[0] = labelList[0].capitalize()
4513- else:
4514- return mname.capitalize()
4515- labelList.append(word)
4516- return ' '.join(labelList)
4517-
4518-
4519-def labelAndDescriptionFromDocstring(docstring):
4520- if docstring is None:
4521- docstring = ''
4522- docs = filter(lambda x: x, [x.strip() for x in docstring.split('\n')])
4523- if len(docs) > 1:
4524- return docs[0], '\n'.join(docs[1:])
4525- else:
4526- return None, '\n'.join(docs)
4527-
4528-
4529-_typedInterfaceMetadata = {}
4530-
4531-
4532-class MetaTypedInterface(InterfaceClass):
4533- """The metaclass for TypedInterface. When TypedInterface is subclassed,
4534- this metaclass' __new__ method is invoked. The Typed Binding introspection
4535- described in the Binding docstring occurs, and when it is all done, there will
4536- be three attributes on the TypedInterface class:
4537-
4538- - __methods__: An ordered list of all the MethodBinding instances
4539- produced by introspecting all autocallable methods on this
4540- TypedInterface
4541-
4542- - __properties__: An ordered list of all the Property Binding
4543- instances produced by introspecting all properties which have
4544- Typed values on this TypedInterface
4545-
4546- - __spec__: An ordered list of all methods and properties
4547-
4548- These lists are sorted in the order that the methods and properties appear
4549- in the TypedInterface definition.
4550-
4551- For example:
4552-
4553- >>> class Foo(TypedInterface):
4554- ... bar = String()
4555- ... baz = Integer()
4556- ...
4557- ... def frotz(): pass
4558- ... frotz = autocallable(frotz)
4559- ...
4560- ... xyzzy = Float()
4561- ...
4562- ... def blam(): pass
4563- ... blam = autocallable(blam)
4564-
4565- Once the metaclass __new__ is done, the Foo class instance will have three
4566- properties, __methods__, __properties__, and __spec__,
4567- """
4568- __methods__ = property(lambda self: _typedInterfaceMetadata[self, '__methods__'])
4569- __id__ = property(lambda self: _typedInterfaceMetadata[self, '__id__'])
4570- __properties__ = property(lambda self: _typedInterfaceMetadata[self, '__properties__'])
4571- __spec__ = property(lambda self: _typedInterfaceMetadata[self, '__spec__'])
4572- name = property(lambda self: _typedInterfaceMetadata[self, 'name'])
4573- label = property(lambda self: _typedInterfaceMetadata[self, 'label'])
4574- description = property(lambda self: _typedInterfaceMetadata[self, 'description'])
4575- default = property(lambda self: _typedInterfaceMetadata.get((self, 'default'), 'DEFAULT'))
4576- complexType = property(lambda self: _typedInterfaceMetadata.get((self, 'complexType'), True))
4577-
4578- def __new__(cls, name, bases, dct):
4579- rv = cls = InterfaceClass.__new__(cls)
4580- _typedInterfaceMetadata[cls, '__id__'] = nextId()
4581- _typedInterfaceMetadata[cls, '__methods__'] = methods = []
4582- _typedInterfaceMetadata[cls, '__properties__'] = properties = []
4583- possibleActions = []
4584- actionAttachers = []
4585- for key, value in dct.items():
4586- if key[0] == '_': continue
4587-
4588- if isinstance(value, MetaTypedInterface):
4589- ## A Nested TypedInterface indicates a GroupBinding
4590- properties.append(GroupBinding(key, value, value.__id__))
4591-
4592- ## zope.interface doesn't like these
4593- del dct[key]
4594- setattr(cls, key, value)
4595- elif callable(value):
4596- names, _, _, typeList = inspect.getargspec(value)
4597-
4598- _testCallArgs = ()
4599-
4600- if typeList is None:
4601- typeList = []
4602-
4603- if len(names) == len(typeList) + 1:
4604- warnings.warn(
4605- "TypeInterface method declarations should not have a 'self' parameter",
4606- DeprecationWarning,
4607- stacklevel=2)
4608- del names[0]
4609- _testCallArgs = (_Marker,)
4610-
4611- if len(names) != len(typeList):
4612- ## Allow non-autocallable methods in the interface; ignore them
4613- continue
4614-
4615- argumentTypes = [
4616- Argument(n, argtype, argtype.id) for n, argtype in zip(names[-len(typeList):], typeList)
4617- ]
4618-
4619- result = value(*_testCallArgs)
4620-
4621- label = None
4622- description = None
4623- if getattr(value, 'autocallable', None):
4624- # autocallables have attributes that can set label and description
4625- label = value.attributes.get('label', None)
4626- description = value.attributes.get('description', None)
4627-
4628- adapted = iformless.ITyped(result, None)
4629- if adapted is None:
4630- adapted = Object(result)
4631-
4632- # ITyped has label and description we can use
4633- if label is None:
4634- label = adapted.label
4635- if description is None:
4636- description = adapted.description
4637-
4638- defaultLabel, defaultDescription = labelAndDescriptionFromDocstring(value.__doc__)
4639- if defaultLabel is None:
4640- # docstring had no label, try the action if it is an autocallable
4641- if getattr(value, 'autocallable', None):
4642- if label is None and value.action is not None:
4643- # no explicit label, but autocallable has action we can use
4644- defaultLabel = value.action
4645-
4646- if defaultLabel is None:
4647- # final fallback: use the function name as label
4648- defaultLabel = nameToLabel(key)
4649-
4650- if label is None:
4651- label = defaultLabel
4652- if description is None:
4653- description = defaultDescription
4654-
4655- theMethod = Method(
4656- adapted, argumentTypes, label=label, description=description
4657- )
4658-
4659- if getattr(value, 'autocallable', None):
4660- methods.append(
4661- MethodBinding(
4662- key, theMethod, value.id, value.action, value.attributes))
4663- else:
4664- possibleActions.append((value, MethodBinding(key, theMethod)))
4665- else:
4666- if not value.label:
4667- value.label = nameToLabel(key)
4668- if iformless.IActionableType.providedBy(value):
4669- actionAttachers.append(value)
4670- properties.append(
4671- Property(key, value, value.id)
4672- )
4673- for attacher in actionAttachers:
4674- attacher.attachActionBindings(possibleActions)
4675- methods.sort(_sorter)
4676- properties.sort(_sorter)
4677- _typedInterfaceMetadata[cls, '__spec__'] = spec = methods + properties
4678- spec.sort(_sorter)
4679- _typedInterfaceMetadata[cls, 'name'] = name
4680-
4681- # because attributes "label" and "description" would become Properties,
4682- # check for ones with an underscore prefix.
4683- _typedInterfaceMetadata[cls, 'label'] = dct.get('_label', None)
4684- _typedInterfaceMetadata[cls, 'description'] = dct.get('_description', None)
4685- defaultLabel, defaultDescription = labelAndDescriptionFromDocstring(dct.get('__doc__'))
4686- if defaultLabel is None:
4687- defaultLabel = nameToLabel(name)
4688- if _typedInterfaceMetadata[cls, 'label'] is None:
4689- _typedInterfaceMetadata[cls, 'label'] = defaultLabel
4690- if _typedInterfaceMetadata[cls, 'description'] is None:
4691- _typedInterfaceMetadata[cls, 'description'] = defaultDescription
4692-
4693- return rv
4694-
4695-
4696-#######################################
4697-## External API; subclass this to create a TypedInterface
4698-#######################################
4699-
4700-TypedInterface = MetaTypedInterface('TypedInterface', (InterfaceClass('TypedInterface'), ), {})
4701-
4702
4703=== removed file 'Nevow/formless/configurable.py'
4704--- Nevow/formless/configurable.py 2006-03-17 15:00:39 +0000
4705+++ Nevow/formless/configurable.py 1970-01-01 00:00:00 +0000
4706@@ -1,173 +0,0 @@
4707-# Copyright (c) 2004 Divmod.
4708-# See LICENSE for details.
4709-
4710-from zope.interface import implements, providedBy
4711-
4712-from formless.iformless import IConfigurable, IActionableType, IBinding
4713-from formless.annotate import Argument, ElementBinding, GroupBinding, Object, TypedInterface
4714-
4715-from nevow import inevow
4716-from nevow.context import WovenContext
4717-
4718-class Configurable(object):
4719- implements(IConfigurable)
4720-
4721- bindingDict = None
4722-
4723- def __init__(self, original):
4724- self.original = original
4725- self.boundTo = self
4726-
4727- def getBindingNames(self, context):
4728- ## Todo: remove this getattr
4729- ifs = providedBy(getattr(self, 'boundTo', self))
4730- ifs = [
4731- x for x in ifs if x is not IConfigurable and x is not TypedInterface
4732- ]
4733- bindingNames = []
4734- self.bindingDict = bindingDict = {}
4735- for interface in ifs:
4736- ## TypedInterfaces have a __spec__ attribute which is a list of all Typed properties and
4737- ## autocallable methods
4738- for binding in getattr(interface, '__spec__', []):
4739- bindingDict[binding.name] = binding
4740- if binding.name not in bindingNames:
4741- bindingNames.append(binding.name)
4742- if IActionableType.providedBy(binding.typedValue):
4743- acts = binding.typedValue.actions
4744- if acts is None:
4745- acts = []
4746- for action in acts:
4747- bindingDict[action.name] = action
4748- return bindingNames
4749-
4750- def getDefault(self, forBinding):
4751- ## TODO: Clean this up, it's a mess
4752- if not isinstance(forBinding, Argument):
4753- name = forBinding.name
4754- if hasattr(self, name):
4755- return getattr(self, name)
4756- ## Todo: Only do this in ConfigurableAdapter instead of Configurable
4757- if hasattr(self.boundTo, name):
4758- return getattr(self.boundTo, name)
4759- if self.original is not self.boundTo and hasattr(self.original, name):
4760- return getattr(self.original, name)
4761- return forBinding.default
4762-
4763- def getBinding(self, context, name):
4764- if self.bindingDict is None:
4765- self.getBindingNames(context)
4766- if self.bindingDict is None:
4767- self.bindingDict = {}
4768- binding = getattr(self, 'bind_%s' % name, getattr(self.boundTo, 'bind_%s' % name, None))
4769- if binding is not None:
4770- binding = binding(context)
4771- else:
4772- try:
4773- binding = self.bindingDict[name]
4774- except KeyError:
4775- raise RuntimeError, "%s is not an exposed binding on object %s." % (name, self.boundTo)
4776- binding.boundTo = self.boundTo
4777- return binding
4778-
4779- def postForm(self, ctx, bindingName, args):
4780- """Accept a form post to the given bindingName. The bindingName
4781- can be dotted to indicate an attribute of this Configurable, eg
4782- addresses.0.changeEmail. The post arguments are given in args.
4783- Return a Resource which will be rendered in response.
4784- """
4785- from formless import iformless
4786- from nevow.tags import invisible
4787- request = ctx.locate(inevow.IRequest)
4788- pathSegs = bindingName.split('.')
4789- configurable = self
4790-
4791- cf = ctx.locate(iformless.IConfigurableFactory)
4792- ## Get the first binding
4793- firstSeg = pathSegs.pop(0)
4794- binding = configurable.getBinding(ctx, firstSeg)
4795- ctx.remember(binding, IBinding)
4796- ctx.remember(configurable, IConfigurable)
4797- ## I don't think this works right now, it needs to be fixed.
4798- ## Most cases it won't be triggered, because we're just traversing a
4799- ## single binding name
4800- for seg in pathSegs:
4801- assert 1 == 0, "Sorry, this doesn't work right now"
4802- binding = configurable.getBinding(ctx, seg)
4803- child = self.boundTo
4804- if not isinstance(binding, GroupBinding):
4805- accessor = inevow.IContainer(configurable.boundTo, None)
4806- if accessor is None:
4807- child = getattr(configurable.boundTo, binding.name)
4808- else:
4809- child = accessor.child(ctx, binding.name)
4810- ## If it's a groupbinding, we don't do anything at all for this path segment
4811-
4812- ## This won't work right now. We need to push the previous configurable
4813- ## as the configurableFactory somehow and ask that for hte next binding
4814- ## we also need to support deferreds coming back from locateConfigurable
4815- assert 'black' is 'white', "Deferred support is pending"
4816- configurable = cf.locateConfigurable(ctx, child)
4817- ctx = WovenContext(ctx, invisible(key=seg))
4818- ctx.remember(binding, IBinding)
4819- ctx.remember(configurable, IConfigurable)
4820-
4821- bindingProcessor = iformless.IInputProcessor(binding)
4822- rv = bindingProcessor.process(ctx, binding.boundTo, args)
4823- ctx.remember(rv, inevow.IHand)
4824- ctx.remember('%r success.' % bindingName, inevow.IStatusMessage)
4825- return rv
4826-
4827- def summary(self):
4828- return "An instance of %s" % self.__class__.__name__
4829-
4830- postLocation = None
4831-
4832-class NotFoundConfigurable(Configurable):
4833- def getBinding(self, context, name):
4834- raise RuntimeError, self.original
4835-
4836-
4837-class TypedInterfaceConfigurable(Configurable):
4838- def __init__(self, original):
4839- self.original = original
4840- self.boundTo = original
4841-
4842- def summary(self):
4843- return "An instance of %s" % self.original.__class__.__name__
4844-
4845- def __repr__(self):
4846- return "TypedInterfaceConfigurable(%r)" % self.original
4847-
4848-
4849-class ListConfigurable(TypedInterfaceConfigurable):
4850- def getBinding(self, context, name):
4851- eb = ElementBinding(name, Object())
4852- eb.boundTo = self.original
4853- return eb
4854-
4855-
4856-class GroupConfigurable(TypedInterfaceConfigurable):
4857- def __init__(self, original, groupInterface):
4858- TypedInterfaceConfigurable.__init__(self, original)
4859- self.groupInterface = groupInterface
4860-
4861- bindingDict = None
4862-
4863- def getBindingNames(self, context):
4864- bindingNames = []
4865- self.bindingDict = bindingDict = {}
4866- interface = self.groupInterface
4867- for binding in getattr(interface, '__spec__', []):
4868- bindingDict[binding.name] = binding
4869- if binding.name not in bindingNames:
4870- bindingNames.append(binding.name)
4871- if IActionableType.providedBy(binding.typedValue):
4872- acts = binding.typedValue.actions
4873- if acts is None:
4874- acts = []
4875- for action in acts:
4876- bindingDict[action.name] = action
4877- return bindingNames
4878-
4879-
4880
4881=== removed file 'Nevow/formless/formutils.py'
4882--- Nevow/formless/formutils.py 2006-04-14 17:23:46 +0000
4883+++ Nevow/formless/formutils.py 1970-01-01 00:00:00 +0000
4884@@ -1,143 +0,0 @@
4885-# Copyright (c) 2004 Divmod.
4886-# See LICENSE for details.
4887-
4888-from __future__ import generators
4889-
4890-from zope.interface import implements
4891-
4892-from twisted.python import components
4893-
4894-from nevow import inevow
4895-from nevow import tags
4896-
4897-from formless import iformless
4898-
4899-
4900-try:
4901- enumerate = enumerate
4902-except:
4903- def enumerate(collection):
4904- i = 0
4905- it = iter(collection)
4906- while 1:
4907- yield (i, it.next())
4908- i += 1
4909-
4910-
4911-class PrefixerDict(dict):
4912- def __init__(self, prefix, errors):
4913- if prefix is None: prefix = ''
4914- self.prefix = prefix
4915- self.errors = errors
4916- dict.__init__(self)
4917-
4918- def __setitem__(self, key, value):
4919- if key is None:
4920- key = ''
4921- if key == '':
4922- pfxkey = self.prefix
4923- else:
4924- pfxkey = '.'.join((self.prefix, key))
4925- self.errors[pfxkey] = value
4926-
4927- def __getitem__(self, key):
4928- if key == '':
4929- pfxkey = self.prefix
4930- else:
4931- pfxkey = '.'.join((self.prefix, key))
4932- return self.errors[pfxkey]
4933-
4934- def update(self, other):
4935- for key, value in other.items():
4936- self[key] = value
4937-
4938-
4939-class FormDefaults(components.Adapter):
4940- def __init__(self):
4941- self.defaults = {}
4942-
4943- def setDefault(self, key, value, context=None):
4944- self.defaults[key] = value
4945-
4946- def getDefault(self, key, context=None):
4947- #print "getting default for key", key, self.defaults
4948- # 1) Check on the request
4949- current = self.defaults.get(key, None)
4950- if current is None:
4951- # 2) Check on the session
4952- if context is not None:
4953- sessionDefaults = context.locate(iformless.IFormDefaults)
4954- if sessionDefaults is not self:
4955- current = sessionDefaults.getDefault(key)
4956- if current is not None:
4957- return current
4958- # 3) Ask the Binding instance for the default values
4959- try:
4960- configurable = context.locate(iformless.IConfigurable)
4961- except KeyError:
4962- return ''
4963- return configurable.getDefault(context.locate(inevow.IData))
4964- return current
4965-
4966- def getAllDefaults(self, key):
4967- return PrefixerDict(key, self.defaults)
4968-
4969- def clearAll(self):
4970- self.defaults = {}
4971-
4972-
4973-class FormErrors(components.Adapter):
4974- """An object which keeps track of which forms have which errors
4975- """
4976- implements(iformless.IFormErrors)
4977- def __init__(self):
4978- self.errors = {}
4979-
4980- def setError(self, errorKey, error):
4981- self.errors[errorKey] = error
4982-
4983- def getError(self, errorKey):
4984- #print "get error", errorKey, self.__dict__
4985- return self.errors.get(errorKey)
4986-
4987- def getAllErrors(self, formName):
4988- return PrefixerDict(formName, self.errors)
4989-
4990- def updateErrors(self, formName, errors):
4991- PrefixerDict(formName, self.errors).update(errors)
4992-
4993- def clearErrors(self, formName):
4994- for key in self.errors.keys():
4995- if key.startswith(formName):
4996- del self.errors[key]
4997-
4998- def clearAll(self):
4999- self.errors = {}
5000-
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches

to all changes: