"""This module is DEPRECATED."""
import warnings
warnings.warn("This module is deprecated, please use Woven instead.", DeprecationWarning)
import string, time, types, traceback, pprint, sys, os
import linecache
import re
from cStringIO import StringIO
from twisted.python import failure, log, rebuild, reflect, util
from twisted.internet import defer
from twisted.protocols import http
import html, resource, error
import util as webutil
from util import formatFailure, htmlrepr, htmlUnknown, htmlDict, htmlList,\
htmlInst, htmlString, htmlReprTypes
from server import NOT_DONE_YET
True = (1==1)
False = not True
"""A twisted web component framework.
This code is mainly old stuff which is being kept around for historical
reasons. It is being very gradually deprecated in favor of twisted.web.woven;
however, woven is still maturing and does not yet have equivalent functionality
in all areas. (Though in some ways, it's already much more featureful.) This
module will be removed when woven has reached feature- and documentation-parity
with it, and all Twisted functionality that uses it has been rewritten.
"""
FORGET_IT = 99
def listify(x):
return [x]
def _ellipsize(x):
y = repr(x)
if len(y) > 1024:
return y[:1024]+"..."
return y
class Widget:
"""A component of a web page.
"""
title = None
def getTitle(self, request):
return self.title or reflect.qual(self.__class__)
def display(self, request):
"""Implement me to represent your widget.
I must return a list of strings and twisted.internet.defer.Deferred
instances.
"""
raise NotImplementedError("%s.display" % reflect.qual(self.__class__))
class StreamWidget(Widget):
"""A 'streamable' component of a webpage.
"""
def stream(self, write, request):
"""Call 'write' multiple times with a string argument to represent this widget.
"""
raise NotImplementedError("%s.stream" % reflect.qual(self.__class__))
def display(self, request):
"""Produce a list containing a single string.
"""
l = []
try:
result = self.stream(l.append, request)
if result is not None:
return result
return l
except:
return [webutil.formatFailure(failure.Failure())]
class WidgetMixin(Widget):
"""A mix-in wrapper for a Widget.
This mixin can be used to wrap functionality in any other widget with a
method of your choosing. It is designed to be used for mix-in classes that
can be mixed in to Form, StreamWidget, Presentation, etc, to augment the
data available to the 'display' methods of those classes, usually by adding
it to a Session.
"""
def display(self):
raise NotImplementedError("%s.display" % self.__class__)
def displayMixedWidget(self, request):
for base in reflect.allYourBase(self.__class__):
if issubclass(base, Widget) and not issubclass(base, WidgetMixin):
return base.display(self, request)
class Presentation(Widget):
"""I am a widget which formats a template with interspersed python expressions.
"""
template = '''
Hello, %%%%world%%%%.
'''
world = "you didn't assign to the 'template' attribute"
def __init__(self, template=None, filename=None):
if filename:
self.template = open(filename).read()
elif template:
self.template = template
self.variables = {}
self.tmpl = string.split(self.template, "%%%%")
def addClassVars(self, namespace, Class):
for base in Class.__bases__:
if issubclass(base, Presentation) and base is not Presentation:
self.addClassVars(namespace, base)
for k in Class.__dict__.keys():
namespace[k] = getattr(self, k)
def addVariables(self, namespace, request):
self.addClassVars(namespace, self.__class__)
def prePresent(self, request):
"""Perform any tasks which must be done before presenting the page.
"""
def formatTraceback(self, tb):
return [html.PRE(tb)]
def streamCall(self, call, *args, **kw):
"""Utility: Call a method like StreamWidget's 'stream'.
"""
io = StringIO()
apply(call, (io.write,) + args, kw)
return io.getvalue()
def display(self, request):
tm = []
flip = 0
namespace = {}
self.prePresent(request)
self.addVariables(namespace, request)
namespace['request'] = request
namespace['self'] = self
for elem in self.tmpl:
flip = not flip
if flip:
if elem:
tm.append(elem)
else:
try:
x = eval(elem, namespace, namespace)
except:
log.deferr()
tm.append(webutil.formatFailure(failure.Failure()))
else:
if isinstance(x, types.ListType):
tm.extend(x)
elif isinstance(x, Widget):
val = x.display(request)
if not isinstance(val, types.ListType):
raise Exception("%s.display did not return a list, it returned %s!" % (x.__class__, repr(val)))
tm.extend(val)
else:
tm.append(x)
return tm
def htmlFor_hidden(write, name, value):
write('<INPUT TYPE="hidden" NAME="%s" VALUE="%s" />' % (name, value))
def htmlFor_file(write, name, value):
write('<INPUT SIZE="60" TYPE="file" NAME="%s" />' % name)
def htmlFor_string(write, name, value):
write('<INPUT SIZE="60" TYPE="text" NAME="%s" VALUE="%s" />' % (name, value))
def htmlFor_password(write, name, value):
write('<INPUT SIZE="60" TYPE="password" NAME="%s" />' % name)
def htmlFor_text(write, name, value):
write('<textarea COLS="60" ROWS="10" NAME="%s" WRAP="virtual">%s</textarea>' % (name, value))
def htmlFor_menu(write, name, value, allowMultiple=False):
"Value of the format [(optionName, displayName[, selected]), ...]"
write(' <select NAME="%s"%s>\n' %
(name, (allowMultiple and " multiple") or ''))
for v in value:
optionName, displayName, selected = util.padTo(3, v)
selected = (selected and " selected") or ''
write(' <option VALUE="%s"%s>%s</option>\n' %
(optionName, selected, displayName))
if not value:
write(' <option VALUE=""></option>\n')
write(" </select>\n")
def htmlFor_multimenu(write, name, value):
"Value of the format [(optionName, displayName[, selected]), ...]"
return htmlFor_menu(write, name, value, True)
def htmlFor_checkbox(write, name, value):
"A checkbox."
if value:
value = 'checked = "1"'
else:
value = ''
write('<INPUT TYPE="checkbox" NAME="__checkboxes__" VALUE="%s" %s />\n' % (name, value))
def htmlFor_checkgroup(write, name, value):
"A check-group."
for optionName, displayName, checked in value:
checked = (checked and 'checked = "1"') or ''
write('<INPUT TYPE="checkbox" NAME="%s" VALUE="%s" %s />%s<br />\n' % (name, optionName, checked, displayName))
def htmlFor_radio(write, name, value):
"A radio button group."
for optionName, displayName, checked in value:
checked = (checked and 'checked = "1"') or ''
write('<INPUT TYPE="radio" NAME="%s" VALUE="%s" %s />%s<br />\n' % (name, optionName, checked, displayName))
class FormInputError(Exception):
pass
class Form(Widget):
"""I am a web form.
In order to use me, you probably want to set self.formFields (or override
'getFormFields') and override 'process'. In order to demonstrate how this
is done, here is a small sample Form subclass::
| from twisted.web import widgets
| class HelloForm(widgets.Form):
| formFields = [
| ['string', 'Who to greet?', 'whoToGreet', 'World',
| 'This is for choosing who to greet.'],
| ['menu', 'How to greet?', 'how', [('cheerfully', 'with a smile'),
| ('sullenly', 'without enthusiasm'),
| ('spontaneously', 'on the spur of the moment')]]
| 'This is for choosing how to greet them.']
| def process(self, write, request, submit, whoToGreet, how):
| write('The web wakes up and %s says, \"Hello, %s!\"' % (how, whoToGreet))
If you load this widget, you will see that it displays a form with 2 inputs
derived from data in formFields. Note the argument names to 'process':
after 'write' and 'request', they are the same as the 3rd elements ('Input
Name' parameters) of the formFields list.
"""
formGen = {
'hidden': htmlFor_hidden,
'file': htmlFor_file,
'string': htmlFor_string,
'int': htmlFor_string,
'float': htmlFor_string,
'text': htmlFor_text,
'menu': htmlFor_menu,
'multimenu': htmlFor_multimenu,
'password': htmlFor_password,
'checkbox': htmlFor_checkbox,
'checkgroup': htmlFor_checkgroup,
'radio': htmlFor_radio,
}
formParse = {
'int': int,
'float': float,
}
formFields = [
]
formAcceptExtraArgs = 0
def getFormFields(self, request, fieldSet = None):
"""I return a list of lists describing this form, or a Deferred.
This information is used both to display the form and to process it.
The list is in the following format::
| [['Input Type', 'Display Name', 'Input Name', 'Input Value', 'Description'],
| ['Input Type 2', 'Display Name 2', 'Input Name 2', 'Input Value 2', 'Description 2']
| ...]
Valid values for 'Input Type' are:
- 'hidden': a hidden field that contains a string that the user won't change
- 'string': a short string
- 'int': an integer, e.g. 1, 0, 25 or -23
- 'float': a float, e.g. 1.0, 2, -3.45, or 28.4324231
- 'text': a longer text field, suitable for entering paragraphs
- 'menu': an HTML SELECT input, a list of choices
- 'multimenu': an HTML SELECT input allowing multiple choices
- 'checkgroup': a group of checkboxes
- 'radio': a group of radio buttons
- 'password': a 'string' field where the contents are not visible as the user types
- 'file': a file-upload form (EXPERIMENTAL)
'Display Name' is a descriptive string that will be used to
identify the field to the user.
The 'Input Name' must be a legal Python identifier that describes both
the value's name on the HTML form and the name of an argument to
'self.process()'.
The 'Input Value' is usually a string, but its value can depend on the
'Input Type'. 'int' it is an integer, 'menu' it is a list of pairs of
strings, representing (value, name) pairs for the menu options. Input
value for 'checkgroup' and 'radio' should be a list of ('inputName',
'Display Name', 'checked') triplets.
The 'Description' field is an (optional) string which describes the form
item to the user.
If this result is statically determined for your Form subclass, you can
assign it to FormSubclass.formFields; if you need to determine it
dynamically, you can override this method.
Note: In many cases it is desirable to use user input for defaults in
the form rather than those supplied by your calculations, which is what
this method will do to self.formFields. If this is the case for you,
but you still need to dynamically calculate some fields, pass your
results back through this method by doing::
| def getFormFields(self, request):
| myFormFields = [self.myFieldCalculator()]
| return widgets.Form.getFormFields(self, request, myFormFields)
"""
fields = []
if fieldSet is None:
fieldSet = self.formFields
if not self.shouldProcess(request):
return fieldSet
for field in fieldSet:
if len(field)==5:
inputType, displayName, inputName, inputValue, description = field
else:
inputType, displayName, inputName, inputValue = field
description = ""
if inputType == 'checkbox':
if request.args.has_key('__checkboxes__'):
if inputName in request.args['__checkboxes__']:
inputValue = 1
else:
inputValue = 0
else:
inputValue = 0
elif inputType in ('checkgroup', 'radio'):
if request.args.has_key(inputName):
keys = request.args[inputName]
else:
keys = []
iv = inputValue
inputValue = []
for optionName, optionDisplayName, checked in iv:
checked = optionName in keys
inputValue.append([optionName, optionDisplayName, checked])
elif request.args.has_key(inputName):
iv = request.args[inputName][0]
if inputType in ['menu', 'multimenu']:
if iv in inputValue:
inputValue.remove(iv)
inputValue.insert(0, iv)
else:
inputValue = iv
fields.append([inputType, displayName, inputName, inputValue, description])
return fields
submitNames = ['Submit']
actionURI = ''
def format(self, form, write, request):
"""I display an HTML FORM according to the result of self.getFormFields.
"""
write('<form ENCTYPE="multipart/form-data" METHOD="post" ACTION="%s">\n'
'<table BORDER="0">\n' % (self.actionURI or request.uri))
for field in form:
if len(field) == 5:
inputType, displayName, inputName, inputValue, description = field
else:
inputType, displayName, inputName, inputValue = field
description = ""
write('<tr>\n<td ALIGN="right" VALIGN="top"><B>%s</B></td>\n'
'<td VALIGN="%s">\n' %
(displayName, ((inputType == 'text') and 'top') or 'middle'))
self.formGen[inputType](write, inputName, inputValue)
write('\n<br />\n<font size="-1">%s</font></td>\n</tr>\n' % description)
write('<tr><td></td><td ALIGN="left"><hr />\n')
for submitName in self.submitNames:
write('<INPUT TYPE="submit" NAME="submit" VALUE="%s" />\n' % submitName)
write('</td></tr>\n</table>\n'
'<INPUT TYPE="hidden" NAME="__formtype__" VALUE="%s" />\n'
% (reflect.qual(self.__class__)))
fid = self.getFormID()
if fid:
write('<INPUT TYPE="hidden" NAME="__formid__" VALUE="%s" />\n' % fid)
write("</form>\n")
def getFormID(self):
"""Override me: I disambiguate between multiple forms of the same type.
In order to determine which form an HTTP POST request is for, you must
have some unique identifier which distinguishes your form from other
forms of the same class. An example of such a unique identifier would
be: on a page with multiple FrobConf forms, each FrobConf form refers
to a particular Frobnitz instance, which has a unique id(). The
FrobConf form's getFormID would probably look like this::
| def getFormID(self):
| return str(id(self.frobnitz))
By default, this method will return None, since distinct Form instances
may be identical as far as the application is concerned.
"""
def process(self, write, request, submit, **kw):
"""Override me: I process a form.
I will only be called when the correct form input data to process this
form has been received.
I take a variable number of arguments, beginning with 'write',
'request', and 'submit'. 'write' is a callable object that will append
a string to the response, 'request' is a twisted.web.request.Request
instance, and 'submit' is the name of the submit action taken.
The remainder of my arguments must be correctly named. They will each be named after one of the
"""
write("<pre>Submit: %s <br /> %s</pre>" % (submit, html.PRE(pprint.PrettyPrinter().pformat(kw))))
def _doProcess(self, form, write, request):
"""(internal) Prepare arguments for self.process.
"""
args = request.args.copy()
kw = {}
for field in form:
inputType, displayName, inputName, inputValue = field[:4]
if inputType == 'checkbox':
if request.args.has_key('__checkboxes__'):
if inputName in request.args['__checkboxes__']:
formData = 1
else:
formData = 0
else:
formData = 0
elif inputType in ['checkgroup', 'radio', 'multimenu']:
if args.has_key(inputName):
formData = args[inputName]
del args[inputName]
else:
formData = []
else:
if not args.has_key(inputName):
raise FormInputError("missing field %s." % repr(inputName))
formData = args[inputName]
del args[inputName]
if not len(formData) == 1:
raise FormInputError("multiple values for field %s." %repr(inputName))
formData = formData[0]
method = self.formParse.get(inputType)
if method:
try:
formData = method(formData)
except:
raise FormInputError("%s: %s" % (displayName, "error"))
kw[inputName] = formData
submitAction = args.get('submit')
if submitAction:
submitAction = submitAction[0]
for field in ['submit', '__formtype__', '__checkboxes__']:
if args.has_key(field):
del args[field]
if args and not self.formAcceptExtraArgs:
raise FormInputError("unknown fields: %s" % repr(args))
return apply(self.process, (write, request, submitAction), kw)
def formatError(self,error):
"""Format an error message.
By default, this will make the message appear in red, bold italics.
"""
return '<font color="#f00"><b><i>%s</i></b></font><br />\n' % error
def shouldProcess(self, request):
args = request.args
fid = self.getFormID()
return (args and args.has_key('__formtype__') and args['__formtype__'][0] == reflect.qual(self.__class__) and ((not fid) or (args.has_key('__formid__') and args['__formid__'][0] == fid)))
def tryAgain(self, err, req):
"""Utility method for re-drawing the form with an error message.
This is handy in forms that process Deferred results. Normally you can
just raise a FormInputError() and this will happen by default.
"""
l = []
w = l.append
w(self.formatError(err))
self.format(self.getFormFields(req), w, req)
return l
def display(self, request):
"""Display the form."""
form = self.getFormFields(request)
if isinstance(form, defer.Deferred):
if self.shouldProcess(request):
form.addCallback(lambda form, f=self._displayProcess, r=request: f(r, form))
else:
form.addCallback(lambda form, f=self._displayFormat, r=request: f(r, form))
return [form]
else:
if self.shouldProcess(request):
return self._displayProcess(request, form)
else:
return self._displayFormat(request, form)
def _displayProcess(self, request, form):
l = []
write = l.append
try:
val = self._doProcess(form, write, request)
if val:
l.extend(val)
except FormInputError, fie:
write(self.formatError(str(fie)))
return l
def _displayFormat(self, request, form):
l = []
self.format(form, l.append, request)
return l
class DataWidget(Widget):
def __init__(self, data):
self.data = data
def display(self, request):
return [self.data]
class Time(Widget):
def display(self, request):
return [time.ctime(time.time())]
class Container(Widget):
def __init__(self, *widgets):
self.widgets = widgets
def display(self, request):
value = []
for widget in self.widgets:
d = widget.display(request)
value.extend(d)
return value
class _RequestDeferral:
def __init__(self):
self.deferred = defer.Deferred()
self.io = StringIO()
self.write = self.io.write
def finish(self):
self.deferred.callback([self.io.getvalue()])
def possiblyDeferWidget(widget, request):
try:
disp = widget.display(request)
for elem in disp:
if isinstance(elem, defer.Deferred):
req = _RequestDeferral()
RenderSession(disp, req)
return req.deferred
return string.join(disp, '')
except:
io = StringIO()
traceback.print_exc(file=io)
return html.PRE(io.getvalue())
class RenderSession:
"""I handle rendering of a list of deferreds, outputting their
results in correct order."""
class Sentinel:
pass
def __init__(self, lst, request):
self.lst = lst
self.request = request
self.needsHeaders = 0
self.beforeBody = 1
self.forgotten = 0
self.pauseList = []
for i in range(len(self.lst)):
item = self.lst[i]
if isinstance(item, defer.Deferred):
self._addDeferred(item, self.lst, i)
self.keepRendering()
def _addDeferred(self, deferred, lst, idx):
sentinel = self.Sentinel()
if hasattr(deferred, 'needsHeader'):
self.needsHeaders = self.needsHeaders + 1
args = (sentinel, 1)
else:
args = (sentinel, 0)
lst[idx] = sentinel, deferred
deferred.pause()
self.pauseList.append(deferred)
deferred.addCallbacks(self.callback, self.callback,
callbackArgs=args, errbackArgs=args)
def callback(self, result, sentinel, decNeedsHeaders):
if self.forgotten:
return
if result != FORGET_IT:
self.needsHeaders = self.needsHeaders - decNeedsHeaders
else:
result = [FORGET_IT]
if not type(result) in (types.ListType, types.TupleType):
result = [result]
if result[0] is NOT_DONE_YET:
done = 0
result = result[1]
if not type(result) in (types.ListType, types.TupleType):
result = [result]
else:
done = 1
for i in xrange(len(result)):
item = result[i]
if isinstance(item, defer.Deferred):
self._addDeferred(item, result, i)
for position in range(len(self.lst)):
item = self.lst[position]
if type(item) is types.TupleType and len(item) > 0:
if item[0] is sentinel:
break
else:
raise AssertionError('Sentinel for Deferred not found!')
if done:
self.lst[position:position+1] = result
else:
self.lst[position:position] = result
self.keepRendering()
def keepRendering(self):
while self.pauseList:
pl = self.pauseList
self.pauseList = []
for deferred in pl:
deferred.unpause()
return
if self.needsHeaders:
return
assert self.lst is not None, "This shouldn't happen."
while 1:
item = self.lst[0]
if self.beforeBody and FORGET_IT in self.lst:
self.forgotten = 1
return
if isinstance(item, types.StringType):
self.beforeBody = 0
self.request.write(item)
elif type(item) is types.TupleType and len(item) > 0:
if isinstance(item[0], self.Sentinel):
return
elif isinstance(item, failure.Failure):
self.request.write(webutil.formatFailure(item))
else:
self.beforeBody = 0
unknown = html.PRE(repr(item))
self.request.write("RENDERING UNKNOWN: %s" % unknown)
del self.lst[0]
if len(self.lst) == 0:
self.lst = None
self.request.finish()
return
class WidgetResource(resource.Resource):
def __init__(self, widget):
self.widget = widget
resource.Resource.__init__(self)
def render(self, request):
RenderSession(self.widget.display(request), request)
return NOT_DONE_YET
class Page(resource.Resource, Presentation):
def __init__(self):
resource.Resource.__init__(self)
Presentation.__init__(self)
def render(self, request):
displayed = self.display(request)
RenderSession(displayed, request)
return NOT_DONE_YET
class WidgetPage(Page):
"""
I am a Page that takes a Widget in its constructor, and displays that
Widget wrapped up in a simple HTML template.
"""
stylesheet = '''
a
{
font-family: Lucida, Verdana, Helvetica, Arial, sans-serif;
color: #369;
text-decoration: none;
}
th
{
font-family: Lucida, Verdana, Helvetica, Arial, sans-serif;
font-weight: bold;
text-decoration: none;
text-align: left;
}
pre, code
{
font-family: "Courier New", Courier, monospace;
}
p, body, td, ol, ul, menu, blockquote, div
{
font-family: Lucida, Verdana, Helvetica, Arial, sans-serif;
color: #000;
}
'''
template = '''<html>
<head>
<title>%%%%self.title%%%%</title>
<style>
%%%%self.stylesheet%%%%
</style>
<base href="%%%%request.prePathURL()%%%%">
</head>
<body>
<h1>%%%%self.title%%%%</h1>
%%%%self.widget%%%%
</body>
</html>
'''
title = 'No Title'
widget = 'No Widget'
def __init__(self, widget):
Page.__init__(self)
self.widget = widget
if hasattr(widget, 'stylesheet'):
self.stylesheet = widget.stylesheet
def prePresent(self, request):
self.title = self.widget.getTitle(request)
def render(self, request):
displayed = self.display(request)
RenderSession(displayed, request)
return NOT_DONE_YET
class Gadget(resource.Resource):
"""I am a collection of Widgets, to be rendered through a Page Factory.
self.pageFactory should be a Resource that takes a Widget in its
constructor. The default is twisted.web.widgets.WidgetPage.
"""
isLeaf = 0
def __init__(self):
resource.Resource.__init__(self)
self.widgets = {}
self.files = []
self.modules = []
self.paths = {}
def render(self, request):
request.setResponseCode(http.FOUND)
request.setHeader("location","http%s://%s%s/" % (
request.isSecure() and 's' or '',
request.getHeader("host"),
(string.split(request.uri,'?')[0])))
return "NO DICE!"
def putWidget(self, path, widget):
"""
Gadget.putWidget(path, widget)
Add a Widget to this Gadget. It will be rendered through the
pageFactory associated with this Gadget, whenever 'path' is requested.
"""
self.widgets[path] = widget
def addFile(self, path):
"""
Gadget.addFile(path)
Add a static path to this Gadget. This method is obsolete, use
Gadget.putPath instead.
"""
log.msg("Gadget.addFile() is deprecated.")
self.paths[path] = path
def putPath(self, path, pathname):
"""
Gadget.putPath(path, pathname)
Add a static path to this Gadget. Whenever 'path' is requested,
twisted.web.static.File(pathname) is sent.
"""
self.paths[path] = pathname
def getWidget(self, path, request):
return self.widgets.get(path)
def pageFactory(self, *args, **kwargs):
"""
Gadget.pageFactory(*args, **kwargs) -> Resource
By default, this method returns self.page(*args, **kwargs). It
is only for backwards-compatibility -- you should set the 'pageFactory'
attribute on your Gadget inside of its __init__ method.
"""
if hasattr(self, "page"):
log.msg("Gadget.page is deprecated, use Gadget.pageFactory instead")
return apply(self.page, args, kwargs)
else:
return apply(WidgetPage, args, kwargs)
def getChild(self, path, request):
if path == '':
if isinstance(self, Widget):
return self.pageFactory(self)
widget = self.getWidget(path, request)
if widget:
if isinstance(widget, resource.Resource):
return widget
else:
p = self.pageFactory(widget)
p.isLeaf = getattr(widget,'isLeaf',0)
return p
elif self.paths.has_key(path):
prefix = getattr(sys.modules[self.__module__], '__file__', '')
if prefix:
prefix = os.path.abspath(os.path.dirname(prefix))
return static.File(os.path.join(prefix, self.paths[path]))
elif path == '__reload__':
return self.pageFactory(Reloader(map(reflect.namedModule, [self.__module__] + self.modules)))
else:
return error.NoResource("No such child resource in gadget.")
class TitleBox(Presentation):
template = '''\
<table %%%%self.widthOption%%%% cellpadding="1" cellspacing="0" border="0"><tr>\
<td bgcolor="%%%%self.borderColor%%%%"><center><font color="%%%%self.titleTextColor%%%%">%%%%self.title%%%%</font></center>\
<table width="100%" cellpadding="3" cellspacing="0" border="0"><tr>\
<td bgcolor="%%%%self.boxColor%%%%"><font color="%%%%self.boxTextColor%%%%">%%%%self.widget%%%%</font></td>\
</tr></table></td></tr></table>\
'''
borderColor = '#000000'
titleTextColor = '#ffffff'
boxTextColor = '#000000'
boxColor = '#ffffff'
widthOption = 'width="100%"'
title = 'No Title'
widget = 'No Widget'
def __init__(self, title, widget):
"""Wrap a widget with a given title.
"""
self.widget = widget
self.title = title
Presentation.__init__(self)
class Reloader(Presentation):
template = '''
Reloading...
<ul>
%%%%reload(request)%%%%
</ul> ... reloaded!
'''
def __init__(self, modules):
Presentation.__init__(self)
self.modules = modules
def reload(self, request):
request.redirect("..")
x = []
write = x.append
for module in self.modules:
rebuild.rebuild(module)
write('<li>reloaded %s<br />' % module.__name__)
return x
class Sidebar(StreamWidget):
bar = [
['Twisted',
['mirror', 'http://coopweb.org/ssd/twisted/'],
['mailing list', 'cgi-bin/mailman/listinfo/twisted-python']
]
]
headingColor = 'ffffff'
headingTextColor = '000000'
activeHeadingColor = '000000'
activeHeadingTextColor = 'ffffff'
sectionColor = '000088'
sectionTextColor = '008888'
activeSectionColor = '0000ff'
activeSectionTextColor = '00ffff'
def __init__(self, highlightHeading, highlightSection):
self.highlightHeading = highlightHeading
self.highlightSection = highlightSection
def getList(self):
return self.bar
def stream(self, write, request):
write("<table width=120 cellspacing=1 cellpadding=1 border=0>")
for each in self.getList():
if each[0] == self.highlightHeading:
headingColor = self.activeHeadingColor
headingTextColor = self.activeHeadingTextColor
canHighlight = 1
else:
headingColor = self.headingColor
headingTextColor = self.headingTextColor
canHighlight = 0
write('<tr><td colspan=2 bgcolor="#%s"><font color="%s">'
'<strong>%s</strong>'
'</font></td></td></tr>\n' % (headingColor, headingTextColor, each[0]))
for name, link in each[1:]:
if canHighlight and (name == self.highlightSection):
sectionColor = self.activeSectionColor
sectionTextColor = self.activeSectionTextColor
else:
sectionColor = self.sectionColor
sectionTextColor = self.sectionTextColor
write('<tr><td align=right bgcolor="#%s" width=6>-</td>'
'<td bgcolor="#%s"><a href="%s"><font color="#%s">%s'
'</font></a></td></tr>'
% (sectionColor, sectionColor, request.sibLink(link), sectionTextColor, name))
write("</table>")
from twisted.web.woven import template
from twisted.python import components
class WebWidgetNodeMutator(template.NodeMutator):
"""A WebWidgetNodeMutator replaces the node that is passed in to generate
with the result of generating the twisted.web.widget instance it adapts.
"""
def generate(self, request, node):
widget = self.data
displayed = widget.display(request)
try:
html = string.join(displayed)
except:
pr = Presentation()
pr.tmpl = displayed
html = string.join(displayed)
stringMutator = template.StringNodeMutator(html)
return stringMutator.generate(request, node)
components.registerAdapter(WebWidgetNodeMutator, Widget, template.INodeMutator)
import static