input (radio/password), max/min length, pattern
This commit is contained in:
@@ -1,23 +1,93 @@
|
||||
extends Control
|
||||
static var button_groups: Dictionary = {}
|
||||
|
||||
func init(element: HTMLParser.HTMLElement) -> void:
|
||||
var line_edit: LineEdit = $LineEdit
|
||||
var check_box: CheckBox = $CheckBox
|
||||
var radio_button: CheckBox = $RadioButton
|
||||
|
||||
var input_type = element.get_attribute("type").to_lower()
|
||||
var placeholder = element.get_attribute("placeholder")
|
||||
var value = element.get_attribute("value")
|
||||
var group = element.get_attribute("group")
|
||||
var minlength = element.get_attribute("minlength")
|
||||
var maxlength = element.get_attribute("maxlength")
|
||||
var pattern = element.get_attribute("pattern")
|
||||
|
||||
# Hide all inputs initially
|
||||
line_edit.visible = false
|
||||
check_box.visible = false
|
||||
radio_button.visible = false
|
||||
|
||||
match input_type:
|
||||
"checkbox":
|
||||
line_edit.visible = false
|
||||
check_box.visible = true
|
||||
if value and value == "true": check_box.button_pressed = true
|
||||
custom_minimum_size = check_box.size
|
||||
"radio":
|
||||
radio_button.visible = true
|
||||
radio_button.toggle_mode = true
|
||||
if value and value == "true": radio_button.button_pressed = true
|
||||
custom_minimum_size = radio_button.size
|
||||
|
||||
if group.length() > 0:
|
||||
if not button_groups.has(group):
|
||||
button_groups[group] = ButtonGroup.new()
|
||||
radio_button.button_group = button_groups[group]
|
||||
"password":
|
||||
line_edit.visible = true
|
||||
line_edit.secret = true
|
||||
custom_minimum_size = line_edit.size
|
||||
setup_text_input(line_edit, placeholder, value, minlength, maxlength, pattern)
|
||||
_: # Default to text input
|
||||
line_edit.visible = true
|
||||
check_box.visible = false
|
||||
line_edit.secret = false
|
||||
custom_minimum_size = line_edit.size
|
||||
|
||||
if placeholder: line_edit.placeholder_text = placeholder
|
||||
if value: line_edit.text = value
|
||||
setup_text_input(line_edit, placeholder, value, minlength, maxlength, pattern)
|
||||
|
||||
func setup_text_input(line_edit: LineEdit, placeholder: String, value: String, minlength: String, maxlength: String, pattern: String) -> void:
|
||||
if placeholder: line_edit.placeholder_text = placeholder
|
||||
if value: line_edit.text = value
|
||||
|
||||
line_edit.max_length = maxlength.to_int()
|
||||
|
||||
if minlength.length() > 0 or pattern.length() > 0:
|
||||
line_edit.text_changed.connect(_on_text_changed.bind(minlength, pattern))
|
||||
|
||||
func _on_text_changed(new_text: String, minlength: String, pattern: String) -> void:
|
||||
var line_edit = get_node("LineEdit") as LineEdit
|
||||
var is_valid = true
|
||||
|
||||
# Check minimum length
|
||||
if minlength.length() > 0 and minlength.is_valid_int():
|
||||
var min_len = minlength.to_int()
|
||||
if new_text.length() < min_len and new_text.length() > 0:
|
||||
is_valid = false
|
||||
|
||||
# Check pattern (regex)
|
||||
if pattern.length() > 0 and new_text.length() > 0:
|
||||
var regex = RegEx.new()
|
||||
if regex.compile(pattern) == OK:
|
||||
if not regex.search(new_text):
|
||||
is_valid = false
|
||||
|
||||
if is_valid:
|
||||
# Reset to default styles
|
||||
line_edit.remove_theme_stylebox_override("normal")
|
||||
line_edit.remove_theme_stylebox_override("focus")
|
||||
line_edit.modulate = Color.WHITE
|
||||
else:
|
||||
var normal_style = create_red_border_style_from_theme(line_edit, "normal")
|
||||
var focus_style = create_red_border_style_from_theme(line_edit, "focus")
|
||||
|
||||
line_edit.add_theme_stylebox_override("normal", normal_style)
|
||||
line_edit.add_theme_stylebox_override("focus", focus_style)
|
||||
line_edit.modulate = Color.WHITE
|
||||
|
||||
func create_red_border_style_from_theme(line_edit: LineEdit, style_name: String) -> StyleBoxFlat:
|
||||
var original_style: StyleBoxFlat = line_edit.get_theme_stylebox(style_name)
|
||||
var style: StyleBoxFlat = original_style.duplicate()
|
||||
|
||||
style.border_color = Color.RED
|
||||
|
||||
return style
|
||||
|
||||
174
Scripts/main.gd
174
Scripts/main.gd
@@ -74,15 +74,28 @@ both spaces and
|
||||
line breaks
|
||||
</pre>
|
||||
|
||||
<form>
|
||||
<!-- action, method, and type=submit are for when we implement Lua -->
|
||||
<form action=\"/submit\" method=\"POST\">
|
||||
<span>Name:</span>
|
||||
<input type=\"text\" placeholder=\"First name\" value=\"John\" />
|
||||
<span>Surname:</span>
|
||||
<input type=\"text\" placeholder=\"Last name\" value=\"Doe\" />
|
||||
<input type=\"text\" placeholder=\"First name\" value=\"John\" maxlength=\"20\" minlength=\"3\" />
|
||||
<span>Email regex:</span>
|
||||
<input type=\"text\" placeholder=\"Last name\" value=\"Doe\" pattern=\"^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$\" />
|
||||
<span>Smart:</span>
|
||||
<input type=\"checkbox\" />
|
||||
<input type=\"checkbox\" value=\"true\" />
|
||||
<button>Submit</button>
|
||||
|
||||
<p>favorite food</p>
|
||||
<input type=\"radio\" group=\"food\" />
|
||||
<span>Pizza</span>
|
||||
<input type=\"radio\" group=\"food\" />
|
||||
<span>Berry</span>
|
||||
<input type=\"radio\" group=\"food\" />
|
||||
<span>Gary</span>
|
||||
|
||||
<input type=\"password\" placeholder=\"your password...\" />
|
||||
<button type=\"submit\">Submit</button>
|
||||
|
||||
|
||||
</form>
|
||||
|
||||
<separator direction=\"horizontal\" />
|
||||
@@ -138,89 +151,14 @@ line breaks
|
||||
|
||||
continue
|
||||
|
||||
match element.tag_name:
|
||||
"p":
|
||||
var p = P.instantiate()
|
||||
p.init(element)
|
||||
website_container.add_child(p)
|
||||
if contains_hyperlink(element):
|
||||
p.rich_text_label.meta_clicked.connect(func(meta): OS.shell_open(str(meta)))
|
||||
"h1":
|
||||
var h1 = H1.instantiate()
|
||||
h1.init(element)
|
||||
website_container.add_child(h1)
|
||||
if contains_hyperlink(element):
|
||||
h1.rich_text_label.meta_clicked.connect(func(meta): OS.shell_open(str(meta)))
|
||||
"h2":
|
||||
var h2 = H2.instantiate()
|
||||
h2.init(element)
|
||||
website_container.add_child(h2)
|
||||
if contains_hyperlink(element):
|
||||
h2.rich_text_label.meta_clicked.connect(func(meta): OS.shell_open(str(meta)))
|
||||
"h3":
|
||||
var h3 = H3.instantiate()
|
||||
h3.init(element)
|
||||
website_container.add_child(h3)
|
||||
if contains_hyperlink(element):
|
||||
h3.rich_text_label.meta_clicked.connect(func(meta): OS.shell_open(str(meta)))
|
||||
"h4":
|
||||
var h4 = H4.instantiate()
|
||||
h4.init(element)
|
||||
website_container.add_child(h4)
|
||||
if contains_hyperlink(element):
|
||||
h4.rich_text_label.meta_clicked.connect(func(meta): OS.shell_open(str(meta)))
|
||||
"h5":
|
||||
var h5 = H5.instantiate()
|
||||
h5.init(element)
|
||||
website_container.add_child(h5)
|
||||
if contains_hyperlink(element):
|
||||
h5.rich_text_label.meta_clicked.connect(func(meta): OS.shell_open(str(meta)))
|
||||
"h6":
|
||||
var h6 = H6.instantiate()
|
||||
h6.init(element)
|
||||
website_container.add_child(h6)
|
||||
if contains_hyperlink(element):
|
||||
h6.rich_text_label.meta_clicked.connect(func(meta): OS.shell_open(str(meta)))
|
||||
"pre":
|
||||
var pre = PRE.instantiate()
|
||||
pre.init(element)
|
||||
website_container.add_child(pre)
|
||||
"br":
|
||||
var br = BR.instantiate()
|
||||
br.init(element)
|
||||
website_container.add_child(br)
|
||||
"img":
|
||||
var img = IMG.instantiate()
|
||||
img.init(element)
|
||||
website_container.add_child(img)
|
||||
"separator":
|
||||
var separator = SEPARATOR.instantiate()
|
||||
separator.init(element)
|
||||
website_container.add_child(separator)
|
||||
"form":
|
||||
var form = FORM.instantiate()
|
||||
form.init(element)
|
||||
website_container.add_child(form)
|
||||
|
||||
# Render form children
|
||||
for child_element in element.children:
|
||||
var child_node = create_element_node(child_element)
|
||||
if child_node:
|
||||
form.add_child(child_node)
|
||||
"input":
|
||||
var input = INPUT.instantiate()
|
||||
input.init(element)
|
||||
website_container.add_child(input)
|
||||
"button":
|
||||
var button = BUTTON.instantiate()
|
||||
button.init(element)
|
||||
website_container.add_child(button)
|
||||
"span":
|
||||
var span = SPAN.instantiate()
|
||||
span.init(element)
|
||||
website_container.add_child(span)
|
||||
_:
|
||||
print("Couldn't parse unsupported HTML tag \"%s\"" % element.tag_name)
|
||||
var element_node = create_element_node(element)
|
||||
if element_node:
|
||||
website_container.add_child(element_node)
|
||||
# Handle hyperlinks for all elements
|
||||
if contains_hyperlink(element) and element_node.has_method("get") and element_node.get("rich_text_label"):
|
||||
element_node.rich_text_label.meta_clicked.connect(func(meta): OS.shell_open(str(meta)))
|
||||
else:
|
||||
print("Couldn't parse unsupported HTML tag \"%s\"" % element.tag_name)
|
||||
|
||||
i += 1
|
||||
|
||||
@@ -254,18 +192,60 @@ func contains_hyperlink(element: HTMLParser.HTMLElement) -> bool:
|
||||
return false
|
||||
|
||||
func create_element_node(element: HTMLParser.HTMLElement) -> Control:
|
||||
var node: Control = null
|
||||
|
||||
match element.tag_name:
|
||||
"p":
|
||||
node = P.instantiate()
|
||||
node.init(element)
|
||||
"h1":
|
||||
node = H1.instantiate()
|
||||
node.init(element)
|
||||
"h2":
|
||||
node = H2.instantiate()
|
||||
node.init(element)
|
||||
"h3":
|
||||
node = H3.instantiate()
|
||||
node.init(element)
|
||||
"h4":
|
||||
node = H4.instantiate()
|
||||
node.init(element)
|
||||
"h5":
|
||||
node = H5.instantiate()
|
||||
node.init(element)
|
||||
"h6":
|
||||
node = H6.instantiate()
|
||||
node.init(element)
|
||||
"pre":
|
||||
node = PRE.instantiate()
|
||||
node.init(element)
|
||||
"br":
|
||||
node = BR.instantiate()
|
||||
node.init(element)
|
||||
"img":
|
||||
node = IMG.instantiate()
|
||||
node.init(element)
|
||||
"separator":
|
||||
node = SEPARATOR.instantiate()
|
||||
node.init(element)
|
||||
"form":
|
||||
node = FORM.instantiate()
|
||||
node.init(element)
|
||||
|
||||
for child_element in element.children:
|
||||
var child_node = create_element_node(child_element)
|
||||
if child_node:
|
||||
node.add_child(child_node)
|
||||
"input":
|
||||
var input = INPUT.instantiate()
|
||||
input.init(element)
|
||||
return input
|
||||
node = INPUT.instantiate()
|
||||
node.init(element)
|
||||
"button":
|
||||
var button = BUTTON.instantiate()
|
||||
button.init(element)
|
||||
return button
|
||||
node = BUTTON.instantiate()
|
||||
node.init(element)
|
||||
"span":
|
||||
var span = SPAN.instantiate()
|
||||
span.init(element)
|
||||
return span
|
||||
node = SPAN.instantiate()
|
||||
node.init(element)
|
||||
_:
|
||||
return null
|
||||
|
||||
return node
|
||||
|
||||
Reference in New Issue
Block a user