Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented get element target algorithm #27299

Merged
merged 1 commit into from Jul 24, 2020
Merged

Implemented get element target algorithm #27299

merged 1 commit into from Jul 24, 2020

Conversation

@avr1254
Copy link
Contributor

avr1254 commented Jul 16, 2020

Added check for area and anchor element

Finished issue: Implemented get target and no opener algorithm

Implemented get element target and get element noopener algorithms.

Used the algorithms in html spec to implement target and no opener algorithms.


  • ./mach build -d does not report any errors
  • ./mach test-tidy does not report any errors
  • These changes fix #27253 (GitHub issue number if applicable)
  • There are tests for these changes OR
  • These changes do not require tests because ___
@highfive
Copy link

highfive commented Jul 16, 2020

Thanks for the pull request, and welcome! The Servo team is excited to review your changes, and you should hear from @SimonSapin (or someone else) soon.

@highfive
Copy link

highfive commented Jul 16, 2020

Heads up! This PR modifies the following files:

  • @asajeffrey: components/script/dom/htmlformelement.rs, components/script/dom/htmlanchorelement.rs
  • @KiChjang: components/script/dom/htmlformelement.rs, components/script/dom/htmlanchorelement.rs
@highfive
Copy link

highfive commented Jul 16, 2020

warning Warning warning

  • These commits modify script code, but no tests are modified. Please consider adding a test!
@jdm jdm assigned jdm and unassigned SimonSapin Jul 16, 2020
@avr1254
Copy link
Contributor Author

avr1254 commented Jul 16, 2020

I think the error says Incorrect License for a source file. Any idea what that means?

@avr1254 avr1254 force-pushed the avr1254:master branch 3 times, most recently from b262242 to eac6011 Jul 16, 2020
@avr1254
Copy link
Contributor Author

avr1254 commented Jul 20, 2020

@jdm I think this looks good. Is there something I'm missing in the code?

@jdm
Copy link
Member

jdm commented Jul 21, 2020

Sorry, I got distracted from this. I'll review it tomorrow!

Copy link
Member

jdm left a comment

Good start!

components/script/dom/htmlformelement.rs Outdated Show resolved Hide resolved
@@ -581,21 +582,39 @@ pub fn follow_hyperlink(subject: &Element, hyperlink_suffix: Option<String>) {
let source = document.browsing_context().unwrap();

// Step 4-5: target attribute.
let target_attribute_value = subject.get_attribute(&ns!(), &local_name!("target"));

let subject_type = subject.get_attribute(&ns!(), &local_name!("target"));

This comment has been minimized.

Copy link
@jdm

jdm Jul 21, 2020

Member

My preference would be to extract this into a separate function that has a comment linking to https://html.spec.whatwg.org/multipage/semantics.html#get-an-element's-target and invoke that, so that this code more clearly follows the specification.

if !subject.has_attribute(&local_name!("target")) {
let base = (*document).base_element();
match base {
Some(base) => {
let base_html_unwrap = (*base).upcast::<HTMLElement>().upcast::<Element>();
if base_html_unwrap.has_attribute(&local_name!("target")) {
target_attribute_value =
base_html_unwrap.get_attribute(&ns!(), &local_name!("target"));
} else {
target_attribute_value = None;
}
},
None => target_attribute_value = None,
};
}
}
Comment on lines 591 to 648

This comment has been minimized.

Copy link
@jdm

jdm Jul 21, 2020

Member

With a get_element_target function that returns Option<DOMString>, we could write this as:

if !(subject.is::<HTMLAreaElement>() || subject.is::<HTMLAnchorElement>() || subject.is::<HTMLFormElement>()) {
    return None;
}
if subject.has_attribute(&local_name!("target")) {
    return subject.get_attribute(&ns!(), &local_name!("target"));
}
document
    .base_element()
    .map(|base| base.upcast::<Element>())
    .and_then(|element| {
        if element.has_attribute(&local_name!("target")) {
            Some(element.get_attribute(&local_name!("target")))
        } else {
            None
        }
    })
let noopener = if let Some(link_types) = subject.get_attribute(&ns!(), &local_name!("rel")) {
let values = link_types.Value();
let contains_noopener = values.contains("noopener");
let contains_noreferrer = values.contains("noreferrer");
let contains_opener = values.contains("opener");
let target_is_blank = if let Some(name) = target_attribute_value.as_ref() {
name.Value().to_lowercase() == "_blank"
} else {
false
};

contains_noreferrer || contains_noopener || (!contains_opener && target_is_blank)
values.contains("noreferrer") ||
values.contains("noopener") ||
(!values.contains("opener") && target_is_blank)
} else {
false
};
Comment on lines 608 to 620

This comment has been minimized.

Copy link
@jdm

jdm Jul 21, 2020

Member

