diff --git a/src/web/web-dom/node.h b/src/web/web-dom/node.h index 97f204f9d3..f289be18cc 100644 --- a/src/web/web-dom/node.h +++ b/src/web/web-dom/node.h @@ -55,6 +55,12 @@ struct Node : return *_parent; } + Node const &parentNode() const { + if (not _parent) + panic("node has no parent"); + return *_parent; + } + usize _parentIndex() { return indexOf(parentNode()._children, *this).unwrap(); } diff --git a/src/web/web-select/match.h b/src/web/web-select/match.h new file mode 100644 index 0000000000..52965f9ae7 --- /dev/null +++ b/src/web/web-select/match.h @@ -0,0 +1,59 @@ +#pragma once + +#include + +#include "select2.h" + +namespace Web::Select { + +// 17. Calculating a selector’s specificity +// https://www.w3.org/TR/selectors-4/#specificity-rules +struct Spec { + bool match; + isize a, b, c; + + static Spec NOMATCH; + static Spec MATCH; + + Spec operator and(Spec const &other) const { + return Spec{ + match && other.match, + a + other.a, + b + other.b, + c + other.c + }; + } + + Spec operator or(Spec const &other) const { + return Spec{ + match || other.match, + a + other.a, + b + other.b, + c + other.c + }; + } +}; + +Spec match(Selector const &sel, Dom::Element &el) { + return sel.visit(Visitor{ + [&](Combinator const &s) -> Spec { + switch (s.type) { + case Combinator::LIST: + return match(*s.lhs, el) or match(*s.rhs, el); + + case Combinator::DESCENDANT: + return match(*s.lhs, el) or el.parentNode().map([&](auto &parent) { + return match(*s.rhs, parent); + }).value_or(Spec::NOMATCH); + + default: + return Spec::NOMATCH; + } + }, + [&](auto &) -> Spec { + return Spec::NOMATCH; + } + }); +} + +} // namespace Web::Select diff --git a/src/web/web-select/select.h b/src/web/web-select/select.h new file mode 100644 index 0000000000..9af756344e --- /dev/null +++ b/src/web/web-select/select.h @@ -0,0 +1,493 @@ +// Copyright © 2018-2024, the skiftOS Developers +// Copyright © 2024, Odoo S.A. +// +// SPDX-License-Identifier: MIT + +#include +#include +#include + +namespace Web::Select { + +struct Selector; + +struct AnB { + isize a, b; +}; + +struct Specificity { + isize a, b, c; +}; + +struct Selector { + struct PseudoClass { + Str name; + + PseudoClass(Str name) : name(name) {} + }; + + // 4. MARK: Logical Combinations ------------------------------------------- + + // 4.1. Selector Lists + // https://www.w3.org/TR/selectors-4/#grouping + + struct ListCombinator { + Box _lhs; + Box _rhs; + }; + + // 4.2 The Matches-Any Pseudo-class: :is() + // https://www.w3.org/TR/selectors-4/#matches + + struct IsPseudoClass { + }; + + // 4.3. The Negation Pseudo-class: :not() + // https://www.w3.org/TR/selectors-4/#negation + + struct NegationPseudoClass { + }; + + // 4.4. The Specificity-adjustment Pseudo-class: :where() + // https://www.w3.org/TR/selectors-4/#zero-matches + + struct WherePseudoClass { + }; + + // 4.5. The Relational Pseudo-class: :has() + // https://www.w3.org/TR/selectors-4/#has + + struct HasPseudoClass { + }; + + // 5. MARK: Elemental selectors -------------------------------------------- + + // 5.1 Type (tag name) selector + // https://www.w3.org/TR/selectors-4/#type-selectors + + struct TypeSelector { + TagName type; + }; + + // 5.2. Universal selector + // https://www.w3.org/TR/selectors-4/#universal-selecto + + struct UniversalSelector { + }; + + // 5.3. Namespace prefix selector + // https://www.w3.org/TR/selectors-4/#universal-selecto + + struct NamespaceSelector { + Ns ns; + }; + + // 5.4. The Defined Pseudo-class: :defined + // https://www.w3.org/TR/selectors-4/#defined + + struct DefinedPseudoClass { + }; + + // 6. MARK: Attribute selectors -------------------------------------------- + + // 6.1. Attribute presence and value selectors + // https://www.w3.org/TR/selectors-4/#attribute-representation + + struct AttributeSelector { + enum Case { + SENSITIVE, + INSENSITIVE, + }; + + enum Match { + PRESENT, //< [attr] + + EXACT, //< [attr="value"] + CONTAINS, //< [attr~="value"] + HYPHENATED, //< [attr|="value"] + + STR_START_WITH, //< [attr^="value"] + STR_END_WITH, //< [attr$="value"] + STR_CONTAIN, //< [attr*="value"] + }; + + Opt ns = NONE; + Case case_ = SENSITIVE; + Match match = PRESENT; + + String name; + String value; + }; + + // 6.6. Class selectors + // https://www.w3.org/TR/selectors-4/#type-selectors + + struct ClassSelector { + String class_; + }; + + // 6.7. ID selectors + // https://www.w3.org/TR/selectors-4/#type-selectors + + struct IdSelector { + String id; + }; + + // 7. MARK: Linguistic Pseudo-classes -------------------------------------- + + // 7.1 The Directionality Pseudo-class: :dir() + // https://www.w3.org/TR/selectors-4/#the-dir-pseudo + + enum struct DirPseudoClass { + LTR, + RTL, + }; + + // 7.2. The Lang Pseudo-class: :lang() + // https://www.w3.org/TR/selectors-4/#the-dir-pseudo + + struct LangPseudoClass { + String lang; + }; + + // 8. MARK: Location Pseudo-classes ---------------------------------------- + + // 8.1. The Hyperlink Pseudo-class: :any-link + // https://www.w3.org/TR/selectors-4/#the-any-link-pseudo + + static constexpr PseudoClass ANY_LINK = "any-link"s; + + // 8.2 The Link History Pseudo-classes: :link and :visited + // https://www.w3.org/TR/selectors-4/#the-link-pseudo + + static constexpr PseudoClass LINK = "link"s; + + static constexpr PseudoClass VISITED = "visited"s; + + // 8.3. The Local Link Pseudo-class: :local-link + // https://www.w3.org/TR/selectors-4/#the-local-link-pseudo + + static constexpr PseudoClass LOCAL_LINK = "local-link"s; + + // 8.4. The Target Pseudo-class: :target + // https://www.w3.org/TR/selectors-4/#the-target-pseudo + + static constexpr PseudoClass TARGET = "target"s; + + // 8.5. The Target Container Pseudo-class: :target-within + // https://www.w3.org/TR/selectors-4/#the-target-within-pseudo + + static constexpr PseudoClass TARGET_WITHIN = "target-within"s; + + // 8.6. The Reference Element Pseudo-class: :scope + // https://www.w3.org/TR/selectors-4/#the-scope-pseudo + + static constexpr PseudoClass SCOPE = "scope"s; + + // 9. MARK: User Action Pseudo-classes --- -------------------------------- + + // 9.1. The Pointer Hover Pseudo-class: :hover + // https://www.w3.org/TR/selectors-4/#the-hover-pseudo + + static constexpr PseudoClass HOVER = "hover"s; + + // 9.2. The Active Pseudo-class: :active + // https://www.w3.org/TR/selectors-4/#the-active-pseudo + + static constexpr PseudoClass ACTIVE = "active"s; + + // 9.3. The Input Focus Pseudo-class: :focus + // https://www.w3.org/TR/selectors-4/#the-focus-pseudo + + static constexpr PseudoClass FOCUS = "focus"s; + + // 9.4. The Focus-Indicated Pseudo-class: :focus-visible + // https://www.w3.org/TR/selectors-4/#the-focus-visible-pseudo + + static constexpr PseudoClass FOCUS_VISIBLE = "focus-visible"s; + + // 9.5. The Focus Within Pseudo-class: :focus-within + // https://www.w3.org/TR/selectors-4/#the-focus-within-pseudo + + static constexpr PseudoClass FOCUS_WITHIN = "focus-within"s; + + // 10. MARK: Time-dimensional Pseudo-classes ------------------------------- + + // 10.1. The Current Time Pseudo-class: :current + // https://www.w3.org/TR/selectors-4/#the-current-pseudo + + static constexpr PseudoClass CURRENT = "current"s; + + // 10.2. The Past Time Pseudo-class: :past + // https://www.w3.org/TR/selectors-4/#the-past-pseudo + + static constexpr PseudoClass PAST = "past"s; + + // 10.3. The Future Time Pseudo-class: :future + // https://www.w3.org/TR/selectors-4/#the-future-pseudo + + static constexpr PseudoClass FUTURE = "future"s; + + // 11. MARK: Resource State Pseudo-classes -------------------------------- + + // 11.1. Media Playback State: the :playing, :paused, and :seeking pseudo-classes + // https://www.w3.org/TR/selectors-4/#video-state + + static constexpr PseudoClass PLAYING = "playing"s; + + static constexpr PseudoClass PAUSED = "paused"s; + + static constexpr PseudoClass SEEKING = "seeking"s; + + // 11.2. Media Loading State: the :buffering and :stalled pseudo-classes + // https://www.w3.org/TR/selectors-4/#media-loading-state + + static constexpr PseudoClass BUFFERING = "buffering"s; + + static constexpr PseudoClass STALLED = "stalled"s; + + // 11.3. Sound State: the :muted and :volume-locked pseudo-classes + // https://www.w3.org/TR/selectors-4/#sound-state + + static constexpr PseudoClass MUTED = "muted"s; + + static constexpr PseudoClass VOLUME_LOCKED = "volume-locked"s; + + // 12. MARK: Element Display State Pseudo-classes -------------------------- + + // 12.1. Collapse State: the :open and :closed pseudo-class + // https://www.w3.org/TR/selectors-4/#open-state + + static constexpr PseudoClass OPEN = "open"s; + + static constexpr PseudoClass CLOSED = "closed"s; + + // 12.2. Modal (Exclusive Interaction) State: the :modal pseudo-class + // https://www.w3.org/TR/selectors-4/#modal-state + + static constexpr PseudoClass MODAL = "modal"s; + + // 12.4. Picture-in-Picture Presentation State: the :picture-in-picture pseudo-class + // https://www.w3.org/TR/selectors-4/#picture-in-picture-state + + static constexpr PseudoClass PICTURE_IN_PICTURE = "picture-in-picture"s; + + // 13. MARK: The Input Pseudo-classes -------------------------------------- + + // 13.1.1. The :enabled and :disabled Pseudo-classes + // https://www.w3.org/TR/selectors-4/#enableddisabled + + static constexpr PseudoClass ENABLED = "enabled"s; + + static constexpr PseudoClass DISABLED = "disabled"s; + + // 13.1.2. The Mutability Pseudo-classes: :read-only and :read-write + // https://www.w3.org/TR/selectors-4/#readonlyreadwrite + + static constexpr PseudoClass READ_ONLY = "read-only"s; + + static constexpr PseudoClass READ_WRITE = "read-write"s; + + // 13.1.3. The Placeholder-shown Pseudo-class: :placeholder-shown + // https://www.w3.org/TR/selectors-4/#placeholder + + static constexpr PseudoClass PLACEHOLDER_SHOWN = "placeholder-shown"s; + + // 13.1.4. The Automatic Input Pseudo-class: :autofill + // https://www.w3.org/TR/selectors-4/#autofill + + static constexpr PseudoClass AUTOFILL = "autofill"s; + + // 13.1.5. The Default-option Pseudo-class: :default + // https://www.w3.org/TR/selectors-4/#the-default-pseudo + + static constexpr PseudoClass DEFAULT = "default"s; + + // 13.2.1. The Selected-option Pseudo-class: :checked + // https://www.w3.org/TR/selectors-4/#checked + + static constexpr PseudoClass CHECKED = "checked"s; + + // 13.2.2. The Indeterminate-value Pseudo-class: :indeterminate + // https://www.w3.org/TR/selectors-4/#indeterminate + + static constexpr PseudoClass INDETERMINATE = "indeterminate"s; + + // 13.3.1. The Empty-Value Pseudo-class: :blank + // https://www.w3.org/TR/selectors-4/#blank + + static constexpr PseudoClass BLANK = "blank"s; + + // 13.3.2. The Validity Pseudo-classes: :valid and :invalid + // https://www.w3.org/TR/selectors-4/#validity + + static constexpr PseudoClass VALID = "valid"s; + + // 13.3.3. The Range Pseudo-classes: :in-range and :out-of-range + // https://www.w3.org/TR/selectors-4/#range-pseudos + + static constexpr PseudoClass IN_RANGE = "in-range"s; + + static constexpr PseudoClass OUT_OF_RANGE = "out-of-range"s; + + // 13.3.4. The Optionality Pseudo-classes: :required and :optional + // https://www.w3.org/TR/selectors-4/#opt-pseudos + + static constexpr PseudoClass REQUIRED = "required"s; + + static constexpr PseudoClass OPTIONAL = "optional"s; + + // 13.3.5. The User-interaction Pseudo-classes: :user-valid and :user-invalid + // https://www.w3.org/TR/selectors-4/#user-pseudos + + static constexpr PseudoClass USER_VALID = "user-valid"s; + + static constexpr PseudoClass USER_INVALID = "user-invalid"s; + + // 14. MARK: Tree-Structural pseudo-classes -------------------------------- + + // 14.1. :root pseudo-class + // https://www.w3.org/TR/selectors-4/#the-root-pseudo + + static constexpr PseudoClass ROOT = "root"s; + + // 14.2. :empty pseudo-class + // https://www.w3.org/TR/selectors-4/#the-empty-pseudo + + static constexpr PseudoClass EMPTY = "empty"s; + + // 14.3.1. :nth-child() pseudo-class + // https://www.w3.org/TR/selectors-4/#the-nth-child-pseudo + + struct NthChildPseudoClass { + AnB anb; + }; + + // 14.3.2. :nth-last-child() pseudo-class + // https://www.w3.org/TR/selectors-4/#the-nth-last-child-pseudo + + struct NthLastChildPseudoClass { + AnB anb; + }; + + // 14.3.3. :first-child pseudo-class + // https://www.w3.org/TR/selectors-4/#the-first-child-pseudo + + struct FirstChildPseudoClass { + }; + + // 14.3.4. :last-child pseudo-class + // https://www.w3.org/TR/selectors-4/#the-last-child-pseudo + + struct LastChildPseudoClass { + }; + + // 14.3.5. :only-child pseudo-class + // https://www.w3.org/TR/selectors-4/#the-only-child-pseudo + + struct OnlyChildPseudoClass { + }; + + // 14.4.1. :nth-of-type() pseudo-class + // https://www.w3.org/TR/selectors-4/#the-nth-of-type-pseudo + + struct NthOfTypePseudoClass { + AnB anb; + }; + + // 14.4.2. :nth-last-of-type() pseudo-class + // https://www.w3.org/TR/selectors-4/#the-nth-last-of-type-pseudo + + struct NthLastOfTypePseudoClass { + AnB anb; + }; + + // 14.4.3. :first-of-type pseudo-class + // https://www.w3.org/TR/selectors-4/#the-first-of-type-pseudo + static constexpr PseudoClass FIRST_OF_TYPE = "first-of-type"s; + + // 14.4.4. :last-of-type pseudo-class + // https://www.w3.org/TR/selectors-4/#the-last-of-type-pseudo + + static constexpr PseudoClass ONLY_OF_TYPE = "last-of-type"s; + + // 14.4.5. :only-of-type pseudo-class + // https://www.w3.org/TR/selectors-4/#the-only-of-type-pseudo + + static constexpr PseudoClass ONLY_OF_TYPE = "only-of-type"s; + + // 15. MARK: Combinators --------------------------------------------------- + + // 15.1. Descendant combinator ( ) + // https://www.w3.org/TR/selectors-4/#child-combinators + + struct DescendantCombinator { + Box _lhs; + Box _rhs; + }; + + // 15.2. Child combinator (>) + // https://www.w3.org/TR/selectors-4/#adjacent-sibling-combinators + + struct ChildCombinator { + Box _lhs; + Box _rhs; + }; + + // 15.3. Next-sibling combinator (+) + // https://www.w3.org/TR/selectors-4/#adjacent-sibling-combinators + + struct NextSiblingCombinator { + Box _lhs; + Box _rhs; + }; + + // 15.4. Subsequent-sibling combinator (~) + // https://www.w3.org/TR/selectors-4/#general-sibling-combinators + + struct SubsequentSiblingCombinator { + Box _lhs; + Box _rhs; + }; + + // 16. MARK: Grid-Structural Selectors ------------------------------------- + + // 16.1. Column combinator (||) + // https://www.w3.org/TR/selectors-4/#the-column-combinator + + struct ColumnCombinator { + Box _lhs; + Box _rhs; + }; + + // 16.2. :nth-col() pseudo-class + // https://www.w3.org/TR/selectors-4/#the-nth-col-pseudo + + struct NthColPseudoClass { + AnB anb; + }; + + // 16.3. :nth-last-col() pseudo-class + // https://www.w3.org/TR/selectors-4/#the-nth-col-pseudo + + using _Store = Union< + ListCombinator, + IsPseudoClass, + NegationPseudoClass, + WherePseudoClass, + HasPseudoClass, + UniversalSelector, + TypeSelector, + AttributeSelector, + ClassSelector, + IdSelector, + RootPseudoClass, + EmptyPseudoClass, + NthChildPseudoClass, + NthLastChildPseudoClass, + ColumnCombinator>; + + _Store _store; +}; + +} // namespace Web::Select diff --git a/src/web/web-select/select2.h b/src/web/web-select/select2.h new file mode 100644 index 0000000000..8b94b9a693 --- /dev/null +++ b/src/web/web-select/select2.h @@ -0,0 +1,62 @@ +#pragma once + +#include +#include +#include + +namespace Web::Select { + +struct Selector; + +struct Combinator { + enum struct _Type { + LIST, + DESCENDANT, + CHILD, + ADJACENT, + SUBSEQUENT, + COLUMN + }; + + using enum _Type; + _Type type; + Box lhs; + Box rhs; +}; + +struct LogicalCombinator { + enum struct _Type { + IS, + NOT, + WHERE, + HAS, + }; + + _Type type; + Box inner; +}; + +struct TypeSelector { + TagName type; +}; + +struct IdSelector { + String id; +}; + +struct ClassSelector { + String class_; +}; + +using _Selector = Union< + Combinator, + LogicalCombinator, + TypeSelector, + IdSelector, + ClassSelector>; + +struct Selector : public _Selector { + using _Selector::_Selector; +}; + +} // namespace Web::Select diff --git a/src/web/web-select/tests/test-selector.cpp b/src/web/web-select/tests/test-selector.cpp new file mode 100644 index 0000000000..129fe134cf --- /dev/null +++ b/src/web/web-select/tests/test-selector.cpp @@ -0,0 +1,13 @@ +// Copyright © 2018-2024, the skiftOS Developers +// Copyright © 2024, Odoo S.A. +// +// SPDX-License-Identifier: MIT + +#include +#include + +namespace Web::Select::Tests { + +test$("") {} + +} // namespace Web::Select::Tests diff --git a/src/web/web-view/view.cpp b/src/web/web-view/view.cpp index 589a233c64..c736965f0a 100644 --- a/src/web/web-view/view.cpp +++ b/src/web/web-view/view.cpp @@ -6,6 +6,10 @@ namespace Web::View { struct View : public Ui::View { + Strong _dom; + + View(Strong dom) : _dom(dom) {} + void paint(Gfx::Context &g, Math::Recti) override { g.save(); g.clear(bound(), Css::WHITE); @@ -17,8 +21,8 @@ struct View : public Ui::View { } }; -Ui::Child view(Strong) { - return makeStrong(); +Ui::Child view(Strong dom) { + return makeStrong(dom); } } // namespace Web::View