|
| 1 | +# |
| 2 | +# The goal is to finally have a form filler where you pass data for |
| 3 | +# each form, using the algorithm for "Seeding a form with initial values" |
| 4 | +# See http://www.whatwg.org/specs/web-forms/current-work/#seeding |
| 5 | +# |
| 6 | + |
| 7 | +import _base |
| 8 | + |
| 9 | +from html5lib.constants import spaceCharacters |
| 10 | +spaceCharacters = u"".join(spaceCharacters) |
| 11 | + |
| 12 | +class SimpleFilter(_base.Filter): |
| 13 | + def __init__(self, source, fieldStorage): |
| 14 | + _base.Filter.__init__(self, source) |
| 15 | + self.fieldStorage = fieldStorage |
| 16 | + |
| 17 | + def __iter__(self): |
| 18 | + field_indices = {} |
| 19 | + state = None |
| 20 | + field_name = None |
| 21 | + for token in _base.Filter.__iter__(self): |
| 22 | + type = token["type"] |
| 23 | + if type in ("StartTag", "EmptyTag"): |
| 24 | + name = token["name"].lower() |
| 25 | + if name == "input": |
| 26 | + field_name = None |
| 27 | + field_type = None |
| 28 | + input_value_index = -1 |
| 29 | + input_checked_index = -1 |
| 30 | + for i,(n,v) in enumerate(token["data"]): |
| 31 | + n = n.lower() |
| 32 | + if n == u"name": |
| 33 | + field_name = v.strip(spaceCharacters) |
| 34 | + elif n == u"type": |
| 35 | + field_type = v.strip(spaceCharacters) |
| 36 | + elif n == u"checked": |
| 37 | + input_checked_index = i |
| 38 | + elif n == u"value": |
| 39 | + input_value_index = i |
| 40 | + |
| 41 | + value_list = self.fieldStorage.getlist(field_name) |
| 42 | + field_index = field_indices.setdefault(field_name, 0) |
| 43 | + if field_index < len(value_list): |
| 44 | + value = value_list[field_index] |
| 45 | + else: |
| 46 | + value = "" |
| 47 | + |
| 48 | + if field_type in (u"checkbox", u"radio"): |
| 49 | + if value_list: |
| 50 | + if token["data"][input_value_index][1] == value: |
| 51 | + if input_checked_index < 0: |
| 52 | + token["data"].append((u"checked", u"")) |
| 53 | + field_indices[field_name] = field_index + 1 |
| 54 | + elif input_checked_index >= 0: |
| 55 | + del token["data"][input_checked_index] |
| 56 | + |
| 57 | + elif field_type not in (u"button", u"submit", u"reset"): |
| 58 | + if input_value_index >= 0: |
| 59 | + token["data"][input_value_index] = (u"value", value) |
| 60 | + else: |
| 61 | + token["data"].append((u"value", value)) |
| 62 | + field_indices[field_name] = field_index + 1 |
| 63 | + |
| 64 | + field_type = None |
| 65 | + field_name = None |
| 66 | + |
| 67 | + elif name == "textarea": |
| 68 | + field_type = "textarea" |
| 69 | + field_name = dict((token["data"])[::-1])["name"] |
| 70 | + |
| 71 | + elif name == "select": |
| 72 | + field_type = "select" |
| 73 | + attributes = dict(token["data"][::-1]) |
| 74 | + field_name = attributes.get("name") |
| 75 | + is_select_multiple = "multiple" in attributes |
| 76 | + is_selected_option_found = False |
| 77 | + |
| 78 | + elif field_type == "select" and field_name and name == "option": |
| 79 | + option_selected_index = -1 |
| 80 | + option_value = None |
| 81 | + for i,(n,v) in enumerate(token["data"]): |
| 82 | + n = n.lower() |
| 83 | + if n == "selected": |
| 84 | + option_selected_index = i |
| 85 | + elif n == "value": |
| 86 | + option_value = v.strip(spaceCharacters) |
| 87 | + if option_value is None: |
| 88 | + raise NotImplementedError("<option>s without a value= attribute") |
| 89 | + else: |
| 90 | + value_list = self.fieldStorage.getlist(field_name) |
| 91 | + if value_list: |
| 92 | + field_index = field_indices.setdefault(field_name, 0) |
| 93 | + if field_index < len(value_list): |
| 94 | + value = value_list[field_index] |
| 95 | + else: |
| 96 | + value = "" |
| 97 | + if (is_select_multiple or not is_selected_option_found) and option_value == value: |
| 98 | + if option_selected_index < 0: |
| 99 | + token["data"].append((u"selected", u"")) |
| 100 | + field_indices[field_name] = field_index + 1 |
| 101 | + is_selected_option_found = True |
| 102 | + elif option_selected_index >= 0: |
| 103 | + del token["data"][option_selected_index] |
| 104 | + |
| 105 | + elif field_type is not None and field_name and type == "EndTag": |
| 106 | + name = token["name"].lower() |
| 107 | + if name == field_type: |
| 108 | + if name == "textarea": |
| 109 | + value_list = self.fieldStorage.getlist(field_name) |
| 110 | + if value_list: |
| 111 | + field_index = field_indices.setdefault(field_name, 0) |
| 112 | + if field_index < len(value_list): |
| 113 | + value = value_list[field_index] |
| 114 | + else: |
| 115 | + value = "" |
| 116 | + yield {"type": "Characters", "data": value} |
| 117 | + field_indices[field_name] = field_index + 1 |
| 118 | + |
| 119 | + field_name = None |
| 120 | + |
| 121 | + elif name == "option" and field_type == "select": |
| 122 | + pass # TODO: part of "option without value= attribute" processing |
| 123 | + |
| 124 | + elif field_type == "textarea": |
| 125 | + continue # ignore token |
| 126 | + |
| 127 | + yield token |
0 commit comments