This would also be good to extract into a function that links to https://html.spec.whatwg.org/multipage/links.html#get-an-element's-noopener and splits the string value appropriately (https://html.spec.whatwg.org/multipage/links.html#linkTypes)

let target_attribute_value;
let subject = submitter.form_owner().unwrap();
if submitter.is_submit_button() && submitter.target() != DOMString::new() {
target_attribute_value = action;
} else {
// the result of getting an element's target given submitter's form owner.
if subject
.upcast::<HTMLElement>()
.upcast::<Element>()
.has_attribute(&local_name!("target"))
{
target_attribute_value = subject
.upcast::<HTMLElement>()
.upcast::<Element>()
.get_attribute(&ns!(), &local_name!("target"))
.unwrap()
.Value();
} else {
let base =
(*document_from_node(subject.upcast::<HTMLElement>().upcast::<Element>()))
.base_element();
match base {
Some(base) => {
let base_html_unwrap = (*base).upcast::<HTMLElement>().upcast::<Element>();
if base_html_unwrap.has_attribute(&local_name!("target")) {
target_attribute_value = (*base_html_unwrap
.get_attribute(&ns!(), &local_name!("target"))
.unwrap())
.Value();
} else {
target_attribute_value = DOMString::new();
}
},
None => target_attribute_value = DOMString::new(),
};
}
}

// Step 18
let noopener = if let Some(form_data) = subject
.upcast::<HTMLElement>()
.upcast::<Element>()
.get_attribute(&ns!(), &local_name!("rel"))
{
let values = form_data.Value();
let target_is_blank: bool =
target_attribute_value.to_string().to_lowercase() == "_blank".to_string();
values.contains("noreferrer") ||
values.contains("noopener") ||
(!values.contains("opener") && target_is_blank)
} else {
false
};
Comment on lines 750 to 802

This comment has been minimized.

Copy link
@jdm

jdm Jul 21, 2020

Member

Reusing the functions here would be a good improvement.

@avr1254 avr1254 force-pushed the avr1254:master branch from eac6011 to 0b86fd6 Jul 22, 2020
@avr1254 avr1254 force-pushed the avr1254:master branch from c9075d2 to 03e7180 Jul 22, 2020
Copy link
Member

jdm left a comment

Getting close!

if (document_from_node(subject).base_element())
.unwrap()
Comment on lines 587 to 588

This comment has been minimized.

Copy link
@jdm

jdm Jul 22, 2020

Member

We don't want to panic if there is no <base>, so let's do this:

document_from_node(subject)
    .base_element()
    .map(|base| base.upcast::<Element>())
    .and_then(|element| {
        if element.has_attribute(&local_name!("target")) {
            Some(element.get_string_attribute(&local_name!("target")))
        } else {
            None
        }
    })

This comment has been minimized.

Copy link
@avr1254

avr1254 Jul 22, 2020

Author Contributor

I get an error code E0515 about not being able to return a value referencing function parameter 'base'

This comment has been minimized.

Copy link
@avr1254

avr1254 Jul 22, 2020

Author Contributor

@jdm Would using a match statement instead of unwrapping the base_element() value eliminate the chance for a panic?

This comment has been minimized.

Copy link
@jdm

jdm Jul 22, 2020

Member

It would. It may also be possible to do .base_element().as_ref(), or remove the map and do let element = element.upcast::<Element>(); inside of the and_then.

subject
.get_attribute(&ns!(), &local_name!("target"))
.unwrap()
.Value(),
Comment on lines 581 to 584

This comment has been minimized.

Copy link
@jdm

jdm Jul 22, 2020

Member

Let's use get_string_attribute, which avoids the need to unwrap anything.

{
return false;
}
let link_types = subject.get_attribute(&ns!(), &local_name!("rel")).unwrap();

This comment has been minimized.

Copy link
@jdm

jdm Jul 22, 2020

Member

To avoid panicking, let's do:

let link_types = match subject.get_attribute(&ns!(), &local_name!("rel")) {
    Some(rel) => rel.Value(),
    None => return false,
};
let target_is_blank = if let Some(name) = target_attribute_value.as_ref() {
name.to_lowercase() == "_blank"
} else {
false
};
Comment on lines 614 to 608

This comment has been minimized.

Copy link
@jdm

jdm Jul 22, 2020

Member

let target_is_blank = target_attribute_value.as_ref().map_or(false, |target| target.to_lowercase() == "_blank");

if values.contains("noreferrer") ||
values.contains("noopener") ||
(!values.contains("opener") && target_is_blank)
{
return true;
} else {
return false;
}
Comment on lines 619 to 626

This comment has been minimized.

Copy link
@jdm

jdm Jul 22, 2020

Member

We can return the condition directly; there's no need for the explicit return true or return false here.

let mut target_attribute_value = None;
if subject.is::<HTMLAreaElement>() || subject.is::<HTMLAnchorElement>() {
target_attribute_value = get_element_target(subject);
}
Comment on lines 645 to 648

