HTMLDetailsElement.cpp 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. /*
  2. * Copyright (c) 2020, the SerenityOS developers.
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibWeb/Bindings/Intrinsics.h>
  7. #include <LibWeb/DOM/Event.h>
  8. #include <LibWeb/HTML/EventLoop/TaskQueue.h>
  9. #include <LibWeb/HTML/HTMLDetailsElement.h>
  10. #include <LibWeb/HTML/HTMLSummaryElement.h>
  11. #include <LibWeb/HTML/ToggleEvent.h>
  12. namespace Web::HTML {
  13. HTMLDetailsElement::HTMLDetailsElement(DOM::Document& document, DOM::QualifiedName qualified_name)
  14. : HTMLElement(document, move(qualified_name))
  15. {
  16. }
  17. HTMLDetailsElement::~HTMLDetailsElement() = default;
  18. void HTMLDetailsElement::initialize(JS::Realm& realm)
  19. {
  20. Base::initialize(realm);
  21. set_prototype(&Bindings::ensure_web_prototype<Bindings::HTMLDetailsElementPrototype>(realm, "HTMLDetailsElement"));
  22. }
  23. void HTMLDetailsElement::attribute_changed(DeprecatedFlyString const& name, DeprecatedString const& value)
  24. {
  25. Base::attribute_changed(name, value);
  26. // https://html.spec.whatwg.org/multipage/interactive-elements.html#details-notification-task-steps
  27. if (name == HTML::AttributeNames::open) {
  28. // 1. If the open attribute is added, queue a details toggle event task given the details element, "closed", and "open".
  29. if (!value.is_null()) {
  30. queue_a_details_toggle_event_task("closed"_string, "open"_string);
  31. }
  32. // 2. Otherwise, queue a details toggle event task given the details element, "open", and "closed".
  33. else {
  34. queue_a_details_toggle_event_task("open"_string, "closed"_string);
  35. }
  36. }
  37. }
  38. // https://html.spec.whatwg.org/multipage/interactive-elements.html#queue-a-details-toggle-event-task
  39. void HTMLDetailsElement::queue_a_details_toggle_event_task(String old_state, String new_state)
  40. {
  41. // 1. If element's details toggle task tracker is not null, then:
  42. if (m_details_toggle_task_tracker.has_value()) {
  43. // 1. Set oldState to element's details toggle task tracker's old state.
  44. old_state = move(m_details_toggle_task_tracker->old_state);
  45. // 2. Remove element's details toggle task tracker's task from its task queue.
  46. HTML::main_thread_event_loop().task_queue().remove_tasks_matching([&](auto const& task) {
  47. return task.id() == m_details_toggle_task_tracker->task_id;
  48. });
  49. // 3. Set element's details toggle task tracker to null.
  50. m_details_toggle_task_tracker->task_id = {};
  51. }
  52. // 2. Queue an element task given the DOM manipulation task source and element to run the following steps:
  53. auto task_id = queue_an_element_task(HTML::Task::Source::DOMManipulation, [this, old_state, new_state = move(new_state)]() mutable {
  54. // 1. Fire an event named toggle at element, using ToggleEvent, with the oldState attribute initialized to
  55. // oldState and the newState attribute initialized to newState.
  56. ToggleEventInit event_init {};
  57. event_init.old_state = move(old_state);
  58. event_init.new_state = move(new_state);
  59. dispatch_event(ToggleEvent::create(realm(), HTML::EventNames::toggle, move(event_init)));
  60. // 2. Set element's details toggle task tracker to null.
  61. m_details_toggle_task_tracker = {};
  62. });
  63. // 3. Set element's details toggle task tracker to a struct with task set to the just-queued task and old state set to oldState.
  64. m_details_toggle_task_tracker = ToggleTaskTracker {
  65. .task_id = task_id,
  66. .old_state = move(old_state),
  67. };
  68. }
  69. }