Skip to content

Commit

Permalink
Merge pull request #62 from RFnexus/micron
Browse files Browse the repository at this point in the history
Add Checkbox and Radio Group fields to Micron
  • Loading branch information
markqvist authored Nov 27, 2024
2 parents dc43bc6 + 912c510 commit c2fc703
Show file tree
Hide file tree
Showing 4 changed files with 215 additions and 56 deletions.
21 changes: 20 additions & 1 deletion nomadnet/examples/various/input_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
-=
>>>Text Fields
An input field : `B444`<username`Entered data>`b
An masked field : `B444`<!|password`Value of Field>`b
Expand All @@ -27,7 +29,24 @@
The data can be `!`[submitted`:/page/input_fields.mu`username|two]`!.
You can `!`[submit`:/page/input_fields.mu`one|password|small]`! other fields, or just `!`[a single one`:/page/input_fields.mu`username]`!
>> Checkbox Fields
`B444`<?|sign_up|1|*`>`b Sign me up
>> Radio group
Select your favorite color:
`B900`<^|color|Red`>`b Red
`B090`<^|color|Green`>`b Green
`B009`<^|color|Blue`>`b Blue
>>> Submitting data
You can `!`[submit`:/page/input_fields.mu`one|password|small|color]`! other fields, or just `!`[a single one`:/page/input_fields.mu`username]`!
Or simply `!`[submit them all`:/page/input_fields.mu`*]`!.
Expand Down
58 changes: 41 additions & 17 deletions nomadnet/ui/textui/Browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,23 +180,47 @@ def handle_link(self, link_target, link_data = None):
else:
link_fields.append(e)

def recurse_down(w):
target = None
if isinstance(w, list):
for t in w:
recurse_down(t)
elif isinstance(w, tuple):
for t in w:
recurse_down(t)
elif hasattr(w, "contents"):
recurse_down(w.contents)
elif hasattr(w, "original_widget"):
recurse_down(w.original_widget)
elif hasattr(w, "_original_widget"):
recurse_down(w._original_widget)
else:
if hasattr(w, "field_name") and (all_fields or w.field_name in link_fields):
request_data["field_"+w.field_name] = w.get_edit_text()
def recurse_down(w):
if isinstance(w, list):
for t in w:
recurse_down(t)
elif isinstance(w, tuple):
for t in w:
recurse_down(t)
elif hasattr(w, "contents"):
recurse_down(w.contents)
elif hasattr(w, "original_widget"):
recurse_down(w.original_widget)
elif hasattr(w, "_original_widget"):
recurse_down(w._original_widget)
else:
if hasattr(w, "field_name") and (all_fields or w.field_name in link_fields):
field_key = "field_" + w.field_name
if isinstance(w, urwid.Edit):
request_data[field_key] = w.edit_text
elif isinstance(w, urwid.RadioButton):
if w.state:
user_data = getattr(w, "field_value", None)
if user_data is not None:
request_data[field_key] = user_data
elif isinstance(w, urwid.CheckBox):
user_data = getattr(w, "field_value", "1")
if w.state:
existing_value = request_data.get(field_key, '')
if existing_value:
# Concatenate the new value with the existing one
request_data[field_key] = existing_value + ',' + user_data
else:
# Initialize the field with the current value
request_data[field_key] = user_data
else:
pass # do nothing if checkbox is not check







