Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8347153

Support tree-structural pseudo-classes

XMLWordPrintable

    • Icon: CSR CSR
    • Resolution: Approved
    • Icon: P4 P4
    • jfx24, jfx25
    • javafx
    • None
    • behavioral
    • minimal
    • No compatibility risk is expected.
    • Java API, File or wire format

      Summary

      Add tree-structural pseudo-classes to JavaFX.

      Problem

      Currently, nodes can't be selected in CSS based on their index position relative to their siblings. The root node can be selected with the non-standard style class .root, but not with the :root pseudo-class.

      Solution

      Add the following tree-structural pseudo-classes to JavaFX:

      • :root
      • :first-child
      • :last-child
      • :only-child
      • :nth-child() with arguments even and odd

      The An+B [of S]? microsyntax for :nth-child() is not supported, as this would require major changes in JavaFX CSS.

      Specification

      --- a/modules/javafx.graphics/src/main/docs/javafx/scene/doc-files/cssref.html
      +++ b/modules/javafx.graphics/src/main/docs/javafx/scene/doc-files/cssref.html
      @@ -539,8 +539,7 @@
           <p>
               JavaFX CSS also supports pseudo&#8209;classes, but does not implement the full range of pseudo&#8209;classes as
               specified in <a href="http://www.w3.org/TR/css3-selectors/#pseudo-classes">Pseudo&#8209;classes</a>. The pseudo&#8209;classes
      -        supported by each Node type are given in the tables within this reference. Note that JavaFX does not currently
      -        support structural pseudo&#8209;classes.
      +        supported by each Node type are given in the tables within this reference.
           </p>
           <p>
               Each node honors a set of properties that depends on the node's JavaFX
      @@ -869,7 +868,6 @@
               syntax not specified in this document.</li>
           <li>With the exception of @font&#8209;face and @import, @-keyword statements are ignored.</li>
           <li>The &lt;media-query-list&gt; of the @import statement is not parsed.</li>
      -    <li>The structural pseudo&#8209;classes are not supported. </li>
           <li>The ":active" and ":focus" dynamic pseudo&#8209;classes are not supported.
               However, <a href="#node">Nodes</a> do support the ":pressed" and
               ":focused" pseudo&#8209;classes, which are similar. </li>
      @@ -1529,7 +1527,7 @@
             with the "style" property on a node.</p>
           <p>In the following example, all background color of all buttons uses the
             looked up color "abc".</p>
      -    <p class="example">.root { abc: #f00 }<br>
      +    <p class="example">:root { abc: #f00 }<br>
             .button { -fx-background-color: abc }</p>
           <h4>RGB Colors <span class="grammar" style="font-size: smaller;">&lt;rgb-color&gt;</span></h4>
           <p>The RGB color model is used in numerical color specifications. It has a
      @@ -1825,11 +1823,11 @@
               </tbody>
           </table>
           <h4><a id="popupwindow">Group</a></h4>
      -    <p class="styleclass">Style class: .root.popup</p>
      +    <p class="styleclass">Style class: :root.popup</p>
           <p>PopupWindow does not have any properties that can be styled by CSS, but a PopupWindow does have its own Scene.
      -        Scene's root gets the .root style-class by default. If the Scene is the root scene of a PopupWindow, then the
      +        Scene's root gets the :root pseudo-class by default. If the Scene is the root scene of a PopupWindow, then the
               .popup style-class is also added. This allows the root scene of a PopupWindow to have distinct styles via
      -        the CSS rule <code>.root.popup { /* declarations */ }</code>
      +        the CSS rule <code>:root.popup { /* declarations */ }</code>
           <h2><a id="nodes">Nodes</a></h2>
           <table class="package" width="100%">
             <tbody>
      @@ -2002,41 +2000,63 @@
           <h4>Pseudo-classes</h4>
           <table class="csspropertytable">
           <caption>Available CSS Pseudo-classes</caption>
      -      <thead>
      -        <tr>
      -        <th class="propertyname" scope="col">CSS Pseudo-class</th>
      -        <th scope="col">Comments</th>
      -        </tr>
      -      </thead>
             <tbody>
               <tr>
      -        <th class="propertyname" scope="row">disabled</th>
      -          <td>applies when the <strong>disabled</strong> variable is true</td>
      +          <th class="propertyname subheader" scope="col">User Action Pseudo-classes</th>
      +          <th class="subheader" scope="col">Comments</th>
               </tr>
               <tr>
      -        <th class="propertyname" scope="row">focused</th>
      +          <th class="propertyname" scope="row">focused</th>
                 <td>applies when the <strong>focused</strong> variable is true</td>
               </tr>
               <tr>
      -        <th class="propertyname" scope="row">focus-visible</th>
      +          <th class="propertyname" scope="row">focus-visible</th>
                 <td>applies when the <strong>focusVisible</strong> variable is true</td>
               </tr>
               <tr>
      -        <th class="propertyname" scope="row">focus-within</th>
      +          <th class="propertyname" scope="row">focus-within</th>
                 <td>applies when the <strong>focusWithin</strong> variable is true</td>
               </tr>
               <tr>
      -        <th class="propertyname" scope="row">hover</th>
      +          <th class="propertyname" scope="row">hover</th>
                 <td>applies when the <strong>hover</strong> variable is true</td>
               </tr>
               <tr>
      -        <th class="propertyname" scope="row">pressed</th>
      +          <th class="propertyname" scope="row">pressed</th>
                 <td>applies when the <strong>pressed</strong> variable is true</td>
               </tr>
               <tr>
      -        <th class="propertyname" scope="row">show-mnemonic</th>
      -          <td>apples when the mnemonic affordance (typically an underscore)
      -            should be shown.</td>
      +          <th class="propertyname subheader" scope="col">Input Pseudo-classes</th>
      +          <th class="subheader" scope="col">Comments</th>
      +        </tr>
      +        <tr>
      +          <th class="propertyname" scope="row">disabled</th>
      +          <td>applies when the <strong>disabled</strong> variable is true</td>
      +        </tr>
      +        <tr>
      +          <th class="propertyname" scope="row">show-mnemonic</th>
      +          <td>applies when the mnemonic affordance (typically an underscore) should be shown</td>
      +        </tr>
      +        <tr>
      +          <th class="propertyname subheader" scope="col">Tree-Structural Pseudo-classes</th>
      +          <th class="subheader" scope="col">Comments</th>
      +        </tr>
      +        <tr>
      +          <th class="propertyname" scope="row">first-child</th>
      +          <td>applies when the node is the first child in its <code>Parent</code> container</td>
      +        </tr>
      +        <tr>
      +          <th class="propertyname" scope="row">last-child</th>
      +          <td>applies when the node is the last child in its <code>Parent</code> container</td>
      +        </tr>
      +        <tr>
      +          <th class="propertyname" scope="row">only-child</th>
      +          <td>applies when the node is the only child in its <code>Parent</code> container</td>
      +        </tr>
      +        <tr>
      +          <th class="propertyname" scope="row">nth-child(even | odd)</th>
      +          <td>applies when the node is the n-th child in its <code>Parent</code> container
      +              (the first child at index 0 matches "odd", the second child at index 1 matches "even", etc.)</td>
               </tr>
             </tbody>
           </table>
      @@ -2062,6 +2082,25 @@
               </tr>
             </tbody>
           </table>
      +    <h4>Pseudo-classes</h4>
      +    <table class="csspropertytable">
      +        <caption>Available CSS Pseudo-classes</caption>
      +        <thead>
      +        <tr>
      +            <th class="propertyname" scope="col">CSS Pseudo-class</th>
      +            <th scope="col">Comments</th>
      +        </tr>
      +        </thead>
      +        <tbody>
      +        <tr>
      +            <th class="propertyname" scope="row">root</th>
      +            <td>applies when the <code>Parent</code> is the root node of a <code>Scene</code> or <code>SubScene</code></td>
      +        </tr>
      +        <tr>
      +            <td colspan="2" class="parents" scope="row">Also has all pseudo&#8209;classes of <a href="#node">Node</a></td>
      +        </tr>
      +        </tbody>
      +    </table>
           <br>
           <h4><a id="scene">Scene</a></h4>
           <p class="styleclass">Style class: not applicable<br>
      @@ -2067,7 +2106,8 @@
           <p class="styleclass">Style class: not applicable<br>
           </p>
           <p>The Scene object has no settable CSS properties, nor does it have any
      -      pseudo&#8209;classes. However, the root node of the scene is assigned the style
      +      pseudo&#8209;classes. However, the root node of the scene matches the
      +      structural pseudo-class <code>:root</code>, as well as the legacy style
             class "root" (in addition to style classes already assigned to the node).
             This is useful because the root node of Scene is the root container for
             all active scene&#8209;graph nodes. Thus, it can serve as a container for
      @@ -4294,7 +4334,7 @@
           <p>The PasswordField control has all the properties of <a href="#textfield">TextField</a></p>
           <h4><a id="popupcontrol">PopupControl</a></h4>
           <p>PopupControl is also a <a href="#popupwindow">PopupWindow</a> and as such, its root node has the
      -    style-class .root.popup</p>
      +    style-class :root.popup</p>
           <h4><a id="progressbar">ProgressBar</a></h4>
           <p class="styleclass">Style class: progress-bar</p>
           <table class="csspropertytable">
      --- a/modules/javafx.graphics/src/main/java/javafx/scene/Scene.java
      +++ b/modules/javafx.graphics/src/main/java/javafx/scene/Scene.java
      @@ -1206,7 +1207,9 @@
            * layout of the scene graph.    If a resizable node (layout {@code Region} or
            * {@code Control}) is set as the root, then the root's size will track the
            * scene's size, causing the contents to be relayed out as necessary.
      -     *
      +     * <p>
      +     * The {@code :root} pseudo-class matches the root node.
      +     * <p>
            * Scene doesn't accept null root.
            *
            */
      --- a/modules/javafx.graphics/src/main/java/javafx/scene/SubScene.java
      +++ b/modules/javafx.graphics/src/main/java/javafx/scene/SubScene.java
      @@ -256,7 +257,9 @@
            * Defines the root {@code Node} of the {@code SubScene} scene graph.
            * If a {@code Group} is used as the root, the
            * contents of the scene graph will be clipped by the {@code SubScene}'s width and height.
      -     *
      +     * <p>
      +     * The {@code :root} pseudo-class matches the root node.
      +     * <p>
            * {@code SubScene} doesn't accept null root.
            *
            */

            mstrauss Michael Strauß
            mstrauss Michael Strauß
            Kevin Rushforth
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: