Skip to content

Instantly share code, notes, and snippets.

/form.diff Secret

Created June 5, 2017 11:02
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save anonymous/0f019916164e9abab4241b96c342d203 to your computer and use it in GitHub Desktop.
diff --git a/lib/Mojo/DOM.pm b/lib/Mojo/DOM.pm
index 740633241..35520515e 100644
--- a/lib/Mojo/DOM.pm
+++ b/lib/Mojo/DOM.pm
@@ -161,8 +161,11 @@ sub type { shift->tree->[0] }
sub val {
my $self = shift;
+ # "form"
+ return $self->_form(@_) if (my $tag = $self->tag) eq 'form';
+
# "option"
- return $self->{value} // $self->text if (my $tag = $self->tag) eq 'option';
+ return $self->{value} // $self->text if $tag eq 'option';
# "input" ("type=checkbox" and "type=radio")
my $type = $self->{type} // '';
@@ -173,7 +176,7 @@ sub val {
return $tag eq 'textarea' ? $self->text : $self->{value} if $tag ne 'select';
# "select"
- my $v = $self->find('option:checked')->map('val');
+ my $v = $self->find('option:checked:not([disabled])')->map('val');
return exists $self->{multiple} ? $v->size ? $v->to_array : undef : $v->last;
}
@@ -241,6 +244,35 @@ sub _delegate {
return $self;
}
+sub _form {
+ my ($self, $selector)
+ = (shift, shift // 'button, input[type=submit], input[type=image]');
+
+ my $form = {};
+ if (my $e = $self->at($selector)) { _input($form, $e) }
+ _input($form, $_) for $self->find('select, textarea')->each;
+ my $input
+ = $self->find('input:not([type=button], [type=image], [type=submit])');
+ for my $e ($input->each) {
+ my $type = $e->{type} // '';
+ _input($form, $e)
+ if ($type ne 'radio' && $type ne 'checkbox') || defined $e->{checked};
+ }
+
+ return $form;
+}
+
+sub _input {
+ my ($form, $input) = @_;
+
+ my ($name, $value) = ($input->{name}, $input->val);
+ $form->{$name}
+ = exists $form->{$name}
+ ? [ref $form->{$name} ? @{$form->{$name}} : $form->{$name}, $value]
+ : $value
+ if defined $name && defined $value && !exists $input->{disabled};
+}
+
sub _link {
my ($parent, @children) = @_;
diff --git a/t/mojo/dom.t b/t/mojo/dom.t
index 27c77ee16..4e8c69aec 100644
--- a/t/mojo/dom.t
+++ b/t/mojo/dom.t
@@ -2209,6 +2209,7 @@ $dom = Mojo::DOM->new(<<EOF);
<form action="/foo">
<p>Test</p>
<input type="text" name="a" value="A" />
+ <input type=text name="a" value="A2">
<input type="checkbox" name="q">
<input type="checkbox" checked name="b" value="B">
<input type="radio" name="r">
@@ -2221,6 +2222,7 @@ $dom = Mojo::DOM->new(<<EOF);
<optgroup>
<option>H</option>
<option selected>I</option>
+ <option selected disabled>V</option>
</optgroup>
<option value="J" selected>K</option>
</select>
@@ -2232,6 +2234,7 @@ $dom = Mojo::DOM->new(<<EOF);
</select>
<textarea name="m">M</textarea>
<button name="o" value="O">No!</button>
+ <input type=text name="x" value="X" disabled>
<input type="submit" name="p" value="P" />
</form>
EOF
@@ -2256,6 +2259,10 @@ is $dom->at('input[name=r]')->val, 'on', 'right value';
is $dom->at('input[name=s]')->val, undef, 'no value';
is $dom->at('input[name=t]')->val, '', 'right value';
is $dom->at('input[name=u]')->val, undef, 'no value';
+is_deeply $dom->at('form')->val,
+ {a => ['A', 'A2'], d => 'D', f => ['I', 'J'], m => 'M', o => 'O'}, 'right structure';
+is_deeply $dom->at('form')->val('input[type=submit]'),
+ {a => ['A', 'A2'], d => 'D', f => ['I', 'J'], m => 'M', p => 'P'}, 'right structure';
# PoCo example with whitespace-sensitive text
$dom = Mojo::DOM->new(<<EOF);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment