| Index: third_party/twisted_8_1/twisted/web/widgets.py
|
| diff --git a/third_party/twisted_8_1/twisted/web/widgets.py b/third_party/twisted_8_1/twisted/web/widgets.py
|
| deleted file mode 100644
|
| index de2af70c8809b201294579d1c757ed5a86c25b75..0000000000000000000000000000000000000000
|
| --- a/third_party/twisted_8_1/twisted/web/widgets.py
|
| +++ /dev/null
|
| @@ -1,1050 +0,0 @@
|
| -# -*- test-case-name: twisted.web.test.test_web -*-
|
| -#
|
| -# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
|
| -# See LICENSE for details.
|
| -
|
| -
|
| -"""A twisted web component framework.
|
| -
|
| -This module is DEPRECATED.
|
| -"""
|
| -
|
| -import warnings
|
| -warnings.warn("This module is deprecated, please use Woven instead.", DeprecationWarning)
|
| -
|
| -# System Imports
|
| -import string, time, types, traceback, pprint, sys, os
|
| -import linecache
|
| -import re
|
| -from cStringIO import StringIO
|
| -
|
| -# Twisted Imports
|
| -from twisted.python import failure, log, rebuild, reflect, util
|
| -from twisted.internet import defer
|
| -from twisted.web import http
|
| -
|
| -# Sibling Imports
|
| -import html, resource, error
|
| -import util as webutil
|
| -
|
| -#backwards compatibility
|
| -from util import formatFailure, htmlrepr, htmlUnknown, htmlDict, htmlList,\
|
| - htmlInst, htmlString, htmlReprTypes
|
| -
|
| -
|
| -
|
| -from server import NOT_DONE_YET
|
| -
|
| -True = (1==1)
|
| -False = not True
|
| -
|
| -
|
| -# magic value that sez a widget needs to take over the whole page.
|
| -
|
| -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__:
|
| - # Traverse only superclasses that know about Presentation.
|
| - if issubclass(base, Presentation) and base is not Presentation:
|
| - self.addClassVars(namespace, base)
|
| - # 'lower' classes in the class heirarchy take precedence.
|
| - 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)
|
| - # This variable may not be obscured...
|
| - 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:
|
| - # Only two allowed types here should be deferred and
|
| - # string.
|
| - 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 = [
|
| - ]
|
| -
|
| - # do we raise an error when we get extra args or not?
|
| - 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 # there are arguments to the request
|
| - args.has_key('__formtype__') and # this is a widgets.Form request
|
| - args['__formtype__'][0] == reflect.qual(self.__class__) and # it is for a form of my type
|
| - ((not fid) or # I am only allowed one form per page
|
| - (args.has_key('__formid__') and # if I distinguish myself from others, the request must too
|
| - args['__formid__'][0] == fid))) # I am in fact the same
|
| -
|
| - 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):
|
| - # web in my head get it out get it out
|
| - try:
|
| - disp = widget.display(request)
|
| - # if this widget wants to defer anything -- well, I guess we've got to
|
| - # defer it.
|
| - 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'):
|
| - # You might want to set a header from a deferred, in which
|
| - # case you have to set an attribute -- 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]
|
| -
|
| - # Make sure result is a sequence,
|
| - if not type(result) in (types.ListType, types.TupleType):
|
| - result = [result]
|
| -
|
| - # If the deferred does not wish to produce its result all at
|
| - # once, it can give us a partial result as
|
| - # (NOT_DONE_YET, partial_result)
|
| - ## XXX: How would a deferred go about producing the result in multiple
|
| - ## stages?? --glyph
|
| - 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:
|
| - # short circuit actual rendering process until we're sure no
|
| - # more deferreds need to set headers...
|
| - 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:
|
| - # If I haven't moved yet, and the widget wants to take
|
| - # over the page, let it do so!
|
| - 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
|
| -
|
| -
|
| -## XXX: is this needed?
|
| -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):
|
| - #Redirect to view this entity as a collection.
|
| - request.setResponseCode(http.FOUND)
|
| - # TODO who says it's not https?
|
| - 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
|
| -
|
| - #this is an obsolete function
|
| - 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.
|
| - """
|
| - #XXX: delete this after a while.
|
| - 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 == '':
|
| - # ZOOP!
|
| - 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>")
|
| -
|
| -# moved from template.py
|
| -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
|
| - #strList = pr.display(request)
|
| - html = string.join(displayed)
|
| - stringMutator = template.StringNodeMutator(html)
|
| - return stringMutator.generate(request, node)
|
| -
|
| -components.registerAdapter(WebWidgetNodeMutator, Widget, template.INodeMutator)
|
| -
|
| -import static
|
|
|