Repository: servo/servo
File: components/script/dom/html/htmlformelement.rs (Rust)

Code before:
            // Step 15. If parsed action is failure, then return.
            Err(_) => return,
        };
        // Step 16. Let scheme be the scheme of parsed action.
        let scheme = action_components.scheme().to_owned();
        // Step 17. Let enctype be the submitter element's enctype.
        let enctype = submitter.enctype();

        // Step 19. If the submitter element is a submit button and it has a formtarget attribute,
        // then set formTarget to the formtarget attribute value.
        let form_target = if submitter.is_submit_button() && submitter.target() != DOMString::new()
        {
            Some(submitter.target())
        } else {
            // Step 18. Let formTarget be null.
            None
        };
        // Step 20. Let target be the result of getting an element's target given submitter's form owner and formTarget.
        let form_owner = submitter.form_owner();
        let form = form_owner.as_deref().unwrap_or(self);
        let target = get_element_target(form.upcast::<Element>(), form_target);

        // Step 21. Let noopener be the result of getting an element's noopener with form, parsed action, and target.
        let noopener = self.relations.get().get_element_noopener(target.as_ref());

        // Step 22. Let targetNavigable be the first return value of applying the rules for choosing a navigable given target,
        // form's node navigable, and noopener.
        let source = doc.browsing_context().unwrap();
        let (maybe_chosen, _new) =
            source.choose_browsing_context(target.unwrap_or(DOMString::new()), noopener);

        let Some(chosen) = maybe_chosen else {
            // Step 23. If targetNavigable is null, then return.
            return;
        };
        // Step 24. Let historyHandling be "auto".
        // TODO
        // Step 25. If form document equals targetNavigable's active document, and form document has not yet completely loaded,
        // then set historyHandling to "replace".
        // TODO

        let target_document = match chosen.document() {
            Some(doc) => doc,
            None => return,
        };
        let target_window = target_document.window();
        let mut load_data = LoadData::new(
            LoadOrigin::Script(doc.origin().snapshot()),
            action_components,
            target_document.about_base_url(),
            None,

Review comment (suggestion):
https://html.spec.whatwg.org/multipage/links.html#get-an-element's-noopener
Step 3 in the spec of `get_element_noopener` is missing in our implementation. We may need to update it to check the parsed action.
https://github.com/servo/servo/blob/22ead0354813d83b2befbf46ae8f25c67b822bb3/components/script/links.rs#L291-L292

Code after:
            // Step 15. If parsed action is failure, then return.
            Err(_) => return,
        };
        // Step 16. Let scheme be the scheme of parsed action.
        let scheme = action_components.scheme().to_owned();
        // Step 17. Let enctype be the submitter element's enctype.
        let enctype = submitter.enctype();

        // Step 19. If the submitter element is a submit button and it has a formtarget attribute,
        // then set formTarget to the formtarget attribute value.
        let form_target_attribute = submitter.target();
        let form_target = if submitter.is_submit_button() &&
            valid_navigable_target_name_or_keyword(&form_target_attribute)
        {
            Some(form_target_attribute)
        } else {
            // Step 18. Let formTarget be null.
            None
        };
        // Step 20. Let target be the result of getting an element's target given submitter's form owner and formTarget.
        let form_owner = submitter.form_owner();
        let form = form_owner.as_deref().unwrap_or(self);
        let target = get_element_target(form.upcast::<Element>(), form_target);

        // Step 21. Let noopener be the result of getting an element's noopener with form, parsed action, and target.
        let noopener = self.relations.get().get_element_noopener(target.as_ref());

        // Step 22. Let targetNavigable be the first return value of applying the rules for choosing a navigable given target,
        // form's node navigable, and noopener.
        let source = doc.browsing_context().unwrap();
        let (maybe_chosen, _new) =
            source.choose_browsing_context(target.unwrap_or_default(), noopener);

        let Some(chosen) = maybe_chosen else {
            // Step 23. If targetNavigable is null, then return.
            return;
        };
        // Step 24. Let historyHandling be "auto".
        // TODO
        // Step 25. If form document equals targetNavigable's active document, and form document has not yet completely loaded,
        // then set historyHandling to "replace".
        // TODO

        let target_document = match chosen.document() {
            Some(doc) => doc,
            None => return,
        };
        let target_window = target_document.window();
        let mut load_data = LoadData::new(
            LoadOrigin::Script(doc.origin().snapshot()),
            action_components,