recurse_down(self.attr_maps)
RNS.log("Including request data: "+str(request_data), RNS.LOG_DEBUG)
Expand Down
41 changes: 41 additions & 0 deletions nomadnet/ui/textui/Guide.py
Original file line number Diff line number Diff line change
Expand Up @@ -1152,6 +1152,47 @@ def focus_reader(self):
A masked input field: `B444`<!|masked_demo`hidden text>`B333
Full control: `B444`<!32|all_options`hidden text>`B333
`b
>>> Checkboxes
In addition to text fields, Checkboxes are another way of submitting data. They allow the user to make a single selection or select multiple options.
`Faaa
`=
`<?|field_name|value`>`b Label Text`
`=
When the checkbox is checked, it's field will be set to the provided value. If there are multiple checkboxes that share the same field name, the checked values will be concatenated when they are sent to the node by a comma.
``
`B444`<?|sign_up|1`>`b Sign me up`
You can also pre-check both checkboxes and radio groups by appending a |* after the field value.
`B444`<?|checkbox|1|*`>`b Pre-checked checkbox`
>>> Radio groups
Radio groups are another input that lets the user chose from a set of options. Unlike checkboxes, radio buttons with the same field name are mutually exclusive.
Example:
`=
`B900`<^|color|Red`>`b Red
`B090`<^|color|Green`>`b Green
`B009`<^|color|Blue`>`b Blue
`=
will render:
`B900`<^|color|Red`>`b Red
`B090`<^|color|Green`>`b Green
`B009`<^|color|Blue`>`b Blue
In this example, when the data is submitted, `B444` field_color`b will be set to whichever value from the list was selected.
``
Expand Down
151 changes: 113 additions & 38 deletions nomadnet/ui/textui/MicronParser.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,6 @@ def parse_line(line, state, url_delegate):
tw.in_columns = True
else:
tw = urwid.Text(o, align=state["align"])

widgets.append((urwid.PACK, tw))
else:
if o["type"] == "field":
Expand All @@ -169,10 +168,40 @@ def parse_line(line, state, url_delegate):
fn = o["name"]
fs = o["style"]
fmask = "*" if o["masked"] else None
f = urwid.Edit(caption="", edit_text=fd, align=state["align"], multiline=True, mask=fmask)
f = urwid.Edit(caption="", edit_text=fd, align=state["align"], multiline=False, mask=fmask)
f.field_name = fn
fa = urwid.AttrMap(f, fs)
widgets.append((fw, fa))
elif o["type"] == "checkbox":
fn = o["name"]
fv = o["value"]
flabel = o["label"]
fs = o["style"]
fprechecked = o.get("prechecked", False)
f = urwid.CheckBox(flabel, state=fprechecked)
f.field_name = fn
f.field_value = fv
fa = urwid.AttrMap(f, fs)
widgets.append((urwid.PACK, fa))
elif o["type"] == "radio":
fn = o["name"]
fv = o["value"]
flabel = o["label"]
fs = o["style"]
fprechecked = o.get("prechecked", False)
if "radio_groups" not in state:
state["radio_groups"] = {}
if fn not in state["radio_groups"]:
state["radio_groups"][fn] = []
group = state["radio_groups"][fn]
f = urwid.RadioButton(group, flabel, state=fprechecked, user_data=fv)
f.field_name = fn
f.field_value = fv
fa = urwid.AttrMap(f, fs)
widgets.append((urwid.PACK, fa))




columns_widget = urwid.Columns(widgets, dividechars=0)
text_widget = columns_widget
Expand Down Expand Up @@ -458,54 +487,100 @@ def make_output(state, line, url_delegate):
elif c == "a":
state["align"] = state["default_align"]

elif c == "<":
elif c == '<':
if len(part) > 0:
output.append(make_part(state, part))
part = ""
try:
field_name = None
field_name_end = line[i:].find("`")
if field_name_end == -1:
pass
field_start = i + 1 # position after '<'
backtick_pos = line.find('`', field_start)
if backtick_pos == -1:
pass # No '`', invalid field
else:
field_name = line[i+1:i+field_name_end]
field_name_skip = len(field_name)
field_content = line[field_start:backtick_pos]
field_masked = False
field_width = 24

if "|" in field_name:
f_components = field_name.split("|")
field_type = "field"
field_name = field_content
field_value = ""
field_data = ""
field_prechecked = False

# check if field_content contains '|'
if '|' in field_content:
f_components = field_content.split('|')
field_flags = f_components[0]
field_name = f_components[1]
if "!" in field_flags:

# handle field type indicators
if '^' in field_flags:
field_type = "radio"
field_flags = field_flags.replace("^", "")
elif '?' in field_flags:
field_type = "checkbox"
field_flags = field_flags.replace("?", "")
elif '!' in field_flags:
field_flags = field_flags.replace("!", "")
field_masked = True

# Handle field width
if len(field_flags) > 0:
field_width = min(int(field_flags), 256)

def sr():
return "@{"+str(random.randint(1000,9999))+"}"
rsg = sr()
while rsg in line[i+field_name_end:]:
rsg = sr()
lr = line[i+field_name_end:].replace("\\>", rsg)
endpos = lr.find(">")

if endpos == -1:
pass

try:
field_width = min(int(field_flags), 256)
except ValueError:
pass # Ignore invalid width

# Check for value and pre-checked flag
if len(f_components) > 2:
field_value = f_components[2]
else:
field_value = ""
if len(f_components) > 3:
if f_components[3] == '*':
field_prechecked = True

else:
# No '|', so field_name is field_content
field_name = field_content
field_type = "field"
field_masked = False
field_width = 24
field_value = ""
field_prechecked = False

# Find the closing '>' character
field_end = line.find('>', backtick_pos)
if field_end == -1:
pass # No closing '>', invalid field
else:
field_data = lr[1:endpos].replace(rsg, "\\>")
skip = len(field_data)+field_name_skip+2
field_data = field_data.replace("\\>", ">")
output.append({
"type":"field",
"name": field_name,
"width": field_width,
"masked": field_masked,
"data": field_data,
"style": make_style(state)
})
field_data = line[backtick_pos+1:field_end]

# Now, we have all field data
if field_type in ["checkbox", "radio"]:
# for checkboxes and radios, field_data is the label
output.append({
"type": field_type,
"name": field_name,
"value": field_value if field_value else field_data,
"label": field_data,
"prechecked": field_prechecked,
"style": make_style(state)
})
else:
# For text fields field_data is the initial text
output.append({
"type": "field",
"name": field_name,
"width": field_width,
"masked": field_masked,
"data": field_data,
"style": make_style(state)
})
skip = field_end - i
except Exception as e:
pass



elif c == "[":
endpos = line[i:].find("]")
if endpos == -1:
Expand Down

0 comments on commit c2fc703

Please sign in to comment.