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
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