form.py :  » Network » Twisted » Twisted-1.0.3 » Twisted-1.0.3 » twisted » web » woven » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Network » Twisted 
Twisted » Twisted 1.0.3 » Twisted 1.0.3 » twisted » web » woven » form.py
# -*- test-case-name: twisted.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,getAdapter
from twisted.web import domhelpers,resource
from twisted.internet import defer

# Sibling Imports
from twisted.web.woven import model,view,controller,widgets,input,interfaces,tapestry

from twisted.web.microdom import parseString,lmx


# 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

    
def getValue(request, argument):
    """Return value for form inpurt."""
    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(request, argument):
    """Return values for form inpurt."""
    values = request.args.get(argument.name, None)
    if values:
        try:
            return argument.coerce(values)
        except formmethod.InputError:
            return values
    return argument.default


class FormFillerWidget(widgets.Widget):

    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, arg):
        value = getValue(request, arg)
        if value == None:
            value = ""
        else:
            value = str(value)
        return content.input(type="text",
                             size="60",
                             name=arg.name,
                             value=value)

    def input_text(self, request, content, arg):
        r = content.textarea(cols="60",
                             rows="10",
                             name=arg.name,
                             wrap="virtual")
        r.text(str(getValue(request, arg)))
        return r

    input_integer = input_single
    input_string = input_single
    input_float = input_single

    def input_choice(self, request, content, arg):
        s = content.select(name=arg.name)
        default = getValue(request, arg)
        for tag, value, desc in arg.choices:
            if value == default:
                kw = {'selected' : '1'}
            else:
                kw = {}
            s.option(value=tag, **kw).text(desc)
        return s

    def input_radiogroup(self, request, content, arg):
        s = content.div()
        defaults = getValues(request, arg)
        for tag, value, desc in arg.choices:
            if value in defaults:
                kw = {'checked' : '1'}
            else:
                kw = {}
            s.div().input(name=arg.name,
                          type="radio", **kw).text(desc)
        return s

    def input_checkgroup(self, request, content, arg):
        s = content.div()
        defaults = getValues(request, arg)
        for tag, value, desc in arg.choices:
            if value in defaults:
                kw = {'checked' : '1'}
            else:
                kw = {}
            s.input(type="checkbox",
                    name=arg.name,
                    value=tag, **kw).text(desc)
        return s

    def input_boolean(self, request, content, arg):
        if getValue(request, arg):
            kw = {'checked' : '1'}
        else:
            kw = {}
        i = content.input(type="checkbox",
                          name=arg.name, **kw)
        return i

    def input_password(self, request, content, arg):
        return content.input(type="password",
                             size="60",
                             name=arg.name)

    def input_flags(self, request, content, arg):
        defaults = getValues(request, arg)
        for key, val, label in arg.flags:
            if val in defaults:
                kw = {'checked' : '1'}
            else:
                kw = {}
            nn = content.input(type="checkbox",
                               name=arg.name,
                               value=str(key), **kw)
            nn.text(label)
        return content

    def input_hidden(self, request, content, arg):
        return content.input(type="hidden",
                             name=arg.name,
                             value=getValue(request, arg))

    def input_submit(self, request, content, arg):
        div = content.div()
        for tag, value, desc in arg.choices:
            div.input(type="submit", name=arg.name, value=tag)
            div.text(" ")
        if arg.reset:
            div.input(type="reset")
        return div

    def input_date(self, request, content, arg):
        year, month, day = getValues(request, arg)
        div = content.div()
        div.text("Year: ")
        div.input(type="text", size="4", maxlength="4", name=arg.name, value=str(year))
        div.br()
        div.text("Month: ")
        div.input(type="text", size="2", maxlength="2", name=arg.name, value=str(month))
        div.br()
        div.text("Day: ")
        div.input(type="text", size="2", maxlength="2", name=arg.name, value=str(day))
        return div
    
    def createInput(self, request, shell, arg):
        name = arg.__class__.__name__.lower()
        if _renderers.has_key(arg.__class__):
            imeth = _renderers[arg.__class__]
        else:
            imeth = getattr(self,"input_"+name)
        if name == "hidden":
            return (imeth(request, shell, arg).node, lmx())
        elif name == "submit":
            td = shell.tr().td(valign="top", colspan="2")
            return (imeth(request, td, arg).node, lmx())
        else:
            tr = shell.tr()
            tr.td(align="right", valign="top").text(arg.getShortDescription()+":")
            content = tr.td(valign="top")
            return (imeth(request, content, arg).node,
                    content.div(style="color: green").
                    text(arg.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
        for inNode in domhelpers.getElementsByTagName(node, 'input'):
            if inNode.getAttribute("type").lower() == "submit":
                hasSubmit = 1
            nName = inNode.getAttribute("name")
            assert argz.has_key(nName), "method signature %s does not define argument %s" % (self.model.original, nName)
            inputNodes[nName] = inNode
            del argz[nName]
        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]
            for n in en, tn:
                n.setAttribute('style', "color: red")
            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):
        self.fmethod = fmethod

class FormErrorModel(FormDisplayModel):
    def initialize(self, fmethod, args, err):
        FormDisplayModel.initialize(self, fmethod)
        self.args = args
        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):
        return str(self.desc)


class ThankYou(view.View):
    template = '''
    <html>
    <head>
    <title> Thank You </title>
    </head>
    <body>
    <h1>Thank You for Using Woven</h1>
    <div model=".">
    </div>
    </body>
    </html>
    '''


class FormProcessor(resource.Resource):
    def __init__(self, formMethod, callback=None, errback=None):
        self.formMethod = formMethod
        if callback is None:
            callback = self.viewFactory
        self.callback = callback
        if errback is None:
            errback = self.errorViewFactory
        self.errback = errback

    def render(self, request):
        outDict = {}
        errDict = {}
        for methodArg in self.formMethod.getArgs():
            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:
                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:
                if isinstance(outObj, defer.Deferred):
                    def _cbModel(result):
                        return self.callback(self.modelFactory(result))
                    def _ebModel(err):
                        if err.trap(formmethod.FormException):
                            mf = self.errorModelFactory(request.args, outDict, err.value)
                            return self.errback(mf)
                        raise err
                    outObj.addCallback(_cbModel).addErrback(_ebModel)
                    return tapestry._ChildJuggler(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>
        </head>
        <body>
        Error: <span model="description" />
        <form model=".">
        </form>
        </body>
        </html>
        '''
        return v

    def modelFactory(self, outObj):
        adapt = getAdapter(outObj, interfaces.IModel, outObj)
        # print 'factorizing', adapt
        return adapt

    def viewFactory(self, model):
        # return getAdapter(model, interfaces.IView)
        return ThankYou(model)

    # mangliezrs

    def mangle_single(self, args):
        if args:
            return args[0]
        else:
            return ''

    mangle_string = mangle_single
    mangle_password = mangle_single
    mangle_text = mangle_single
    mangle_integer = mangle_single
    mangle_float = mangle_single
    mangle_choice = mangle_single
    mangle_boolean = mangle_single
    mangle_hidden = mangle_single
    mangle_submit = mangle_single
    
    def mangle_flags(self, args):
        if args is None:
            return []
        return args

from twisted.python.formmethod import FormMethod

view.registerViewForModel(FormFillerWidget, FormDisplayModel)
view.registerViewForModel(FormErrorWidget, FormErrorModel)
registerAdapter(FormDisplayModel, FormMethod, interfaces.IModel)

www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.