Beispiel #1
0
class Form(AddHelperMixin, object):

    implements( iformal.IForm )

    callback = None
    actions = None

    def __init__(self, callback=None):
        if callback is not None:
            self.callback = callback
        self.resourceManager = ResourceManager()
        self.data = {}
        self.items = FormItems(None)
        self.errors = FormErrors()
        # Forward to FormItems methods
        self.add = self.items.add
        self.addLast = self.items.addLast
        self.addFirst = self.items.addFirst
        self.addBefore = self.items.addBefore
        self.addAfter = self.items.addAfter
        self.getItemByName = self.items.getItemByName


    def addAction(self, callback, name="submit", validate=True, label=None):
        if self.actions is None:
            self.actions = []
        if name in [action.name for action in self.actions]:
            raise ValueError('Action with name %r already exists.' % name)
        self.actions.append( Action(callback, name, validate, label) )

    def process(self, ctx):

        request = inevow.IRequest(ctx)
        charset = getPOSTCharset(ctx)

        # Get the request args and decode the arg names
        args = dict([(k.decode(charset),v) for k,v in request.args.items()])

        # Find the callback to use, defaulting to the form default
        callback, validate = self.callback, True
        if self.actions is not None:
            for action in self.actions:
                if action.name in args:
                    # Remove it from the data
                    args.pop(action.name)
                    # Remember the callback and whether to validate
                    callback, validate = action.callback, action.validate
                    break

        # IE does not send a button name in the POST args for forms containing
        # a single field when the user presses <enter> to submit the form. If
        # we only have one possible action then we can safely assume that's the
        # action to take.
        #
        # If there are 0 or 2+ actions then we can't assume anything because we
        # have no idea what order the buttons are on the page (someone might
        # have altered the DOM using JavaScript for instance). In that case
        # throw an error and make it a problem for the developer.
        if callback is None:
            if self.actions is None or len(self.actions) != 1:
                raise Exception('The form has no callback and no action was found.')
            else:
                callback, validate = self.actions[0].callback, \
                        self.actions[0].validate

        # Remember the args in case validation fails.
        self.errors.data = args

        def _cbProcessingDone(_):
            if self.errors and validate:
                return self.errors

            def _clearUpResources( r ):
                if not self.errors:
                    self.resourceManager.clearUpResources()
                return r

            d = defer.maybeDeferred(callback, ctx, self, self.data)
            d.addCallback( _clearUpResources )
            d.addErrback(self._cbFormProcessingFailed, ctx)
            return d

        # Iterate the items and collect the form data and/or errors.
        dl = []
        for item in self.items:
            dl.append(defer.maybeDeferred(item.process, ctx, self, args, self.errors))

        d = defer.gatherResults(dl)
        d.addCallback(_cbProcessingDone)
        return d

    def _cbFormProcessingFailed(self, failure, ctx):
        e = failure.value
        failure.trap(validation.FormError, validation.FieldError)
        self.errors.add(failure.value)
        return self.errors
Beispiel #2
0
class Form(AddHelperMixin, object):

    implements(iformal.IForm)

    callback = None
    actions = None

    def __init__(self, callback=None):
        if callback is not None:
            self.callback = callback
        self.resourceManager = ResourceManager()
        self.data = {}
        self.items = FormItems(None)
        self.errors = FormErrors()
        # Forward to FormItems methods
        self.add = self.items.add
        self.getItemByName = self.items.getItemByName

    def addAction(self, callback, name="submit", validate=True, label=None):
        if self.actions is None:
            self.actions = []
        if name in [action.name for action in self.actions]:
            raise ValueError('Action with name %r already exists.' % name)
        self.actions.append(Action(callback, name, validate, label))

    def process(self, ctx):

        request = inevow.IRequest(ctx)
        charset = getPOSTCharset(ctx)

        # Get the request args and decode the arg names
        args = dict([(k.decode(charset), v) for k, v in request.args.items()])

        # Find the callback to use, defaulting to the form default
        callback, validate = self.callback, True
        if self.actions is not None:
            for action in self.actions:
                if action.name in args:
                    # Remove it from the data
                    args.pop(action.name)
                    # Remember the callback and whether to validate
                    callback, validate = action.callback, action.validate
                    break

        # IE does not send a button name in the POST args for forms containing
        # a single field when the user presses <enter> to submit the form. If
        # we only have one possible action then we can safely assume that's the
        # action to take.
        #
        # If there are 0 or 2+ actions then we can't assume anything because we
        # have no idea what order the buttons are on the page (someone might
        # have altered the DOM using JavaScript for instance). In that case
        # throw an error and make it a problem for the developer.
        if callback is None:
            if self.actions is None or len(self.actions) != 1:
                raise Exception(
                    'The form has no callback and no action was found.')
            else:
                callback, validate = self.actions[0].callback, \
                        self.actions[0].validate

        # Remember the args in case validation fails.
        self.errors.data = args

        # Iterate the items and collect the form data and/or errors.
        for item in self.items:
            item.process(ctx, self, args, self.errors)

        if self.errors and validate:
            return self.errors

        def _clearUpResources(r):
            if not self.errors:
                self.resourceManager.clearUpResources()
            return r

        d = defer.maybeDeferred(callback, ctx, self, self.data)
        d.addCallback(_clearUpResources)
        d.addErrback(self._cbFormProcessingFailed, ctx)
        return d

    def _cbFormProcessingFailed(self, failure, ctx):
        e = failure.value
        failure.trap(validation.FormError, validation.FieldError)
        self.errors.add(failure.value)
        return self.errors