@@ -42,6 +42,7 @@ void HTMLDialogElement::visit_edges(JS::Cell::Visitor& visitor)
42
42
Base::visit_edges (visitor);
43
43
44
44
visitor.visit (m_close_watcher);
45
+ visitor.visit (m_request_close_source_element);
45
46
}
46
47
47
48
void HTMLDialogElement::removed_from (Node* old_parent, Node& old_root)
@@ -63,7 +64,7 @@ void HTMLDialogElement::removed_from(Node* old_parent, Node& old_root)
63
64
}
64
65
65
66
// https://html.spec.whatwg.org/multipage/interactive-elements.html#queue-a-dialog-toggle-event-task
66
- void HTMLDialogElement::queue_a_dialog_toggle_event_task (AK::String old_state, AK::String new_state)
67
+ void HTMLDialogElement::queue_a_dialog_toggle_event_task (AK::String old_state, AK::String new_state, GC::Ptr<DOM::Element> source )
67
68
{
68
69
// 1. If element's dialog toggle task tracker is not null, then:
69
70
if (m_dialog_toggle_task_tracker.has_value ()) {
@@ -80,14 +81,14 @@ void HTMLDialogElement::queue_a_dialog_toggle_event_task(AK::String old_state, A
80
81
}
81
82
82
83
// 2. Queue an element task given the DOM manipulation task source and element to run the following steps:
83
- auto task_id = queue_an_element_task (Task::Source::DOMManipulation, [this , old_state, new_state = move (new_state)]() {
84
+ auto task_id = queue_an_element_task (Task::Source::DOMManipulation, [this , old_state, new_state = move (new_state), source ]() {
84
85
// 1. Fire an event named toggle at element, using ToggleEvent, with the oldState attribute initialized to
85
- // oldState and the newState attribute initialized to newState.
86
+ // oldState, the newState attribute initialized to newState, and the source attribute initialized to source .
86
87
ToggleEventInit event_init {};
87
88
event_init.old_state = move (old_state);
88
89
event_init.new_state = move (new_state);
89
90
90
- dispatch_event (ToggleEvent::create (realm (), HTML::EventNames::toggle, move (event_init)));
91
+ dispatch_event (ToggleEvent::create (realm (), HTML::EventNames::toggle, move (event_init), source ));
91
92
92
93
// 2. Set element's dialog toggle task tracker to null.
93
94
m_dialog_toggle_task_tracker = {};
@@ -127,8 +128,8 @@ WebIDL::ExceptionOr<void> HTMLDialogElement::show()
127
128
if (has_attribute (AttributeNames::open))
128
129
return {};
129
130
130
- // 5. Queue a dialog toggle event task given this, "closed", and "open".
131
- queue_a_dialog_toggle_event_task (" closed" _string, " open" _string);
131
+ // 5. Queue a dialog toggle event task given this, "closed", "open", and null .
132
+ queue_a_dialog_toggle_event_task (" closed" _string, " open" _string, nullptr );
132
133
133
134
// 6. Add an open attribute to this, whose value is the empty string.
134
135
TRY (set_attribute (AttributeNames::open, {}));
@@ -169,11 +170,11 @@ WebIDL::ExceptionOr<void> HTMLDialogElement::show()
169
170
// https://html.spec.whatwg.org/multipage/interactive-elements.html#dom-dialog-showmodal
170
171
WebIDL::ExceptionOr<void > HTMLDialogElement::show_modal ()
171
172
{
172
- // The showModal() method steps are to show a modal dialog given this.
173
- return show_a_modal_dialog (*this );
173
+ // The showModal() method steps are to show a modal dialog given this and null .
174
+ return show_a_modal_dialog (*this , nullptr );
174
175
}
175
176
176
- WebIDL::ExceptionOr<void > HTMLDialogElement::show_a_modal_dialog (HTMLDialogElement& subject)
177
+ WebIDL::ExceptionOr<void > HTMLDialogElement::show_a_modal_dialog (HTMLDialogElement& subject, GC::Ptr<DOM::Element> source )
177
178
{
178
179
// To show a modal dialog given a dialog element subject:
179
180
auto & realm = subject.realm ();
@@ -200,13 +201,13 @@ WebIDL::ExceptionOr<void> HTMLDialogElement::show_a_modal_dialog(HTMLDialogEleme
200
201
201
202
// 6. If the result of firing an event named beforetoggle, using ToggleEvent,
202
203
// with the cancelable attribute initialized to true, the oldState attribute initialized to "closed",
203
- // and the newState attribute initialized to "open" at subject is false, then return.
204
+ // the newState attribute initialized to "open", and the source attribute initialized to source at subject is false, then return.
204
205
ToggleEventInit event_init {};
205
206
event_init.cancelable = true ;
206
207
event_init.old_state = " closed" _string;
207
208
event_init.new_state = " open" _string;
208
209
209
- auto beforetoggle_result = subject.dispatch_event (ToggleEvent::create (realm, EventNames::beforetoggle, move (event_init)));
210
+ auto beforetoggle_result = subject.dispatch_event (ToggleEvent::create (realm, EventNames::beforetoggle, move (event_init), source ));
210
211
if (!beforetoggle_result)
211
212
return {};
212
213
@@ -222,8 +223,8 @@ WebIDL::ExceptionOr<void> HTMLDialogElement::show_a_modal_dialog(HTMLDialogEleme
222
223
if (subject.popover_visibility_state () == PopoverVisibilityState::Showing)
223
224
return {};
224
225
225
- // 10. Queue a dialog toggle event task given subject, "closed", and "open".
226
- subject.queue_a_dialog_toggle_event_task (" closed" _string, " open" _string);
226
+ // 10. Queue a dialog toggle event task given subject, "closed", "open", and source .
227
+ subject.queue_a_dialog_toggle_event_task (" closed" _string, " open" _string, source );
227
228
228
229
// 11. Add an open attribute to subject, whose value is the empty string.
229
230
TRY (subject.set_attribute (AttributeNames::open, {}));
@@ -277,19 +278,24 @@ WebIDL::ExceptionOr<void> HTMLDialogElement::show_a_modal_dialog(HTMLDialogEleme
277
278
void HTMLDialogElement::close (Optional<String> return_value)
278
279
{
279
280
// 1. If returnValue is not given, then set it to null.
280
- // 2. Close the dialog this with returnValue.
281
- close_the_dialog (move (return_value));
281
+ // 2. Close the dialog this with returnValue and null .
282
+ close_the_dialog (move (return_value), nullptr );
282
283
}
283
284
284
285
// https://html.spec.whatwg.org/multipage/interactive-elements.html#dom-dialog-requestclose
285
286
void HTMLDialogElement::request_close (Optional<String> return_value)
286
287
{
288
+ // ADHOC: This method is an amalgamation of the requestClose() and "request to close" algorithms from the spec.
289
+ // FIXME: Once the "request-close" command is implemented, this will need to be split into two methods.
290
+ // For now this implementation is only used for the requestClose() method, which sets source to null.
291
+ auto source = nullptr ;
292
+
287
293
// 1. If this does not have an open attribute, then return.
288
294
if (!has_attribute (AttributeNames::open))
289
295
return ;
290
- // ADHOC: 2. If this's close watcher is null, then close the dialog this with returnValue, and return. See https://github.com/whatwg/html/pull/10983
296
+ // ADHOC: 2. If this's close watcher is null, then close the dialog this with returnValue and source , and return. See https://github.com/whatwg/html/pull/10983
291
297
if (!m_close_watcher) {
292
- close_the_dialog (move (return_value));
298
+ close_the_dialog (move (return_value), source );
293
299
return ;
294
300
}
295
301
// 3. Set dialog's enable close watcher for requestClose() to true.
@@ -298,6 +304,8 @@ void HTMLDialogElement::request_close(Optional<String> return_value)
298
304
// 4. If returnValue is not given, then set it to null.
299
305
// 5. Set this's request close return value to returnValue.
300
306
m_request_close_return_value = return_value;
307
+ // 6. Set subject's request close source element to source.
308
+ m_request_close_source_element = source;
301
309
// 6. Request to close dialog's close watcher with false.
302
310
m_close_watcher->request_close (false );
303
311
// 7. Set dialog's enable close watcher for requestClose() to false.
@@ -320,25 +328,25 @@ void HTMLDialogElement::set_return_value(String return_value)
320
328
}
321
329
322
330
// https://html.spec.whatwg.org/multipage/interactive-elements.html#close-the-dialog
323
- void HTMLDialogElement::close_the_dialog (Optional<String> result)
331
+ void HTMLDialogElement::close_the_dialog (Optional<String> result, GC::Ptr<DOM::Element> source )
324
332
{
325
333
// 1. If subject does not have an open attribute, then return.
326
334
if (!has_attribute (AttributeNames::open))
327
335
return ;
328
336
329
- // 2. Fire an event named beforetoggle, using ToggleEvent, with the oldState attribute initialized to "open" and the newState attribute initialized to "closed" at subject.
337
+ // 2. Fire an event named beforetoggle, using ToggleEvent, with the oldState attribute initialized to "open", the newState attribute initialized to "closed", and the source attribute initialized to source at subject.
330
338
ToggleEventInit event_init {};
331
339
event_init.old_state = " open" _string;
332
340
event_init.new_state = " closed" _string;
333
341
334
- dispatch_event (ToggleEvent::create (realm (), HTML::EventNames::beforetoggle, move (event_init)));
342
+ dispatch_event (ToggleEvent::create (realm (), HTML::EventNames::beforetoggle, move (event_init), source ));
335
343
336
344
// 3. If subject does not have an open attribute, then return.
337
345
if (!has_attribute (AttributeNames::open))
338
346
return ;
339
347
340
- // 4. Queue a dialog toggle event task given subject, "open", and "closed".
341
- queue_a_dialog_toggle_event_task (" open" _string, " closed" _string);
348
+ // 4. Queue a dialog toggle event task given subject, "open", "closed", and source .
349
+ queue_a_dialog_toggle_event_task (" open" _string, " closed" _string, source );
342
350
343
351
// 5. Remove subject's open attribute.
344
352
remove_attribute (AttributeNames::open);
@@ -355,30 +363,33 @@ void HTMLDialogElement::close_the_dialog(Optional<String> result)
355
363
// 9. Remove subject from subject's node document's open dialogs list.
356
364
document ().open_dialogs_list ().remove_first_matching ([this ](auto other) { return other == this ; });
357
365
358
- // 10. If result is not null, then set the returnValue attribute to result.
366
+ // 10. If result is not null, then set subject's return value to result.
359
367
if (result.has_value ())
360
368
set_return_value (result.release_value ());
361
369
362
- // 11. Set the request close return value to null.
370
+ // 11. Set subject's request close return value to null.
363
371
m_request_close_return_value = {};
364
372
365
- // FIXME: 12. If subject's previously focused element is not null, then:
373
+ // 12. Set subject's request close source element to null.
374
+ m_request_close_source_element = nullptr ;
375
+
376
+ // FIXME: 13. If subject's previously focused element is not null, then:
366
377
// 1. Let element be subject's previously focused element.
367
378
// 2. Set subject's previously focused element to null.
368
379
// 3. If subject's node document's focused area of the document's DOM anchor is a shadow-including inclusive descendant of subject,
369
380
// or wasModal is true, then run the focusing steps for element; the viewport should not be scrolled by doing this step.
370
381
371
- // 13 . Queue an element task on the user interaction task source given the subject element to fire an event named close at subject.
382
+ // 14 . Queue an element task on the user interaction task source given the subject element to fire an event named close at subject.
372
383
queue_an_element_task (HTML::Task::Source::UserInteraction, [this ] {
373
384
auto close_event = DOM::Event::create (realm (), HTML::EventNames::close);
374
385
dispatch_event (close_event);
375
386
});
376
387
377
- // 14 . If subject's close watcher is not null, then:
388
+ // 15 . If subject's close watcher is not null, then:
378
389
if (m_close_watcher) {
379
- // 14 .1 Destroy subject's close watcher.
390
+ // 15 .1 Destroy subject's close watcher.
380
391
m_close_watcher->destroy ();
381
- // 14 .2 Set subject's close watcher to null.
392
+ // 15 .2 Set subject's close watcher to null.
382
393
m_close_watcher = nullptr ;
383
394
}
384
395
}
@@ -401,10 +412,10 @@ void HTMLDialogElement::set_close_watcher()
401
412
0 , " " _fly_string, &realm ());
402
413
auto cancel_callback = realm ().heap ().allocate <WebIDL::CallbackType>(*cancel_callback_function, realm ());
403
414
m_close_watcher->add_event_listener_without_options (HTML::EventNames::cancel, DOM::IDLEventListener::create (realm (), cancel_callback));
404
- // - closeAction being to close the dialog given dialog and dialog's request close return value.
415
+ // - closeAction being to close the dialog given dialog, dialog's request close return value, and dialog's request close source element .
405
416
auto close_callback_function = JS::NativeFunction::create (
406
417
realm (), [this ](JS::VM&) {
407
- close_the_dialog (m_request_close_return_value);
418
+ close_the_dialog (m_request_close_return_value, m_request_close_source_element );
408
419
409
420
return JS::js_undefined ();
410
421
},
@@ -475,19 +486,17 @@ void HTMLDialogElement::invoker_command_steps(DOM::Element& invoker, String& com
475
486
return ;
476
487
}
477
488
478
- // 2. If command is in the Close state and element has an open attribute:
489
+ // 2. If command is in the Close state and element has an open attribute,
490
+ // then close the dialog given element with invoker's optional value and invoker.
479
491
if (command == " close" && has_attribute (AttributeNames::open)) {
480
- // 1. Let value be invoker's value.
481
- // FIXME: This assumes invoker is a button.
482
- auto value = invoker.get_attribute (AttributeNames::value);
483
-
484
- // 2. Close the dialog element with value.
485
- close_the_dialog (value);
492
+ // FIXME: This assumes invoker is a button.
493
+ auto optional_value = invoker.get_attribute (AttributeNames::value);
494
+ close_the_dialog (optional_value, invoker);
486
495
}
487
496
488
- // 3. If command is the Show Modal state and element does not have an open attribute, then show a modal dialog given element.
497
+ // 3. If command is the Show Modal state and element does not have an open attribute, then show a modal dialog given element and invoker .
489
498
if (command == " show-modal" && !has_attribute (AttributeNames::open)) {
490
- MUST (show_a_modal_dialog (*this ));
499
+ MUST (show_a_modal_dialog (*this , as<HTMLElement>(invoker) ));
491
500
}
492
501
}
493
502
0 commit comments