rcdom: selectedcontent lookup reads self.data, option clone never runs

オープン 初心者向け
#776 コメント 1 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

@jdm がすでに取り組んでいます。

2026年8月21日 から。

  • #777 @jdm による — オープン
  • #783 @rushikeshgarad2024-dev による — オープン

評価

難易度
1/5
見積もり時間
1時間未満
初心者へのやさしさ
90/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
rust
領域
web-dev

調査の方向性

rcdom/lib.rs の Node::get_a_selects_enabled_selectedcontent から始め、issue で説明されている子孫ループを調べます。提供された cargo reproducer を実行し、修正後に selectedcontent 要素がクローンされた子を 1 つ含み、期待どおりにシリアライズされることを確認します。

索引モデルが issue の本文から書いたものです。

説明

Observed

Parsing HTML with a customizable select leaves the <selectedcontent> element empty. Node::get_a_selects_enabled_selectedcontent in rcdom/lib.rs walks the descendants of the select, but the pattern match inside the loop reads &self.data instead of &node.data (line 205 on main, line 213 in the published markup5ever_rcdom 0.39.0+unofficial). self is the select element itself, so the local_name!("selectedcontent") comparison fails on every iteration and the function always returns None. As a result the maybe_clone_an_option_into_selectedcontent callback from #719 never clones anything, whether it is invoked by the html5ever tree builder or called directly on a correctly shaped tree.

Expected

Per https://html.spec.whatwg.org/#clone-an-option-into-a-selectedcontent, closing a selected option inside a select that holds an enabled selectedcontent should replace the children of that selectedcontent with clones of the option's children. Changing the match to &node.data produces exactly that tree.

Reproducer

cargo new sc-repro && cd sc-repro
cargo add [email protected] [email protected]

src/main.rs:

use html5ever::tendril::TendrilSink;
use html5ever::{parse_document, serialize};
use markup5ever_rcdom::{Handle, NodeData, RcDom, SerializableHandle};

fn find(h: &Handle, name: &str, out: &mut Vec<Handle>) {
    if let NodeData::Element { name: n, .. } = &h.data {
        if &*n.local == name {
            out.push(h.clone());
        }
    }
    for child in h.children.borrow().iter() {
        find(child, name, out);
    }
}

fn main() {
    let input = "<select><button><selectedcontent></selectedcontent></button>\
                 <option selected>Hello</option></select>";
    let dom = parse_document(RcDom::default(), Default::default()).one(input);
    let mut buf = Vec::new();
    let doc: SerializableHandle = dom.document.clone().into();
    serialize(&mut buf, &doc, Default::default()).unwrap();
    println!("serialized: {}", String::from_utf8(buf).unwrap());
    let mut sc = Vec::new();
    find(&dom.document, "selectedcontent", &mut sc);
    println!("selectedcontent children: {}", sc[0].children.borrow().len());
}

Output with 0.39.0:

serialized: <html><head></head><body><select><button><selectedcontent></selectedcontent></button><option selected="">Hello</option></select></body></html>
selectedcontent children: 0

With the one word fix (&node.data on the line noted above) the same program prints <selectedcontent>Hello</selectedcontent> and a child count of 1.

Scope

Every code path through maybe_clone_an_option_into_selectedcontent returns without touching the tree, so the callback introduced in #719 never runs its clone step. Any DOM built with markup5ever_rcdom 0.39.0, by parsing or by direct TreeSink calls, leaves each <selectedcontent> element with whatever children it had before the option closed.

主要言語
Rust
スター
2.6k
フォーク
299
平均マージ
17時間 29分
マージ済み PR(30日)
4

環境構築

このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

servo/html5ever のほかの issue

servo/html5ever の issue をすべて見る

似ている issue

Rust の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。