1.1 --- a/MoinForms.py Thu Nov 29 00:53:51 2012 +0100
1.2 +++ b/MoinForms.py Sat Dec 01 20:38:35 2012 +0100
1.3 @@ -7,12 +7,14 @@
1.4 """
1.5
1.6 from MoinMoin import wikiutil
1.7 -from StringIO import StringIO
1.8 from MoinSupport import *
1.9 import re
1.10
1.11 __version__ = "0.1"
1.12
1.13 +form_field_regexp_str = r"<<FormField\((.*?)\)>>"
1.14 +form_field_regexp = re.compile(form_field_regexp_str, re.DOTALL)
1.15 +
1.16 # Common formatting functions.
1.17
1.18 def formatForm(text, request, fmt, attrs=None, write=None):
1.19 @@ -30,7 +32,13 @@
1.20
1.21 fields = getFields(get_form(request))
1.22
1.23 - querystr = attrs and attrs.has_key("action") and ("action=%s" % attrs["action"]) or None
1.24 + queryparams = []
1.25 +
1.26 + for argname in ["fragment", "action"]:
1.27 + if attrs and attrs.has_key(argname):
1.28 + queryparams.append("%s=%s" % (argname, attrs[argname]))
1.29 +
1.30 + querystr = "&".join(queryparams)
1.31
1.32 write(fmt.rawHTML('<form method="post" action="%s">' %
1.33 escattr(page.url(request, querystr))
1.34 @@ -60,8 +68,6 @@
1.35 for region in getRegions(text, True):
1.36 format, attributes, body, header, close = getFragmentFromRegion(region)
1.37
1.38 - # NOTE: Need to adjust FormField macros to use hierarchical names.
1.39 -
1.40 # Include bare regions as they are.
1.41
1.42 if format is None:
1.43 @@ -72,9 +78,15 @@
1.44 elif format == "form":
1.45 section_name = attributes.get("section")
1.46 if section_name and section.has_key(section_name):
1.47 - output.append(header)
1.48 - output.append(getFormOutput(body, section[section_name]))
1.49 - output.append(close)
1.50 +
1.51 + # Iterate over the section contents ignoring the given indexes.
1.52 +
1.53 + for index, element in enumerate(getSectionElements(section[section_name])):
1.54 +
1.55 + # Adjust FormField macros to use hierarchical names.
1.56 +
1.57 + adjusted_body = adjustFormFields(body, section_name, index)
1.58 + output.append(getFormOutput(adjusted_body, element))
1.59
1.60 # Inspect and include other regions.
1.61
1.62 @@ -85,40 +97,157 @@
1.63
1.64 return "".join(output)
1.65
1.66 -def getFields(d):
1.67 +def adjustFormFields(body, section_name, index):
1.68 +
1.69 + """
1.70 + Return a version of the 'body' with the names in FormField macros updated to
1.71 + incorporate the given 'section_name' and 'index'.
1.72 + """
1.73 +
1.74 + result = []
1.75 + in_macro = False
1.76 +
1.77 + for match in form_field_regexp.split(body):
1.78 + if not in_macro:
1.79 + result.append(match)
1.80 + else:
1.81 + result.append("<<FormField(%s)>>" % ",".join(
1.82 + adjustMacroArguments(parseMacroArguments(match), section_name, index)
1.83 + ))
1.84 +
1.85 + in_macro = not in_macro
1.86 +
1.87 + return "".join(result)
1.88 +
1.89 +def adjustMacroArguments(args, section_name, index):
1.90
1.91 """
1.92 - Return the form fields hierarchy for the given dictionary 'd'.
1.93 + Adjust the given 'args' so that the path incorporates the given
1.94 + 'section_name' and 'index', returning a new list containing the revised
1.95 + path and remaining arguments.
1.96 + """
1.97 +
1.98 + result = []
1.99 + path = None
1.100 +
1.101 + for arg in args:
1.102 + if arg.startswith("path="):
1.103 + path = arg[5:]
1.104 + else:
1.105 + result.append(arg)
1.106 +
1.107 + qualified = "%s%s$%s" % (path and ("%s/" % path) or "", section_name, index)
1.108 + result.append("path=%s" % qualified)
1.109 +
1.110 + return result
1.111 +
1.112 +def parseMacroArguments(args):
1.113 +
1.114 + """
1.115 + Interpret the arguments.
1.116 + NOTE: The argument parsing should really be more powerful in order to
1.117 + NOTE: support labels.
1.118 + """
1.119 +
1.120 + try:
1.121 + parsed_args = args and wikiutil.parse_quoted_separated(args, name_value=False) or []
1.122 + except AttributeError:
1.123 + parsed_args = args.split(",")
1.124 +
1.125 + return [arg for arg in parsed_args if arg]
1.126 +
1.127 +def getFields(d, remove=False):
1.128 +
1.129 + """
1.130 + Return the form fields hierarchy for the given dictionary 'd'. If the
1.131 + optional 'remove' parameter is set to a true value, remove the entries for
1.132 + the fields from 'd'.
1.133 """
1.134
1.135 fields = {}
1.136
1.137 for key, value in d.items():
1.138
1.139 + # Detect modifying fields.
1.140 +
1.141 + if key.find("=") != -1:
1.142 + fields[key] = value
1.143 + if remove:
1.144 + del d[key]
1.145 + continue
1.146 +
1.147 # Reproduce the original hierarchy of the fields.
1.148
1.149 section = fields
1.150 - parts = key.split("/")
1.151 + parts = getPathDetails(key)
1.152
1.153 - for part in parts[:-1]:
1.154 - try:
1.155 - name, index = part.split("$", 1)
1.156 - index = int(index)
1.157 - except ValueError:
1.158 - name, index = part, None
1.159 + for name, index in parts[:-1]:
1.160 +
1.161 + # Add an entry for instances of the section.
1.162
1.163 if not section.has_key(name):
1.164 section[name] = {}
1.165
1.166 + # Add an entry for the specific instance of the section.
1.167 +
1.168 if not section[name].has_key(index):
1.169 section[name][index] = {}
1.170
1.171 section = section[name][index]
1.172
1.173 - section[parts[-1]] = value
1.174 + section[parts[-1][0]] = value
1.175 +
1.176 + if remove:
1.177 + del d[key]
1.178
1.179 return fields
1.180
1.181 +def getPathDetails(path):
1.182 + parts = []
1.183 +
1.184 + for part in path.split("/"):
1.185 + try:
1.186 + name, index = part.split("$", 1)
1.187 + index = int(index)
1.188 + except ValueError:
1.189 + name, index = part, None
1.190 +
1.191 + parts.append((name, index))
1.192 +
1.193 + return parts
1.194 +
1.195 +def getSectionForPath(path, fields):
1.196 +
1.197 + """
1.198 + Obtain the section indicated by the given 'path' from the 'fields',
1.199 + returning a tuple of the form (parent section, (name, index)), where the
1.200 + parent section contains the referenced section, where name is the name of
1.201 + the referenced section, and where index, if not None, is the index of a
1.202 + specific section instance within the named section.
1.203 + """
1.204 +
1.205 + parts = getPathDetails(path)
1.206 + section = fields
1.207 +
1.208 + for name, index in parts[:-1]:
1.209 + section = fields[name][index]
1.210 +
1.211 + return section, parts[-1]
1.212 +
1.213 +def getSectionElements(section_elements):
1.214 +
1.215 + "Return the given 'section_elements' as an ordered collection."
1.216 +
1.217 + keys = map(int, section_elements.keys())
1.218 + keys.sort()
1.219 +
1.220 + elements = []
1.221 +
1.222 + for key in keys:
1.223 + elements.append(section_elements[key])
1.224 +
1.225 + return elements
1.226 +
1.227 def formatFormForOutputType(text, request, mimetype, attrs=None, write=None):
1.228
1.229 """