Skip to content

Commit

Permalink
LibWeb/HTML: Extract dialog show_modal() into its own algorithm
Browse files Browse the repository at this point in the history
Corresponds to whatwg/html#10961
  • Loading branch information
AtkinsSJ committed Jan 30, 2025
1 parent 7da3b06 commit 06122aa
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 42 deletions.
92 changes: 50 additions & 42 deletions Libraries/LibWeb/HTML/HTMLDialogElement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,80 +149,88 @@ WebIDL::ExceptionOr<void> HTMLDialogElement::show()
// https://html.spec.whatwg.org/multipage/interactive-elements.html#dom-dialog-showmodal
WebIDL::ExceptionOr<void> HTMLDialogElement::show_modal()
{
// 1. If this has an open attribute and is modal of this is true, then return.
if (has_attribute(AttributeNames::open) && m_is_modal)
// The showModal() method steps are to show a modal dialog given this.
return show_a_modal_dialog(*this);
}

WebIDL::ExceptionOr<void> HTMLDialogElement::show_a_modal_dialog(HTMLDialogElement& subject)
{
// To show a modal dialog given a dialog element subject:
auto& realm = subject.realm();

// 1. If subject has an open attribute and is modal of subject is true, then return.
if (subject.has_attribute(AttributeNames::open) && subject.m_is_modal)
return {};

// 2. If this has an open attribute, then throw an "InvalidStateError" DOMException.
if (has_attribute(AttributeNames::open))
return WebIDL::InvalidStateError::create(realm(), "Dialog already open"_string);
// 2. If subject has an open attribute, then throw an "InvalidStateError" DOMException.
if (subject.has_attribute(AttributeNames::open))
return WebIDL::InvalidStateError::create(realm, "Dialog already open"_string);

// 3. If this's node document is not fully active, then throw an "InvalidStateError" DOMException.
if (!document().is_fully_active())
return WebIDL::InvalidStateError::create(realm(), "Document is not fully active"_string);
// 3. If subject's node document is not fully active, then throw an "InvalidStateError" DOMException.
if (!subject.document().is_fully_active())
return WebIDL::InvalidStateError::create(realm, "Document is not fully active"_string);

// 4. If this is not connected, then throw an "InvalidStateError" DOMException.
if (!is_connected())
return WebIDL::InvalidStateError::create(realm(), "Dialog not connected"_string);
// 4. If subject is not connected, then throw an "InvalidStateError" DOMException.
if (!subject.is_connected())
return WebIDL::InvalidStateError::create(realm, "Dialog not connected"_string);

// 5. If this is in the popover showing state, then throw an "InvalidStateError" DOMException.
if (popover_visibility_state() == PopoverVisibilityState::Showing)
return WebIDL::InvalidStateError::create(realm(), "Dialog already open as popover"_string);
// 5. If subject is in the popover showing state, then throw an "InvalidStateError" DOMException.
if (subject.popover_visibility_state() == PopoverVisibilityState::Showing)
return WebIDL::InvalidStateError::create(realm, "Dialog already open as popover"_string);

// 6. If the result of firing an event named beforetoggle, using ToggleEvent,
// with the cancelable attribute initialized to true, the oldState attribute initialized to "closed",
// and the newState attribute initialized to "open" at this is false, then return.
// and the newState attribute initialized to "open" at subject is false, then return.
ToggleEventInit event_init {};
event_init.cancelable = true;
event_init.old_state = "closed"_string;
event_init.new_state = "open"_string;

auto beforetoggle_result = dispatch_event(ToggleEvent::create(realm(), HTML::EventNames::beforetoggle, move(event_init)));
auto beforetoggle_result = subject.dispatch_event(ToggleEvent::create(realm, EventNames::beforetoggle, move(event_init)));
if (!beforetoggle_result)
return {};

// 7. If this has an open attribute, then return.
if (has_attribute(AttributeNames::open))
// 7. If subject has an open attribute, then return.
if (subject.has_attribute(AttributeNames::open))
return {};

// 8. If this is not connected, then return.
if (!is_connected())
// 8. If subject is not connected, then return.
if (!subject.is_connected())
return {};

// 9. If this is in the popover showing state, then return.
if (popover_visibility_state() == PopoverVisibilityState::Showing)
// 9. If subject is in the popover showing state, then return.
if (subject.popover_visibility_state() == PopoverVisibilityState::Showing)
return {};

// 10. Queue a dialog toggle event task given subject, "closed", and "open".
queue_a_dialog_toggle_event_task("closed"_string, "open"_string);
subject.queue_a_dialog_toggle_event_task("closed"_string, "open"_string);

// 11. Add an open attribute to this, whose value is the empty string.
TRY(set_attribute(AttributeNames::open, {}));

// 12. Set is modal of this to true.
m_is_modal = true;
// 11. Add an open attribute to subject, whose value is the empty string.
TRY(subject.set_attribute(AttributeNames::open, {}));

// FIXME: 13. Assert: this's node document's open dialogs list does not contain this.
// FIXME: 14. Add this to this's node document's open dialogs list.
// FIXME: 15. Let this's node document be blocked by the modal dialog this.
// 12. Set is modal of subject to true.
subject.m_is_modal = true;

// 16. If this's node document's top layer does not already contain this, then add an element to the top layer given this.
if (!document().top_layer_elements().contains(*this))
document().add_an_element_to_the_top_layer(*this);
// FIXME: 13. Assert: subject's node document's open dialogs list does not contain subject.
// FIXME: 14. Add subject to subject's node document's open dialogs list.
// FIXME: 15. Let subject's node document be blocked by the modal dialog subject.

// 17. Set the dialog close watcher with this.
set_close_watcher();
// 16. If subject's node document's top layer does not already contain subject, then add an element to the top layer given subject.
if (!subject.document().top_layer_elements().contains(subject))
subject.document().add_an_element_to_the_top_layer(subject);

// FIXME: 18. Set this's previously focused element to the focused element.
// 17. Set the dialog close watcher with subject.
subject.set_close_watcher();

// FIXME: 19. Let document be this's node document.
// FIXME: 20. Let hideUntil be the result of running topmost popover ancestor given this, document's showing hint popover list, null, and false.
// FIXME: 21. If hideUntil is null, then set hideUntil to the result of running topmost popover ancestor given this, document's showing auto popover list, null, and false.
// FIXME: 18. Set subject's previously focused element to the focused element.
// FIXME: 19. Let document be subject's node document.
// FIXME: 20. Let hideUntil be the result of running topmost popover ancestor given subject, document's showing hint popover list, null, and false.
// FIXME: 21. If hideUntil is null, then set hideUntil to the result of running topmost popover ancestor given subject, document's showing auto popover list, null, and false.
// FIXME: 22. If hideUntil is null, then set hideUntil to document.
// FIXME: 23. Run hide all popovers until given hideUntil, false, and true.

// 24. Run the dialog focusing steps given this.
run_dialog_focusing_steps();
// 24. Run the dialog focusing steps given subject.
subject.run_dialog_focusing_steps();

return {};
}
Expand Down
2 changes: 2 additions & 0 deletions Libraries/LibWeb/HTML/HTMLDialogElement.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ class HTMLDialogElement final : public HTMLElement {
String return_value() const;
void set_return_value(String);

static WebIDL::ExceptionOr<void> show_a_modal_dialog(HTMLDialogElement&);

WebIDL::ExceptionOr<void> show();
WebIDL::ExceptionOr<void> show_modal();
void close(Optional<String> return_value);
Expand Down

0 comments on commit 06122aa

Please sign in to comment.