diff --git a/Userland/Libraries/LibWeb/ARIA/StateAndProperties.cpp b/Userland/Libraries/LibWeb/ARIA/StateAndProperties.cpp new file mode 100644 index 0000000000..7304d053a7 --- /dev/null +++ b/Userland/Libraries/LibWeb/ARIA/StateAndProperties.cpp @@ -0,0 +1,450 @@ +/* + * Copyright (c) 2023, Jonah Shafran + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include + +namespace Web::ARIA { + +ErrorOr state_or_property_to_string_value(StateAndProperties state_or_property, AriaData const& aria_data, DefaultValueType default_value) +{ + switch (state_or_property) { + case StateAndProperties::AriaActiveDescendant: { + auto value = aria_data.aria_active_descendant_or_default(); + return value.has_value() ? String::from_deprecated_string(value.value()) : String::from_utf8(""sv); + } + case StateAndProperties::AriaAtomic: { + bool value; + if (default_value.has()) + value = aria_data.aria_atomic_or_default(default_value.get()); + else + value = aria_data.aria_atomic_or_default(); + return value ? "true"_short_string : "false"_short_string; + } + case StateAndProperties::AriaAutoComplete: { + auto value = aria_data.aria_auto_complete_or_default(); + switch (value) { + case AriaAutocomplete::None: + return "none"_short_string; + case AriaAutocomplete::List: + return "list"_short_string; + case AriaAutocomplete::Both: + return "both"_short_string; + case AriaAutocomplete::Inline: + return "inline"_short_string; + } + VERIFY_NOT_REACHED(); + } + case StateAndProperties::AriaBusy: + return String::from_utf8(aria_data.aria_busy_or_default() ? "true"sv : "false"sv); + case StateAndProperties::AriaChecked: + return ARIA::tristate_to_string(aria_data.aria_checked_or_default()); + case StateAndProperties::AriaColCount: + return ARIA::optional_integer_to_string(aria_data.aria_col_count_or_default()); + case StateAndProperties::AriaColIndex: + return ARIA::optional_integer_to_string(aria_data.aria_col_index_or_default()); + case StateAndProperties::AriaColSpan: + return ARIA::optional_integer_to_string(aria_data.aria_col_span_or_default()); + case StateAndProperties::AriaControls: + return id_reference_list_to_string(aria_data.aria_controls_or_default()); + case StateAndProperties::AriaCurrent: { + auto value = aria_data.aria_current_or_default(); + switch (value) { + case AriaCurrent::False: + return "false"_short_string; + case AriaCurrent::True: + return "true"_short_string; + case AriaCurrent::Date: + return "date"_short_string; + case AriaCurrent::Location: + return "location"_string; + case AriaCurrent::Page: + return "page"_short_string; + case AriaCurrent::Step: + return "step"_short_string; + case AriaCurrent::Time: + return "time"_short_string; + } + VERIFY_NOT_REACHED(); + } + case StateAndProperties::AriaDescribedBy: + return id_reference_list_to_string(aria_data.aria_described_by_or_default()); + case StateAndProperties::AriaDetails: { + auto value = aria_data.aria_details_or_default(); + return value.has_value() ? String::from_deprecated_string(value.value()) : String::from_utf8(""sv); + } + case StateAndProperties::AriaDisabled: + return aria_data.aria_disabled_or_default() ? "true"_short_string : "false"_short_string; + case StateAndProperties::AriaDropEffect: { + StringBuilder builder; + auto value = aria_data.aria_drop_effect_or_default(); + for (auto const drop_effect : value) { + StringView to_add; + switch (drop_effect) { + case AriaDropEffect::Copy: + to_add = "copy"sv; + break; + case AriaDropEffect::Execute: + to_add = "execute"sv; + break; + case AriaDropEffect::Link: + to_add = "link"sv; + break; + case AriaDropEffect::Move: + to_add = "move"sv; + break; + case AriaDropEffect::None: + to_add = "none"sv; + break; + case AriaDropEffect::Popup: + to_add = "popup"sv; + break; + } + if (builder.is_empty()) + builder.append(to_add); + else { + builder.append(" "sv); + builder.append(to_add); + } + } + return builder.to_string(); + } + case StateAndProperties::AriaErrorMessage: { + auto value = aria_data.aria_error_message_or_default(); + return value.has_value() ? String::from_deprecated_string(value.value()) : String {}; + } + case StateAndProperties::AriaExpanded: + return ARIA::optional_bool_to_string(aria_data.aria_expanded_or_default()); + case StateAndProperties::AriaFlowTo: + return id_reference_list_to_string(aria_data.aria_flow_to_or_default()); + case StateAndProperties::AriaGrabbed: + return ARIA::optional_bool_to_string(aria_data.aria_grabbed_or_default()); + case StateAndProperties::AriaHasPopup: { + auto value = aria_data.aria_has_popup_or_default(); + switch (value) { + case AriaHasPopup::False: + return "false"_short_string; + case AriaHasPopup::True: + return "true"_short_string; + case AriaHasPopup::Menu: + return "menu"_short_string; + case AriaHasPopup::Listbox: + return "listbox"_string; + case AriaHasPopup::Tree: + return "tree"_short_string; + case AriaHasPopup::Grid: + return "grid"_short_string; + case AriaHasPopup::Dialog: + return "dialog"_short_string; + } + VERIFY_NOT_REACHED(); + } + case StateAndProperties::AriaHidden: + return ARIA::optional_bool_to_string(aria_data.aria_hidden_or_default()); + case StateAndProperties::AriaInvalid: { + auto value = aria_data.aria_invalid_or_default(); + switch (value) { + case AriaInvalid::Grammar: + return "grammar"_short_string; + case AriaInvalid::False: + return "false"_short_string; + case AriaInvalid::Spelling: + return "spelling"_string; + case AriaInvalid::True: + return "true"_short_string; + } + VERIFY_NOT_REACHED(); + } + case StateAndProperties::AriaKeyShortcuts: + return String::from_deprecated_string(aria_data.aria_key_shortcuts_or_default()); + case StateAndProperties::AriaLabel: + return String::from_deprecated_string(aria_data.aria_label_or_default()); + case StateAndProperties::AriaLabelledBy: + return id_reference_list_to_string(aria_data.aria_labelled_by_or_default()); + case StateAndProperties::AriaLevel: + return ARIA::optional_integer_to_string(aria_data.aria_level_or_default()); + case StateAndProperties::AriaLive: { + AriaLive value; + if (default_value.has()) + value = aria_data.aria_live_or_default(default_value.get()); + else + value = aria_data.aria_live_or_default(); + + switch (value) { + case AriaLive::Assertive: + return "assertive"_string; + case AriaLive::Off: + return "off"_short_string; + case AriaLive::Polite: + return "polite"_short_string; + } + VERIFY_NOT_REACHED(); + } + case StateAndProperties::AriaModal: + return aria_data.aria_modal_or_default() ? "true"_short_string : "false"_short_string; + case StateAndProperties::AriaMultiLine: + return aria_data.aria_multi_line_or_default() ? "true"_short_string : "false"_short_string; + case StateAndProperties::AriaMultiSelectable: + return aria_data.aria_multi_selectable_or_default() ? "true"_short_string : "false"_short_string; + case StateAndProperties::AriaOrientation: { + AriaOrientation value; + if (default_value.has()) + value = aria_data.aria_orientation_or_default(default_value.get()); + else + value = aria_data.aria_orientation_or_default(); + + switch (value) { + case AriaOrientation::Horizontal: + return "horizontal"_string; + case AriaOrientation::Undefined: + return "undefined"_string; + case AriaOrientation::Vertical: + return "vertical"_string; + } + VERIFY_NOT_REACHED(); + } + case StateAndProperties::AriaOwns: + return id_reference_list_to_string(aria_data.aria_owns_or_default()); + case StateAndProperties::AriaPlaceholder: + return String::from_deprecated_string(aria_data.aria_placeholder_or_default()); + case StateAndProperties::AriaPosInSet: + return ARIA::optional_integer_to_string(aria_data.aria_pos_in_set_or_default()); + case StateAndProperties::AriaPressed: + return ARIA::tristate_to_string(aria_data.aria_pressed_or_default()); + case StateAndProperties::AriaReadOnly: + return aria_data.aria_read_only_or_default() ? "true"_short_string : "false"_short_string; + case StateAndProperties::AriaRelevant: { + StringBuilder builder; + auto value = aria_data.aria_relevant_or_default(); + for (auto const relevant : value) { + StringView to_add; + switch (relevant) { + case AriaRelevant::Additions: + to_add = "additions"sv; + break; + case AriaRelevant::AdditionsText: + to_add = "additions text"sv; + break; + case AriaRelevant::All: + to_add = "all"sv; + break; + case AriaRelevant::Removals: + to_add = "removals"sv; + break; + case AriaRelevant::Text: + to_add = "text"sv; + break; + } + if (builder.is_empty()) + builder.append(to_add); + else { + builder.append(" "sv); + builder.append(to_add); + } + } + return builder.to_string(); + } + case StateAndProperties::AriaRequired: + return String::from_utf8(aria_data.aria_required_or_default() ? "true"sv : "false"sv); + case StateAndProperties::AriaRoleDescription: + return String::from_deprecated_string(aria_data.aria_role_description_or_default()); + case StateAndProperties::AriaRowCount: + return ARIA::optional_integer_to_string(aria_data.aria_row_count_or_default()); + case StateAndProperties::AriaRowIndex: + return ARIA::optional_integer_to_string(aria_data.aria_row_index_or_default()); + case StateAndProperties::AriaRowSpan: + return ARIA::optional_integer_to_string(aria_data.aria_row_span_or_default()); + case StateAndProperties::AriaSelected: + return ARIA::optional_bool_to_string(aria_data.aria_selected_or_default()); + case StateAndProperties::AriaSetSize: + return ARIA::optional_integer_to_string(aria_data.aria_set_size_or_default()); + case StateAndProperties::AriaSort: { + auto value = aria_data.aria_sort_or_default(); + switch (value) { + case AriaSort::Ascending: + return "ascending"_string; + case AriaSort::Descending: + return "descending"_string; + case AriaSort::None: + return "none"_short_string; + case AriaSort::Other: + return "other"_short_string; + } + VERIFY_NOT_REACHED(); + } + case StateAndProperties::AriaValueMax: + if (default_value.has()) + return ARIA::optional_number_to_string(aria_data.aria_value_max_or_default(default_value.get())); + else + return ARIA::optional_number_to_string(aria_data.aria_value_max_or_default()); + case StateAndProperties::AriaValueMin: + if (default_value.has()) + return ARIA::optional_number_to_string(aria_data.aria_value_min_or_default(default_value.get())); + else + return ARIA::optional_number_to_string(aria_data.aria_value_min_or_default()); + case StateAndProperties::AriaValueNow: + return ARIA::optional_number_to_string(aria_data.aria_value_now_or_default()); + case StateAndProperties::AriaValueText: + return String::from_deprecated_string(aria_data.aria_value_text_or_default()); + } + VERIFY_NOT_REACHED(); +} + +ErrorOr tristate_to_string(Tristate value) +{ + switch (value) { + case Tristate::False: + return "false"_short_string; + case Tristate::True: + return "true"_short_string; + case Tristate::Undefined: + return "undefined"_string; + case Tristate::Mixed: + return "mixed"_short_string; + } + VERIFY_NOT_REACHED(); +} + +ErrorOr optional_integer_to_string(Optional value) +{ + if (value.has_value()) + return String::number(value.value()); + return String {}; +} + +ErrorOr optional_bool_to_string(Optional value) +{ + if (!value.has_value()) + return "undefined"_string; + if (value.value()) + return "true"_short_string; + return "false"_short_string; +} + +ErrorOr optional_number_to_string(Optional value) +{ + if (!value.has_value()) + return "undefined"_string; + return String::number(value.value()); +} +ErrorOr id_reference_list_to_string(Vector const& value) +{ + StringBuilder builder; + for (auto const& id : value) { + if (builder.is_empty()) { + builder.append(id); + } else { + builder.append(" "sv); + builder.append(id); + } + } + return builder.to_string(); +} + +StringView state_or_property_to_string(StateAndProperties value) +{ + switch (value) { + case StateAndProperties::AriaActiveDescendant: + return "aria-activedescendant"sv; + case StateAndProperties::AriaAtomic: + return "aria-atomic"sv; + case StateAndProperties::AriaAutoComplete: + return "aria-autocomplete"sv; + case StateAndProperties::AriaBusy: + return "aria-busy"sv; + case StateAndProperties::AriaChecked: + return "aria-checked"sv; + case StateAndProperties::AriaColCount: + return "aria-colcount"sv; + case StateAndProperties::AriaColIndex: + return "aria-colindex"sv; + case StateAndProperties::AriaColSpan: + return "aria-colspan"sv; + case StateAndProperties::AriaControls: + return "aria-controls"sv; + case StateAndProperties::AriaCurrent: + return "aria-current"sv; + case StateAndProperties::AriaDescribedBy: + return "aria-describedby"sv; + case StateAndProperties::AriaDetails: + return "aria-details"sv; + case StateAndProperties::AriaDisabled: + return "aria-disabled"sv; + case StateAndProperties::AriaDropEffect: + return "aria-dropeffect"sv; + case StateAndProperties::AriaErrorMessage: + return "aria-errormessage"sv; + case StateAndProperties::AriaExpanded: + return "aria-expanded"sv; + case StateAndProperties::AriaFlowTo: + return "aria-flowto"sv; + case StateAndProperties::AriaGrabbed: + return "aria-grabbed"sv; + case StateAndProperties::AriaHasPopup: + return "aria-haspopup"sv; + case StateAndProperties::AriaHidden: + return "aria-hidden"sv; + case StateAndProperties::AriaInvalid: + return "aria-invalid"sv; + case StateAndProperties::AriaKeyShortcuts: + return "aria-keyshortcuts"sv; + case StateAndProperties::AriaLabel: + return "aria-label"sv; + case StateAndProperties::AriaLabelledBy: + return "aria-labelledby"sv; + case StateAndProperties::AriaLevel: + return "aria-level"sv; + case StateAndProperties::AriaLive: + return "aria-live"sv; + case StateAndProperties::AriaModal: + return "aria-modal"sv; + case StateAndProperties::AriaMultiLine: + return "aria-multiline"sv; + case StateAndProperties::AriaMultiSelectable: + return "aria-multiselectable"sv; + case StateAndProperties::AriaOrientation: + return "aria-orientation"sv; + case StateAndProperties::AriaOwns: + return "aria-owns"sv; + case StateAndProperties::AriaPlaceholder: + return "aria-placeholder"sv; + case StateAndProperties::AriaPosInSet: + return "aria-posinset"sv; + case StateAndProperties::AriaPressed: + return "aria-pressed"sv; + case StateAndProperties::AriaReadOnly: + return "aria-readonly"sv; + case StateAndProperties::AriaRelevant: + return "aria-relevant"sv; + case StateAndProperties::AriaRequired: + return "aria-required"sv; + case StateAndProperties::AriaRoleDescription: + return "aria-roledescription"sv; + case StateAndProperties::AriaRowCount: + return "aria-rowcount"sv; + case StateAndProperties::AriaRowIndex: + return "aria-rowindex"sv; + case StateAndProperties::AriaRowSpan: + return "aria-rowspan"sv; + case StateAndProperties::AriaSelected: + return "aria-selected"sv; + case StateAndProperties::AriaSetSize: + return "aria-setsize"sv; + case StateAndProperties::AriaSort: + return "aria-sort"sv; + case StateAndProperties::AriaValueMax: + return "aria-valuemax"sv; + case StateAndProperties::AriaValueMin: + return "aria-valuemin"sv; + case StateAndProperties::AriaValueNow: + return "aria-valuenow"sv; + case StateAndProperties::AriaValueText: + return "aria-valuetext"sv; + } + VERIFY_NOT_REACHED(); +} + +} diff --git a/Userland/Libraries/LibWeb/ARIA/StateAndProperties.h b/Userland/Libraries/LibWeb/ARIA/StateAndProperties.h new file mode 100644 index 0000000000..f40417b3ac --- /dev/null +++ b/Userland/Libraries/LibWeb/ARIA/StateAndProperties.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2023, Jonah Shafran + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include + +namespace Web::ARIA { + +enum class StateAndProperties { + AriaActiveDescendant, + AriaAtomic, + AriaAutoComplete, + AriaBusy, + AriaChecked, + AriaColCount, + AriaColIndex, + AriaColSpan, + AriaControls, + AriaCurrent, + AriaDescribedBy, + AriaDetails, + AriaDisabled, + AriaDropEffect, + AriaErrorMessage, + AriaExpanded, + AriaFlowTo, + AriaGrabbed, + AriaHasPopup, + AriaHidden, + AriaInvalid, + AriaKeyShortcuts, + AriaLabel, + AriaLabelledBy, + AriaLevel, + AriaLive, + AriaModal, + AriaMultiLine, + AriaMultiSelectable, + AriaOrientation, + AriaOwns, + AriaPlaceholder, + AriaPosInSet, + AriaPressed, + AriaReadOnly, + AriaRelevant, + AriaRequired, + AriaRoleDescription, + AriaRowCount, + AriaRowIndex, + AriaRowSpan, + AriaSelected, + AriaSetSize, + AriaSort, + AriaValueMax, + AriaValueMin, + AriaValueNow, + AriaValueText +}; + +using DefaultValueType = Variant; +ErrorOr state_or_property_to_string_value(StateAndProperties, AriaData const&, DefaultValueType = {}); +ErrorOr tristate_to_string(Tristate); +ErrorOr optional_integer_to_string(Optional); +ErrorOr optional_bool_to_string(Optional); +ErrorOr optional_number_to_string(Optional); +ErrorOr id_reference_list_to_string(Vector const&); +StringView state_or_property_to_string(StateAndProperties); + +} diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index 1424770239..47057abfb5 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -5,6 +5,7 @@ set(SOURCES ARIA/ARIAMixin.cpp ARIA/ARIAMixin.idl ARIA/Roles.cpp + ARIA/StateAndProperties.cpp Bindings/AudioConstructor.cpp Bindings/HostDefined.cpp Bindings/ImageConstructor.cpp