Index: third_party/twisted_8_1/twisted/web/woven/form.py |
diff --git a/third_party/twisted_8_1/twisted/web/woven/form.py b/third_party/twisted_8_1/twisted/web/woven/form.py |
deleted file mode 100644 |
index 749d0d8e1cdd3de086716c9e4b142131bcb22b16..0000000000000000000000000000000000000000 |
--- a/third_party/twisted_8_1/twisted/web/woven/form.py |
+++ /dev/null |
@@ -1,575 +0,0 @@ |
-# -*- test-case-name: twisted.web.test.test_woven -*- |
-# |
-# WORK IN PROGRESS: HARD HAT REQUIRED |
-# |
- |
-from __future__ import nested_scopes |
- |
-# Twisted Imports |
- |
-from twisted.python import formmethod, failure |
-from twisted.python.components import registerAdapter |
-from twisted.web import domhelpers, resource, util |
-from twisted.internet import defer |
- |
-# Sibling Imports |
-from twisted.web.woven import model, view, controller, widgets, input, interfaces |
- |
-from twisted.web.microdom import parseString, lmx, Element |
- |
- |
-#other imports |
-import math |
- |
-# map formmethod.Argument to functions that render them: |
-_renderers = {} |
- |
-def registerRenderer(argumentClass, renderer): |
- """Register a renderer for a given argument class. |
- |
- The renderer function should act in the same way |
- as the 'input_XXX' methods of C{FormFillerWidget}. |
- """ |
- assert callable(renderer) |
- global _renderers |
- _renderers[argumentClass] = renderer |
- |
- |
-class FormFillerWidget(widgets.Widget): |
- |
- SPANNING_TYPES = ["hidden", "submit"] |
- |
- def getValue(self, request, argument): |
- """Return value for form input.""" |
- if not self.model.alwaysDefault: |
- values = request.args.get(argument.name, None) |
- if values: |
- try: |
- return argument.coerce(values[0]) |
- except formmethod.InputError: |
- return values[0] |
- return argument.default |
- |
- def getValues(self, request, argument): |
- """Return values for form input.""" |
- if not self.model.alwaysDefault: |
- values = request.args.get(argument.name, None) |
- if values: |
- try: |
- return argument.coerce(values) |
- except formmethod.InputError: |
- return values |
- return argument.default |
- |
- def createShell(self, request, node, data): |
- """Create a `shell' node that will hold the additional form |
- elements, if one is required. |
- """ |
- return lmx(node).table(border="0") |
- |
- def input_single(self, request, content, model, templateAttributes={}): |
- """ |
- Returns a text input node built based upon the node model. |
- Optionally takes an already-coded DOM node merges that |
- information with the model's information. Returns a new (??) |
- lmx node. |
- """ |
- #in a text field, only the following options are allowed (well, more |
- #are, but they're not supported yet - can add them in later) |
- attribs = ['type', 'name', 'value', 'size', 'maxlength', |
- 'readonly'] #only MSIE recognizes readonly and disabled |
- |
- arguments = {} |
- for attrib in attribs: |
- #model hints and values override anything in the template |
- val = model.getHint(attrib, templateAttributes.get(attrib, None)) |
- if val: |
- arguments[attrib] = str(val) |
- |
- value = self.getValue(request, model) |
- if value: |
- arguments["value"] = str(value) |
- |
- arguments["type"] = "text" #these are default |
- arguments["name"] = model.name |
- |
- return content.input(**arguments) |
- |
- def input_string(self, request, content, model, templateAttributes={}): |
- if not templateAttributes.has_key("size"): |
- templateAttributes["size"] = '60' |
- return self.input_single(request, content, model, templateAttributes) |
- |
- input_integer = input_single |
- input_integerrange = input_single |
- input_float = input_single |
- |
- def input_text(self, request, content, model, templateAttributes={}): |
- r = content.textarea( |
- cols=str(model.getHint('cols', |
- templateAttributes.get('cols', '60'))), |
- rows=str(model.getHint('rows', |
- templateAttributes.get('rows', '10'))), |
- name=model.name, |
- wrap=str(model.getHint('wrap', |
- templateAttributes.get('wrap', "virtual")))) |
- r.text(str(self.getValue(request, model))) |
- return r |
- |
- def input_hidden(self, request, content, model, templateAttributes={}): |
- return content.input(type="hidden", |
- name=model.name, |
- value=str(self.getValue(request, model))) |
- |
- def input_submit(self, request, content, model, templateAttributes={}): |
- arguments = {} |
- val = model.getHint("onClick", templateAttributes.get("onClick", None)) |
- if val: |
- arguments["onClick"] = val |
- arguments["type"] = "submit" |
- arguments["name"] = model.name |
- div = content.div() |
- for tag, value, desc in model.choices: |
- args = arguments.copy() |
- args["value"] = tag |
- div.input(**args) |
- div.text(" ") |
- if model.reset: |
- div.input(type="reset") |
- return div |
- |
- def input_choice(self, request, content, model, templateAttributes={}): |
- # am I not evil? allow onChange js events |
- arguments = {} |
- val = model.getHint("onChange", templateAttributes.get("onChange", None)) |
- if val: |
- arguments["onChange"] = val |
- arguments["name"] = model.name |
- s = content.select(**arguments) |
- default = self.getValues(request, model) |
- for tag, value, desc in model.choices: |
- kw = {} |
- if value in default: |
- kw = {'selected' : '1'} |
- s.option(value=tag, **kw).text(desc) |
- return s |
- |
- def input_group(self, request, content, model, groupValues, inputType, |
- templateAttributes={}): |
- """ |
- Base code for a group of objects. Checkgroup will use this, as |
- well as radiogroup. In the attributes, rows means how many rows |
- the group should be arranged into, cols means how many cols the |
- group should be arranged into. Columns take precedence over |
- rows: if both are specified, the output will always generate the |
- correct number of columns. However, if the number of elements |
- in the group exceed (or is smaller than) rows*cols, then the |
- number of rows will be off. A cols attribute of 1 will mean that |
- all the elements will be listed one underneath another. The |
- default is a rows attribute of 1: everything listed next to each |
- other. |
- """ |
- rows = model.getHint('rows', templateAttributes.get('rows', None)) |
- cols = model.getHint('cols', templateAttributes.get('cols', None)) |
- if rows: |
- rows = int(rows) |
- if cols: |
- cols = int(cols) |
- |
- defaults = self.getValues(request, model) |
- if (rows and rows>1) or (cols and cols>1): #build a table |
- s = content.table(border="0") |
- if cols: |
- breakat = cols |
- else: |
- breakat = math.ceil(float(len(groupValues))/rows) |
- for i in range(0, len(groupValues), breakat): |
- tr = s.tr() |
- for j in range(0, breakat): |
- if i+j >= len(groupValues): |
- break |
- tag, value, desc = groupValues[i+j] |
- kw = {} |
- if value in defaults: |
- kw = {'checked' : '1'} |
- tr.td().input(type=inputType, name=model.name, |
- value=tag, **kw).text(desc) |
- |
- else: |
- s = content.div() |
- for tag, value, desc in groupValues: |
- kw = {} |
- if value in defaults: |
- kw = {'checked' : '1'} |
- s.input(type=inputType, name=model.name, |
- value=tag, **kw).text(desc) |
- if cols: |
- s.br() |
- |
- return s |
- |
- def input_checkgroup(self, request, content, model, templateAttributes={}): |
- return self.input_group(request, content, model, model.flags, |
- "checkbox", templateAttributes) |
- |
- def input_radiogroup(self, request, content, model, templateAttributes={}): |
- return self.input_group(request, content, model, model.choices, |
- "radio", templateAttributes) |
- |
- #I don't know why they're the same, but they were. So I removed the |
- #excess code. Maybe someone should look into removing it entirely. |
- input_flags = input_checkgroup |
- |
- def input_boolean(self, request, content, model, templateAttributes={}): |
- kw = {} |
- if self.getValue(request, model): |
- kw = {'checked' : '1'} |
- return content.input(type="checkbox", name=model.name, **kw) |
- |
- def input_file(self, request, content, model, templateAttributes={}): |
- kw = {} |
- for attrib in ['size', 'accept']: |
- val = model.getHint(attrib, templateAttributes.get(attrib, None)) |
- if val: |
- kw[attrib] = str(val) |
- return content.input(type="file", name=model.name, **kw) |
- |
- def input_date(self, request, content, model, templateAttributes={}): |
- breakLines = model.getHint('breaklines', 1) |
- date = self.getValues(request, model) |
- if date == None: |
- year, month, day = "", "", "" |
- else: |
- year, month, day = date |
- div = content.div() |
- div.text("Year: ") |
- div.input(type="text", size="4", maxlength="4", name=model.name, value=str(year)) |
- if breakLines: |
- div.br() |
- div.text("Month: ") |
- div.input(type="text", size="2", maxlength="2", name=model.name, value=str(month)) |
- if breakLines: |
- div.br() |
- div.text("Day: ") |
- div.input(type="text", size="2", maxlength="2", name=model.name, value=str(day)) |
- return div |
- |
- def input_password(self, request, content, model, templateAttributes={}): |
- return content.input( |
- type="password", |
- size=str(templateAttributes.get('size', "60")), |
- name=model.name) |
- |
- def input_verifiedpassword(self, request, content, model, templateAttributes={}): |
- breakLines = model.getHint('breaklines', 1) |
- values = self.getValues(request, model) |
- if isinstance(values, (str, unicode)): |
- values = (values, values) |
- if not values: |
- p1, p2 = "", "" |
- elif len(values) == 1: |
- p1, p2 = values, "" |
- elif len(values) == 2: |
- p1, p2 = values |
- else: |
- p1, p2 = "", "" |
- div = content.div() |
- div.text("Password: ") |
- div.input(type="password", size="20", name=model.name, value=str(p1)) |
- if breakLines: |
- div.br() |
- div.text("Verify: ") |
- div.input(type="password", size="20", name=model.name, value=str(p2)) |
- return div |
- |
- |
- def convergeInput(self, request, content, model, templateNode): |
- name = model.__class__.__name__.lower() |
- if _renderers.has_key(model.__class__): |
- imeth = _renderers[model.__class__] |
- else: |
- imeth = getattr(self,"input_"+name) |
- |
- return imeth(request, content, model, templateNode.attributes).node |
- |
- def createInput(self, request, shell, model, templateAttributes={}): |
- name = model.__class__.__name__.lower() |
- if _renderers.has_key(model.__class__): |
- imeth = _renderers[model.__class__] |
- else: |
- imeth = getattr(self,"input_"+name) |
- if name in self.SPANNING_TYPES: |
- td = shell.tr().td(valign="top", colspan="2") |
- return (imeth(request, td, model).node, shell.tr().td(colspan="2").node) |
- else: |
- if model.allowNone: |
- required = "" |
- else: |
- required = " *" |
- tr = shell.tr() |
- tr.td(align="right", valign="top").text(model.getShortDescription()+":"+required) |
- content = tr.td(valign="top") |
- return (imeth(request, content, model).node, |
- content.div(_class="formDescription"). # because class is a keyword |
- text(model.getLongDescription()).node) |
- |
- def setUp(self, request, node, data): |
- # node = widgets.Widget.generateDOM(self,request,node) |
- lmn = lmx(node) |
- if not node.hasAttribute('action'): |
- lmn['action'] = (request.prepath+request.postpath)[-1] |
- if not node.hasAttribute("method"): |
- lmn['method'] = 'post' |
- lmn['enctype'] = 'multipart/form-data' |
- self.errorNodes = errorNodes = {} # name: nodes which trap errors |
- self.inputNodes = inputNodes = {} |
- for errorNode in domhelpers.findElementsWithAttribute(node, 'errorFor'): |
- errorNodes[errorNode.getAttribute('errorFor')] = errorNode |
- argz={} |
- # list to figure out which nodes are in the template already and which aren't |
- hasSubmit = 0 |
- argList = self.model.fmethod.getArgs() |
- for arg in argList: |
- if isinstance(arg, formmethod.Submit): |
- hasSubmit = 1 |
- argz[arg.name] = arg |
- inNodes = domhelpers.findElements( |
- node, |
- lambda n: n.tagName.lower() in ('textarea', 'select', 'input', |
- 'div')) |
- for inNode in inNodes: |
- t = inNode.getAttribute("type") |
- if t and t.lower() == "submit": |
- hasSubmit = 1 |
- if not inNode.hasAttribute("name"): |
- continue |
- nName = inNode.getAttribute("name") |
- if argz.has_key(nName): |
- #send an empty content shell - we just want the node |
- inputNodes[nName] = self.convergeInput(request, lmx(), |
- argz[nName], inNode) |
- inNode.parentNode.replaceChild(inputNodes[nName], inNode) |
- del argz[nName] |
- # TODO: |
- # * some arg types should only have a single node (text, string, etc) |
- # * some should have multiple nodes (choice, checkgroup) |
- # * some have a bunch of ancillary nodes that are possible values (menu, radiogroup) |
- # these should all be taken into account when walking through the template |
- if argz: |
- shell = self.createShell(request, node, data) |
- # create inputs, in the same order they were passed to us: |
- for remArg in [arg for arg in argList if argz.has_key(arg.name)]: |
- inputNode, errorNode = self.createInput(request, shell, remArg) |
- errorNodes[remArg.name] = errorNode |
- inputNodes[remArg.name] = inputNode |
- |
- if not hasSubmit: |
- lmn.input(type="submit") |
- |
- |
-class FormErrorWidget(FormFillerWidget): |
- def setUp(self, request, node, data): |
- FormFillerWidget.setUp(self, request, node, data) |
- for k, f in self.model.err.items(): |
- en = self.errorNodes[k] |
- tn = self.inputNodes[k] |
- en.setAttribute('class', 'formError') |
- tn.setAttribute('class', 'formInputError') |
- en.childNodes[:]=[] # gurfle, CLEAR IT NOW!@# |
- if isinstance(f, failure.Failure): |
- f = f.getErrorMessage() |
- lmx(en).text(str(f)) |
- |
- |
-class FormDisplayModel(model.MethodModel): |
- def initialize(self, fmethod, alwaysDefault=False): |
- self.fmethod = fmethod |
- self.alwaysDefault = alwaysDefault |
- |
-class FormErrorModel(FormDisplayModel): |
- def initialize(self, fmethod, args, err): |
- FormDisplayModel.initialize(self, fmethod) |
- self.args = args |
- if isinstance(err, failure.Failure): |
- err = err.value |
- if isinstance(err, Exception): |
- self.err = getattr(err, "descriptions", {}) |
- self.desc = err |
- else: |
- self.err = err |
- self.desc = "Please try again" |
- |
- def wmfactory_description(self, request): |
- return str(self.desc) |
- |
-class _RequestHack(model.MethodModel): |
- def wmfactory_hack(self, request): |
- rv = [[str(a), repr(b)] for (a, b) |
- in request._outDict.items()] |
- #print 'hack', rv |
- return rv |
- |
-class FormProcessor(resource.Resource): |
- def __init__(self, formMethod, callback=None, errback=None): |
- resource.Resource.__init__(self) |
- self.formMethod = formMethod |
- if callback is None: |
- callback = self.viewFactory |
- self.callback = callback |
- if errback is None: |
- errback = self.errorViewFactory |
- self.errback = errback |
- |
- def getArgs(self, request): |
- """Return the formmethod.Arguments. |
- |
- Overridable hook to allow pre-processing, e.g. if we want to enable |
- on them depending on one of the inputs. |
- """ |
- return self.formMethod.getArgs() |
- |
- def render(self, request): |
- outDict = {} |
- errDict = {} |
- for methodArg in self.getArgs(request): |
- valmethod = getattr(self,"mangle_"+ |
- (methodArg.__class__.__name__.lower()), None) |
- tmpval = request.args.get(methodArg.name) |
- if valmethod: |
- # mangle the argument to a basic datatype that coerce will like |
- tmpval = valmethod(tmpval) |
- # coerce it |
- try: |
- cv = methodArg.coerce(tmpval) |
- outDict[methodArg.name] = cv |
- except: |
- errDict[methodArg.name] = failure.Failure() |
- if errDict: |
- # there were problems processing the form |
- return self.errback(self.errorModelFactory( |
- request.args, outDict, errDict)).render(request) |
- else: |
- try: |
- if self.formMethod.takesRequest: |
- outObj = self.formMethod.call(request=request, **outDict) |
- else: |
- outObj = self.formMethod.call(**outDict) |
- except formmethod.FormException, e: |
- err = request.errorInfo = self.errorModelFactory( |
- request.args, outDict, e) |
- return self.errback(err).render(request) |
- else: |
- request._outDict = outDict # CHOMP CHOMP! |
- # I wanted better default behavior for debugging, so I could |
- # see the arguments passed, but there is no channel for this in |
- # the existing callback structure. So, here it goes. |
- if isinstance(outObj, defer.Deferred): |
- def _ebModel(err): |
- if err.trap(formmethod.FormException): |
- mf = self.errorModelFactory(request.args, outDict, |
- err.value) |
- return self.errback(mf) |
- raise err |
- (outObj |
- .addCallback(self.modelFactory) |
- .addCallback(self.callback) |
- .addErrback(_ebModel)) |
- return util.DeferredResource(outObj).render(request) |
- else: |
- return self.callback(self.modelFactory(outObj)).render( |
- request) |
- |
- def errorModelFactory(self, args, out, err): |
- return FormErrorModel(self.formMethod, args, err) |
- |
- def errorViewFactory(self, m): |
- v = view.View(m) |
- v.template = ''' |
- <html> |
- <head> |
- <title> Form Error View </title> |
- <style> |
- .formDescription {color: green} |
- .formError {color: red; font-weight: bold} |
- .formInputError {color: #900} |
- </style> |
- </head> |
- <body> |
- Error: <span model="description" /> |
- <form model="."> |
- </form> |
- </body> |
- </html> |
- ''' |
- return v |
- |
- def modelFactory(self, outObj): |
- adapt = interfaces.IModel(outObj, outObj) |
- # print 'factorizing', adapt |
- return adapt |
- |
- def viewFactory(self, model): |
- # return interfaces.IView(model) |
- if model is None: |
- bodyStr = ''' |
- <table model="hack" style="background-color: #99f"> |
- <tr pattern="listItem" view="Widget"> |
- <td model="0" style="font-weight: bold"> |
- </td> |
- <td model="1"> |
- </td> |
- </tr> |
- </table> |
- ''' |
- model = _RequestHack() |
- else: |
- bodyStr = '<div model="." />' |
- v = view.View(model) |
- v.template = ''' |
- <html> |
- <head> |
- <title> Thank You </title> |
- </head> |
- <body> |
- <h1>Thank You for Using Woven</h1> |
- %s |
- </body> |
- </html> |
- ''' % bodyStr |
- return v |
- |
- # manglizers |
- |
- def mangle_single(self, args): |
- if args: |
- return args[0] |
- else: |
- return '' |
- |
- mangle_string = mangle_single |
- mangle_text = mangle_single |
- mangle_integer = mangle_single |
- mangle_password = mangle_single |
- mangle_integerrange = mangle_single |
- mangle_float = mangle_single |
- mangle_choice = mangle_single |
- mangle_boolean = mangle_single |
- mangle_hidden = mangle_single |
- mangle_submit = mangle_single |
- mangle_file = mangle_single |
- mangle_radiogroup = mangle_single |
- |
- def mangle_multi(self, args): |
- if args is None: |
- return [] |
- return args |
- |
- mangle_checkgroup = mangle_multi |
- mangle_flags = mangle_multi |
- |
-from twisted.python.formmethod import FormMethod |
- |
-view.registerViewForModel(FormFillerWidget, FormDisplayModel) |
-view.registerViewForModel(FormErrorWidget, FormErrorModel) |
-registerAdapter(FormDisplayModel, FormMethod, interfaces.IModel) |
- |