This comment has been minimized.

Copy link
@jdm

jdm Jul 22, 2020

Member

Let's do:

let target_attribute_value = if subject.is::<...> ... {
    get_element_target(subject)
} else {
    None
};
target_attribute_value = Some(action);
} else {
target_attribute_value =
get_element_target(&subject.upcast::<HTMLElement>().upcast::<Element>());

This comment has been minimized.

Copy link
@jdm

jdm Jul 22, 2020

Member

&subject.upcast::<Element>()

let target_attribute_value: Option<DOMString>;
let subject = submitter.form_owner().unwrap();
if submitter.is_submit_button() && submitter.target() != DOMString::new() {
target_attribute_value = Some(action);

This comment has been minimized.

Copy link
@jdm

jdm Jul 22, 2020

Member

This doesn't look right - shouldn't this be submitter.target()?


// Step 18
let noopener = get_element_noopener(
&subject.upcast::<HTMLElement>().upcast::<Element>(),

This comment has been minimized.

Copy link
@jdm

jdm Jul 22, 2020

Member

This should beself.upcast::<Element>(), based on my reading of the spec.

This comment has been minimized.

Copy link
@avr1254

avr1254 Jul 22, 2020

Author Contributor

Sounds good! I'll get to these in the morning.

@bors-servo
Copy link
Contributor

bors-servo commented Jul 24, 2020

💔 Test failed - status-taskcluster

@@ -0,0 +1,3 @@
[opener-closed.html]

This comment has been minimized.

Copy link
@jdm

jdm Jul 24, 2020

Member

Aha - this file should be in the auxiliary-browsing-contexts subdirectory of browsers/windows/. That's why it's not being picked up correctly.

This comment has been minimized.

Copy link
@avr1254

avr1254 Jul 24, 2020

Author Contributor

@jdm Fixed it!

@avr1254 avr1254 force-pushed the avr1254:master branch from 37eee14 to 135fbb2 Jul 24, 2020
@jdm
Copy link
Member

jdm commented Jul 24, 2020

@bors-servo
Copy link
Contributor

bors-servo commented Jul 24, 2020

📌 Commit 135fbb2 has been approved by jdm

@avr1254
Copy link
Contributor Author

avr1254 commented Jul 24, 2020

@jdm Thanks for all the help and mentoring on this PR!

@jdm
Copy link
Member

jdm commented Jul 24, 2020

Thanks for sticking with it!

@bors-servo
Copy link
Contributor

bors-servo commented Jul 24, 2020

Testing commit 135fbb2 with merge 90c9907...

bors-servo added a commit that referenced this pull request Jul 24, 2020
Implemented get element target algorithm

Added check for area and anchor element

Finished issue: Implemented get target and no opener algorithm

Implemented get element target and get element noopener algorithms.

<!-- Please describe your changes on the following line: -->
Used the algorithms in html spec to implement target and no opener algorithms.

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: -->
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [X] These changes fix #27253 (GitHub issue number if applicable)

<!-- Either: -->
- [ ] There are tests for these changes OR
- [ ] These changes do not require tests because ___

<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
@bors-servo
Copy link
Contributor

bors-servo commented Jul 24, 2020

💔 Test failed - status-taskcluster

[opener-closed.html]
[An auxiliary browsing context should report `null` for `window.opener` when that browsing context is discarded]
expected: TIMEOUT
Comment on lines 1 to 4

This comment has been minimized.

Copy link
@jdm

jdm Jul 24, 2020

Member

We're missing a TIMEOUT for the top-level test file, too:

[opener-closed.html]
  expected: TIMEOUT
  [An auxiliary browsing context should report `null` for `window.opener` when that browsing context is discarded]
    expected: TIMEOUT

This comment has been minimized.

Copy link
@avr1254

avr1254 Jul 24, 2020

Author Contributor

Fixed it with the latest push!

and refactored into functions.
@avr1254 avr1254 force-pushed the avr1254:master branch from 135fbb2 to 2d5c30d Jul 24, 2020
@jdm
Copy link
Member

jdm commented Jul 24, 2020

@bors-servo
Copy link
Contributor

bors-servo commented Jul 24, 2020

📌 Commit 2d5c30d has been approved by jdm

@bors-servo
Copy link
Contributor

bors-servo commented Jul 24, 2020

Testing commit 2d5c30d with merge b83433f...

@bors-servo
Copy link
Contributor

bors-servo commented Jul 24, 2020

☀️ Test successful - status-taskcluster
Approved by: jdm
Pushing b83433f to master...

@bors-servo bors-servo merged commit b83433f into servo:master Jul 24, 2020
2 checks passed
2 checks passed
Community-TC (pull_request) TaskGroup: success
Details
homu Test successful
Details
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

5 participants
You can’t perform that action at this time.