pub struct DomBridge {Show 18 fields
pub nodes: Vec<DomNode>,
pub listeners: Vec<Listener>,
pub dirty: bool,
pub built: bool,
pub rects: BTreeMap<usize, (i32, i32, i32, i32)>,
pub border_widths: BTreeMap<usize, (i32, i32, i32, i32)>,
pub computed_styles: BTreeMap<usize, BTreeMap<String, String>>,
pub scroll_tops: BTreeMap<usize, i32>,
pub scroll_heights: BTreeMap<usize, i32>,
pub next_listener_id: u64,
pub mut_observers: Vec<MutObsReg>,
pub mut_records: Vec<(u32, MutRec)>,
pub next_mut_obs_id: u32,
pub pointer_captures: BTreeSet<(usize, i32)>,
pub focused_idx: Option<usize>,
pub pending_scroll_abs_y: Option<i32>,
pub pending_scroll_by_y: Option<i32>,
pub on_handlers: BTreeMap<(usize, String), Value>,
}Expand description
DOM ブリッジ本体。JsRuntime が Rc<RefCell<>> で保持し、レンダラと共有する。
Fields§
§nodes: Vec<DomNode>§listeners: Vec<Listener>§dirty: boolJS が DOM を変更したフラグ。ホストはこれを見て再レイアウトする。
built: bool構築済みかどうか(未構築なら getElementById 等は空を返す)。
rects: BTreeMap<usize, (i32, i32, i32, i32)>レイアウト後の要素矩形 (x, y, w, h)(ページ座標)。getBoundingClientRect / offsetWidth 等が参照。レンダラが flatten 後に populate する。
border_widths: BTreeMap<usize, (i32, i32, i32, i32)>レイアウト後の各要素のborder幅 (top, right, bottom, left)。
computed_styles: BTreeMap<usize, BTreeMap<String, String>>算出スタイル(カスケード後の specified_values、kebab-case キー)。 getComputedStyle が参照。レンダラがスタイル適用後に populate する。
scroll_tops: BTreeMap<usize, i32>サブスクロールコンテナの現在 scrollTop (node_idx → px)。
JS が el.scrollTop = N で書き込み、レンダラが再レイアウト後に同期する。
scroll_heights: BTreeMap<usize, i32>サブスクロールコンテナの scrollHeight (node_idx → px)。 レンダラが parse_and_layout 後に populate する(コンテナ高 + scroll_max_y)。
next_listener_id: u64リスナ ID の発番カウンタ(once / removeEventListener 照合用)。
mut_observers: Vec<MutObsReg>登録済み MutationObserver。
mut_records: Vec<(u32, MutRec)>DOM 変更時に積まれるレコードキュー(observer_id, record)。
next_mut_obs_id: u32MutationObserver の ID 発番カウンタ。
pointer_captures: BTreeSet<(usize, i32)>setPointerCapture/releasePointerCapture/hasPointerCapture
(Pointer Events。丸ごと未対応だった)が捕捉中の (node_idx, pointerId) 集合。
この処理系のイベント配信はヒットテストベースのため、実際にその後の
pointer イベントをこの要素へ強制配送するところまでは配線しない
(hasPointerCapture が仕様どおりの真偽を返せるようにする状態管理のみの
簡略実装。inert 属性のポインタ操作抑制のみ実装と同種の部分対応)。
focused_idx: Option<usize>document.activeElement/element.focus()/.blur()(HTML5。丸ごと
未対応だった)。現在フォーカス中のノード index。WebEngine::focused_id
(レンダラ側の文字列キー版フォーカス状態)とは別に、JS 側から直接
読み書きできる node index ベースの状態としてここに持つ。レンダラの
実クリック/autofocus によるフォーカス変更も同期される(詳細は
layout.rs/render.rs の focused_id 代入箇所を参照)。id/name 属性を
持たない要素へのレンダラ起点フォーカスは同期対象外(レンダラ自身の
既存の制約と同じ)。
pending_scroll_abs_y: Option<i32>window.scrollTo(x, y)/window.scroll(x, y)(丸ごと未対応だった。
実装はあったが SCROLL_Y という孤立した static へ書き込むのみで、
window.scrollY/実際のレンダラ描画位置のどちらにも一切反映されない
死んだ経路だった。2026-07-16 発見)。JS→レンダラの片方向同期用の
「保留中の絶対スクロール先」。focused_idxと同じ「レンダラが毎フレーム
消費する」設計だが、フォーカスと違い同一フレーム内での即時反映が
不要(次の描画で反映されれば十分)なため、render.rsのdraw()冒頭
1箇所でのみ消費すればよく、.focus()のような10箇所以上への配線は
不要(改修規模がずっと小さい)。
pending_scroll_by_y: Option<i32>window.scrollBy(x, y)(丸ごと未対応だった。dom_noopのまま)。
複数回呼ばれた場合は加算し、次の描画で一括反映する。
on_handlers: BTreeMap<(usize, String), Value>element.onchange = fnのような GlobalEventHandlers IDL 属性(関数値)の
永続的な保管先。以前はObj::dom(idx)(呼び出す度に新規生成される使い捨ての
ラッパーオブジェクト)自身の.propsへ書き込んでいたため、代入直後に
そのRcが破棄されると値ごと消え、dispatchEvent側が同じObj::dom(idx)を
新規生成して読み直しても常に見つからない(=ハンドラが一切発火しない)
静かなバグだった。listeners(addEventListener系)と同じくDOM構造体側に
持たせることで、どのObj::dom(idx)インスタンス経由でも一貫して読み書き
できるようにする。キーは(node_idx, "onchange"等のプロパティ名)。
Implementations§
Source§impl DomBridge
impl DomBridge
pub fn new() -> Self
Sourcepub fn set_on_handler(&mut self, node: usize, key: &str, val: Value)
pub fn set_on_handler(&mut self, node: usize, key: &str, val: Value)
element.onXXX = fn(関数値)の永続的な書き込み。
Sourcepub fn get_on_handler(&self, node: usize, key: &str) -> Option<Value>
pub fn get_on_handler(&self, node: usize, key: &str) -> Option<Value>
element.onXXXの読み出し。未設定ならNone。
Sourcepub fn set_pointer_capture(&mut self, idx: usize, pointer_id: i32)
pub fn set_pointer_capture(&mut self, idx: usize, pointer_id: i32)
element.setPointerCapture(pointerId)。
Sourcepub fn release_pointer_capture(&mut self, idx: usize, pointer_id: i32)
pub fn release_pointer_capture(&mut self, idx: usize, pointer_id: i32)
element.releasePointerCapture(pointerId)。
Sourcepub fn has_pointer_capture(&self, idx: usize, pointer_id: i32) -> bool
pub fn has_pointer_capture(&self, idx: usize, pointer_id: i32) -> bool
element.hasPointerCapture(pointerId)。
Sourcefn notify_child_list(
&mut self,
parent_idx: usize,
added: Vec<usize>,
removed: Vec<usize>,
)
fn notify_child_list( &mut self, parent_idx: usize, added: Vec<usize>, removed: Vec<usize>, )
MutationObserver: childList 変化を記録するヘルパ。
Sourcefn notify_attribute(
&mut self,
idx: usize,
attr_name: &str,
old_value: Option<&str>,
)
fn notify_attribute( &mut self, idx: usize, attr_name: &str, old_value: Option<&str>, )
MutationObserver: 属性変化を記録するヘルパ。attributeFilter が指定された
観察者はその一覧に無い属性名を無視し、attributeOldValue が指定された
観察者にのみ変更前の値をレコードへ積む(以前はどちらのオプションも
読み取られておらず、attributeFilter 指定時も無関係な属性の変化まで
全て通知され、oldValue は常に null 固定だった)。
Sourcefn notify_character_data(&mut self, idx: usize, old_value: Option<&str>)
fn notify_character_data(&mut self, idx: usize, old_value: Option<&str>)
MutationObserver: テキストノードの内容変化を記録するヘルパ(丸ごと
未対応だった。notify_attributeと対になるcharacterData版。
idxは変化したテキストノード自身のインデックス〔仕様上
CharacterDataのmutationはテキストノード自身がtargetになる〕。
2026-07-17 発見・実装)。
Sourcepub fn set_rect(&mut self, idx: usize, x: i32, y: i32, w: i32, h: i32)
pub fn set_rect(&mut self, idx: usize, x: i32, y: i32, w: i32, h: i32)
レンダラがレイアウト後に要素矩形を登録する(getBoundingClientRect 等が参照)。
pub fn get_rect(&self, idx: usize) -> Option<(i32, i32, i32, i32)>
pub fn set_border_widths( &mut self, idx: usize, top: i32, right: i32, bottom: i32, left: i32, )
pub fn get_border_widths(&self, idx: usize) -> (i32, i32, i32, i32)
pub fn clear_rects(&mut self)
Sourcepub fn set_computed_style(&mut self, idx: usize, prop: &str, val: &str)
pub fn set_computed_style(&mut self, idx: usize, prop: &str, val: &str)
算出スタイルを登録(kebab-case プロパティ→値)。
Sourcepub fn get_computed(&self, idx: usize, prop: &str) -> String
pub fn get_computed(&self, idx: usize, prop: &str) -> String
算出スタイルを取得(無ければインライン style → 空)。
pub fn clear_computed(&mut self)
Sourcepub fn build_from(&mut self, root: &Node)
pub fn build_from(&mut self, root: &Node)
新しいページの DOM 木からブリッジを再構築する(リスナはクリア)。
Sourcefn collect(node: &Node, parent: Option<usize>, out: &mut Vec<DomNode>) -> usize
fn collect(node: &Node, parent: Option<usize>, out: &mut Vec<DomNode>) -> usize
木をドキュメント順(プリオーダ)に再帰収集。子インデックスを記録する。
Sourcefn collect_text(&self, idx: usize) -> String
fn collect_text(&self, idx: usize) -> String
部分木のテキストを連結(textContent 相当)。現在値(override 優先)で集約。
fn collect_text_into(&self, idx: usize, out: &mut String)
Sourcepub fn build_id_index(&self) -> BTreeMap<&str, usize>
pub fn build_id_index(&self) -> BTreeMap<&str, usize>
id → ノード添字の対応表を 1 回で作る。
【2026-08-05】get_element_by_id は全ノードの線形走査で、
しかも各ノードで is_attached が親を辿る。
レイアウト後の矩形反映では要素 1 個ごとにこれを呼んでおり、
O(要素 × ノード × 深さ) になっていた(実測で要素・ノードとも約 369)。
走査 1 回で表を作れば、引く側は O(log N) で済む。
条件(テキストノードでない・id が空でない・ルートから到達可能)は
get_element_by_id と揃えてある。同じ id が複数あれば先勝ち
(find と同じ)。
計算量: O(N × D)(N はノード数、D は木の深さ)。
pub fn get_element_by_id(&self, id: &str) -> Option<usize>
Sourcepub fn is_attached(&self, idx: usize) -> bool
pub fn is_attached(&self, idx: usize) -> bool
node[0](ルート)から到達可能か。createElement 直後や remove 済みは false。
node.isConnected(丸ごと未対応だった)向けに公開する。
Sourcepub fn query(&self, selector: &str) -> Option<usize>
pub fn query(&self, selector: &str) -> Option<usize>
単純セレクタ(#id / .class / tag、先頭一致)にマッチする最初のノード。
Sourcepub fn query_all(&self, selector: &str) -> Vec<usize>
pub fn query_all(&self, selector: &str) -> Vec<usize>
セレクタにマッチする全ノード(ドキュメント順)。以前は node_matches と同じ
単純セレクタ限定の簡略実装が独立に重複しており、querySelectorAll('div.active')
等のコンパウンドセレクタが常に空になる同型のバグだった。node_matches と
共通の compound_matches/match_selector_chain に統一して解消する。
Sourcepub fn query_all_scoped(
&self,
selector: &str,
scope_root: Option<usize>,
) -> Vec<usize>
pub fn query_all_scoped( &self, selector: &str, scope_root: Option<usize>, ) -> Vec<usize>
query_all の :scope 対応版。element.querySelectorAll/querySelector
の起点要素を scope_root として渡すと、セレクタ中の :scope 疑似クラス
(Selectors Level 4。丸ごと未対応だった)がそのノードにのみ一致するように
なる(詳細は node_matches_scoped 参照)。
Sourcepub fn set_text_content(&mut self, idx: usize, val: &str)
pub fn set_text_content(&mut self, idx: usize, val: &str)
要素の textContent を設定。子孫テキストノードがあれば最初に値を入れ残りを空に、 無ければ既存の子を捨てて単一テキスト子を作る(createElement したノード等)。
Sourcepub fn normalize_node(&mut self, idx: usize)
pub fn normalize_node(&mut self, idx: usize)
node.normalize()(丸ごと未対応だった。DOM 標準メソッドで、連続する隣接テキスト
ノードを1つに連結し、空のテキストノードを取り除く。textContent を何度も
部分的に書き換えた後などに呼ばれる定番の掃除用メソッド)。子孫を再帰的に処理する。
Sourcefn text_of(&self, idx: usize) -> String
fn text_of(&self, idx: usize) -> String
テキストノードの実効テキスト(text_override があればそれ、無ければ
initial_text)。collect_text_into と同じ参照パターン。
fn new_element_node(&mut self, tag: &str) -> usize
fn new_text_node(&mut self, text: &str) -> usize
Sourcepub fn create_element(&mut self, tag: &str) -> usize
pub fn create_element(&mut self, tag: &str) -> usize
document.createElement(tag)。デタッチ状態のノードを返す。
Sourcepub fn create_text_node(&mut self, text: &str) -> usize
pub fn create_text_node(&mut self, text: &str) -> usize
document.createTextNode(text)。
Sourcepub fn create_comment(&mut self, text: &str) -> usize
pub fn create_comment(&mut self, text: &str) -> usize
document.createComment(text)。
Sourcepub fn create_document_fragment(&mut self) -> usize
pub fn create_document_fragment(&mut self) -> usize
document.createDocumentFragment()(丸ごと未対応だった)。仕様どおり、
#fragment という特殊タグの要素として表現する。この要素自身は決して
root から到達可能(is_attached)にならず、append_child/insert_before
に渡されると自身ではなく子要素群がそのまま挿入先へ移動し、自身は空になる
(実 DOM の DocumentFragment の「挿入すると中身だけが移動する」挙動を再現)。
Sourcepub fn template_content(&mut self, idx: usize) -> usize
pub fn template_content(&mut self, idx: usize) -> usize
template.content(<template> が丸ごと未対応だった)。仕様上 <template>
の子は「不活性」で通常の DOM ツリーには存在せず、代わりに .content
(DocumentFragment)経由でのみアクセスできる。この処理系は HTML パース時に
template を特別扱いしないため子が普通にライブツリーへ入ってしまうが、
初回アクセス時にその子を #fragment ノードへ移し替え(内部専用属性
_content_frag にフラグメントの index をキャッシュ)、以後は同じフラグメントを
返すことで「以後 <template> 自身は空、.content だけが中身を持つ」という
仕様どおりの見た目に近づける。
Sourcefn expand_fragment(&mut self, child: usize) -> Vec<usize>
fn expand_fragment(&mut self, child: usize) -> Vec<usize>
child が DocumentFragment(#fragment タグ)なら、その子要素群を
親から切り離して返し、フラグメント自身は空にする。それ以外は [child] を
そのまま返す(append_child/insert_before の共通前処理)。
Sourcepub fn append_child(&mut self, parent: usize, child: usize)
pub fn append_child(&mut self, parent: usize, child: usize)
parent.appendChild(child)。既存の親から外して付け替える。child が
DocumentFragment の場合は仕様どおりその子要素群を代わりに追加する。
Sourcepub fn remove_child(&mut self, parent: usize, child: usize)
pub fn remove_child(&mut self, parent: usize, child: usize)
parent.removeChild(child) / child.remove()。
pub fn remove_node(&mut self, idx: usize)
Sourcepub fn insert_before(
&mut self,
parent: usize,
new_child: usize,
ref_child: Option<usize>,
)
pub fn insert_before( &mut self, parent: usize, new_child: usize, ref_child: Option<usize>, )
parent.insertBefore(new_child, ref_child)。ref が None/不在なら末尾に追加。
new_child が DocumentFragment の場合は仕様どおりその子要素群を代わりに挿入する。
Sourcepub fn replace_child(
&mut self,
parent: usize,
new_child: usize,
old_child: usize,
)
pub fn replace_child( &mut self, parent: usize, new_child: usize, old_child: usize, )
parent.replaceChild(new_child, old_child)。old を new で置換。
Sourcepub fn clone_node(&mut self, idx: usize, deep: bool) -> usize
pub fn clone_node(&mut self, idx: usize, deep: bool) -> usize
node.cloneNode(deep)。属性/テキストをコピーした新ノードを作る(親なし)。deep なら子も再帰。
Sourcepub fn insert_adjacent_node(&mut self, idx: usize, position: &str, node: usize)
pub fn insert_adjacent_node(&mut self, idx: usize, position: &str, node: usize)
単一ノードを基準ノード idx の相対位置へ挿入(insertAdjacent* 共通)。
Sourcepub fn insert_adjacent_html(&mut self, idx: usize, position: &str, html: &str)
pub fn insert_adjacent_html(&mut self, idx: usize, position: &str, html: &str)
element.insertAdjacentHTML(position, html)。html をパースして相対位置へ挿入。
Sourcepub fn set_inner_html(&mut self, idx: usize, html: &str)
pub fn set_inner_html(&mut self, idx: usize, html: &str)
element.innerHTML = html。フラグメントをパースして子を置換する。
appendChild/removeChild/insertBefore/replaceChild は全て
notify_child_list 経由で MutationObserver に通知していたが、
innerHTML 代入だけがこの呼び出しを欠いており、最も頻繁に使われる
DOM 書き換え手段にもかかわらず childList 変化が一切観察できなかった。
Sourcepub fn set_outer_html(&mut self, idx: usize, html: &str)
pub fn set_outer_html(&mut self, idx: usize, html: &str)
element.outerHTML = html。自ノードを HTML パース結果のノード群で置き換える。
Sourcefn import_node(&mut self, node: &Node) -> usize
fn import_node(&mut self, node: &Node) -> usize
dom::Node 部分木をブリッジへ取り込み、ルート idx を返す。
Sourcepub fn to_dom_node(&self) -> Node
pub fn to_dom_node(&self) -> Node
ブリッジツリー(node[0] をルート)を dom::Node へ変換する。
JS の変更(textContent/style/class/動的ノード)が反映された描画用ツリー。
fn build_node(&self, idx: usize) -> Node
Sourcepub fn get_text_content(&self, idx: usize) -> String
pub fn get_text_content(&self, idx: usize) -> String
要素の textContent(現在値)を取得。
fn descendant_text_nodes(&self, idx: usize) -> Vec<usize>
fn descendant_text_into(&self, idx: usize, out: &mut Vec<usize>)
pub fn set_style(&mut self, idx: usize, prop: &str, val: &str)
pub fn get_style(&self, idx: usize, prop: &str) -> String
Sourcepub fn get_style_priority(&self, idx: usize, prop: &str) -> String
pub fn get_style_priority(&self, idx: usize, prop: &str) -> String
element.style.getPropertyPriority(name)(丸ごと未対応だった。
2026-07-16 発見)。!important は生の値文字列末尾にそのまま保持
されている(set_style/css_prop_from_camel 参照)ため、
strip_style_priority で判定するだけで済む。
Sourcepub fn get_css_text(&self, idx: usize) -> String
pub fn get_css_text(&self, idx: usize) -> String
element.style.cssText の読み出し。以前は丸ごと未対応で、cssText を単なる
通常の CSS プロパティ名として扱う既存の汎用経路(get_style)に落ちてしまい、
常に空文字列を返していた(serialize_inline_style 自体は属性文字列の再構築で
既に使われていたが、JS からの読み出しには配線されていなかった)。
Sourcepub fn set_css_text(&mut self, idx: usize, text: &str)
pub fn set_css_text(&mut self, idx: usize, text: &str)
element.style.cssText = "..." の書き込み。単一プロパティとして扱われ常に
無視されていたのを、既存のスタイル属性パーサ(parse_inline_style)で丸ごと
置き換えるよう実装する。
Sourcepub fn get_outer_html(&self, idx: usize) -> String
pub fn get_outer_html(&self, idx: usize) -> String
element.outerHTML(読み出し専用。書き込み側は要素の親子関係の組み替えが
必要で改修規模が大きいため今回は見送り)が丸ごと未対応だった。自身のタグ・属性
(id/class/style を含む)・子孫を再帰的に HTML 文字列へ直列化する。
Sourcepub fn get_inner_html(&self, idx: usize) -> String
pub fn get_inner_html(&self, idx: usize) -> String
element.innerHTML の読み出しが、実際にはマークアップ(子要素タグ)を含めず
textContent と同じ「全テキストを連結しただけ」の値を返してしまっていたバグ。
<div>a<b>bold</b></div> の innerHTML が仕様どおりの "a<b>bold</b>" ではなく
"abold" になっていた。自身のタグは含めず、子ノードだけを直列化する。
fn serialize_node_html(&self, idx: usize, out: &mut String)
pub fn class_add(&mut self, idx: usize, cls: &str)
pub fn class_remove(&mut self, idx: usize, cls: &str)
pub fn class_toggle(&mut self, idx: usize, cls: &str) -> bool
pub fn class_contains(&self, idx: usize, cls: &str) -> bool
Sourcefn collect_descendant_options(&self, idx: usize, out: &mut Vec<usize>)
fn collect_descendant_options(&self, idx: usize, out: &mut Vec<usize>)
<select>配下の<option>要素を全て集める(<optgroup>でグループ化
された<option>も含む再帰探索。丸ごと未対応だった。以前は直接の子
のみを見る実装だったため、`
Sourcepub fn select_options(&self, idx: usize) -> Vec<usize>
pub fn select_options(&self, idx: usize) -> Vec<usize>
<select> の option 子要素一覧(<optgroup>配下も含む)。select. options(丸ごと未対応だった。動的にドロップダウンを構築する定番
イディオムで使われる)向けに公開する。
Sourcefn option_value(&self, opt_idx: usize) -> String
fn option_value(&self, opt_idx: usize) -> String
option 要素の実効値: value 属性があればそれ、無ければテキスト内容
(仕様どおり。collect_form_data の select フォールバックと同じ規則)。
Sourcepub fn selected_option_indices(&self, idx: usize) -> Vec<usize>
pub fn selected_option_indices(&self, idx: usize) -> Vec<usize>
select.selectedOptions(<select multiple> で選択中の option 一覧を得る
定番イディオム。FormData の multi-select 対応と同じく selected 属性を
真実源とする)。単一選択の <select> でも仕様どおり動作する
(selected が無ければ既定選択の最初の option を1件返す)。
Sourcepub fn select_effective_value(&self, idx: usize) -> String
pub fn select_effective_value(&self, idx: usize) -> String
select.value(丸ごと未対応だった。<select> 自身に value 属性は無く、
選択状態は子の <option selected> が持つため、汎用の属性直結 getter では
常に空文字列になっていた)。selected な option を優先し、無ければ
HTML の既定選択どおり最初の option にフォールバックする。
Sourcepub fn effective_form_value(&self, idx: usize) -> String
pub fn effective_form_value(&self, idx: usize) -> String
フォーム系コントロールの「現在の実効値」を文字列で解決する。
checkValidity()/.validationMessage/.validityが素朴に
get_attr(idx,"value")だけを見ており、value属性を持たない
<select>(選択状態は子<option selected>が持つ)や、初期値が
value属性ではなくテキストノードで表現される<textarea>では
常に空文字列として(=未入力として)誤って検証されてしまうバグの
共通修正用。.valueゲッター(dom_props.rs)と同じフォールバック
規則をここに一本化する。
Sourcepub fn set_select_value(&mut self, idx: usize, val: &str)
pub fn set_select_value(&mut self, idx: usize, val: &str)
select.value = v(丸ごと未対応だった)。value が一致する最初の option へ
選択を移す(他の option の selected は解除。仕様どおり単一選択)。
Sourcepub fn select_selected_index(&self, idx: usize) -> i32
pub fn select_selected_index(&self, idx: usize) -> i32
select.selectedIndex(丸ごと未対応だった)。selected な option の位置、
無ければ option が1つ以上あれば 0(既定選択)、無ければ -1。
Sourcepub fn set_select_selected_index(&mut self, idx: usize, n: i32)
pub fn set_select_selected_index(&mut self, idx: usize, n: i32)
select.selectedIndex = n。
Sourcepub fn set_select_length(&mut self, idx: usize, n: usize)
pub fn set_select_length(&mut self, idx: usize, n: usize)
select.length = n(HTML5。select.options.lengthと同じ値を返す
ゲッター兼、nより末尾のoptionを切り捨てる/不足分を空の<option>で
埋めるセッター。丸ごと未対応だった)。仕様どおり、新しい長さが現在より
小さければ末尾から削除、大きければ空の<option>を追加する。
Sourcepub fn option_index(&self, idx: usize) -> i32
pub fn option_index(&self, idx: usize) -> i32
option.index(HTML5。自身が属する<select>内での0始まりの位置。
select.selectedIndexの対になる、<option>側のIDL属性だが丸ごと
未対応だった)。<select>祖先が無い場合は仕様どおり0(要素が
「optionのリスト」に属さない場合の既定値。<datalist>配下は
対象外の簡略実装)。
pub fn get_attr(&self, idx: usize, name: &str) -> Option<String>
pub fn set_attr(&mut self, idx: usize, name: &str, val: &str)
Sourcepub fn has_attr(&self, idx: usize, name: &str) -> bool
pub fn has_attr(&self, idx: usize, name: &str) -> bool
属性が存在するか(空値の boolean 属性も存在として true。id/class は専用フィールド)。
Sourcepub fn remove_attr(&mut self, idx: usize, name: &str)
pub fn remove_attr(&mut self, idx: usize, name: &str)
属性を削除(id/class フィールドも同期)。
Sourcepub fn close_details_group_siblings(&mut self, idx: usize) -> Vec<usize>
pub fn close_details_group_siblings(&mut self, idx: usize) -> Vec<usize>
<input type="radio"> の排他選択(同じ name を持つグループ内で1つだけが
checked になる、というラジオボタンの最も基本的な仕様上の挙動)。idx を
checked にする際、同じ name を持つ他の radio 全ての checked 属性を外す。
フォーム所有者(<form> 単位のスコープ)は区別せず、同じ name を持つ
document 内の全 radio を対象にする簡略実装。
<details name="...">(HTML5。同じnameを持つ<details>同士は
ラジオボタングループのように排他的に開閉する——1つを開くと同じ
グループの他の<details>は自動的に閉じる——仕様が丸ごと未対応
だった。uncheck_radio_group_siblingsと同じ「name属性が一致する
兄弟(ドキュメント全体、DOM上の兄弟関係は問わない)を探して状態を
揃える」パターンをそのまま適用する。2026-07-18 発見・実装)。
pub fn uncheck_radio_group_siblings(&mut self, idx: usize)
Sourcepub fn node_matches(&self, idx: usize, selector: &str) -> bool
pub fn node_matches(&self, idx: usize, selector: &str) -> bool
単一ノードがセレクタ(コンパウンド + 結合子、カンマ区切りは OR)にマッチするか。
matches()/closest()/querySelector(All) 共通の実装本体。以前は #id/.class/
tag/* の単純セレクタしか認識せず、div.active(コンパウンド)や [data-x]
(属性セレクタ)、.a > .b(結合子)を渡すと文字列全体を tag 名として比較する
分岐に落ち、常に false になる静かな破壊バグだった(:not()/:nth-child()/
:is()/:where() 等の疑似クラスは引き続き非対応。改修規模を絞るための
意図的な割り切り)。
Sourcepub fn node_matches_scoped(
&self,
idx: usize,
selector: &str,
scope_root: Option<usize>,
) -> bool
pub fn node_matches_scoped( &self, idx: usize, selector: &str, scope_root: Option<usize>, ) -> bool
node_matches の :scope 対応版。scope_root に element. querySelectorAll/matches/closest 等の起点ノードを渡すと、セレクタ中の
:scope 疑似クラス(Selectors Level 4。丸ごと未対応だった)がそのノードに
のみ一致するようになる。scope_root が None(document.querySelectorAll
等、起点を持たない文脈)の場合は :scope は常に不一致として扱う簡略実装。
Sourcefn compound_matches(
&self,
idx: usize,
c: &CompoundSel,
scope_root: Option<usize>,
) -> bool
fn compound_matches( &self, idx: usize, c: &CompoundSel, scope_root: Option<usize>, ) -> bool
idx がコンパウンドセレクタ(タグ/#id/.class/[attr...])に一致するか。
Sourcefn element_sibling_position(&self, idx: usize) -> (usize, usize)
fn element_sibling_position(&self, idx: usize) -> (usize, usize)
idx の「要素兄弟のみを数えた」1始まりの位置と、要素兄弟の総数を返す
(テキストノードは数えない。CSS の :nth-child() 等と同じ規則)。
Sourcefn element_type_sibling_position(&self, idx: usize) -> (usize, usize)
fn element_type_sibling_position(&self, idx: usize) -> (usize, usize)
element_sibling_position と同じだが、同じタグ名の兄弟のみを数える
(:first-of-type/:last-of-type/:nth-of-type() 用)。
Sourcefn match_selector_chain(
&self,
idx: usize,
steps: &[SelStep],
step_i: usize,
scope_root: Option<usize>,
) -> bool
fn match_selector_chain( &self, idx: usize, steps: &[SelStep], step_i: usize, scope_root: Option<usize>, ) -> bool
idx は steps[step_i] に既に一致した状態で呼ばれる。steps[0..step_i] を
結合子に従って祖先/兄弟方向へ再帰的に検証する。
Sourcefn prev_element_sibling(&self, idx: usize) -> Option<usize>
fn prev_element_sibling(&self, idx: usize) -> Option<usize>
idx の直前の要素兄弟(テキストノードは飛ばす)。
Sourcefn preceding_element_siblings(&self, idx: usize) -> Vec<usize>
fn preceding_element_siblings(&self, idx: usize) -> Vec<usize>
idx より前にある全ての要素兄弟(テキストノードは飛ばす、ドキュメント順)。
Sourcepub fn is_ancestor_of(&self, anc: usize, idx: usize) -> bool
pub fn is_ancestor_of(&self, anc: usize, idx: usize) -> bool
anc が idx の祖先か(idx 自身は含まない)。
Sourcepub fn document_position(&self, this_idx: usize, other_idx: usize) -> u32
pub fn document_position(&self, this_idx: usize, other_idx: usize) -> u32
Node.compareDocumentPosition(other)(DOM標準)が丸ごと未対応だった。
this_idx(reference node)から見た other_idx の位置関係をビットマスクで返す
(DOCUMENT_POSITION_* 定数は呼び出し側 builtins.rs で定義)。祖先/子孫関係は
既存の is_ancestor_of で判定し、それ以外(兄弟や別分岐)は両者の祖先鎖を根まで
辿って最も近い共通祖先(LCA)の子リスト内での順序を比較する。根が異なる
(disconnected)場合、仕様上 PRECEDING/FOLLOWING の割当ては実装依存でよいため
ノードindexの大小で決定的に決める。
Sourcepub fn offset_parent(&self, idx: usize) -> Option<usize>
pub fn offset_parent(&self, idx: usize) -> Option<usize>
idx 自身を含め祖先方向へ、指定タグの最初の要素を返す(<form> 解決等)。
element.offsetParent(HTML5。丸ごと未対応だった)。祖先を遡り、算出
position が static 以外の最初の要素を返す。無ければ <body>
(見つからなければ None = 仕様どおり null)。
pub fn closest_tag(&self, idx: usize, tag: &str) -> Option<usize>
Sourcepub fn associated_form(&self, idx: usize) -> Option<usize>
pub fn associated_form(&self, idx: usize) -> Option<usize>
フォーム系コントロールが実際に属する<form>を解決する。HTML5仕様では
form="formId"属性(<form>の子孫でなくても、そのidで明示的に関連付ける
「form owner」機構)が祖先探索より優先される。以前はclosest_tag(idx, "form")(祖先探索のみ)しか実装されておらず、<form id="f1">の外に置かれた
<input form="f1">(フォーム外配置は<form>の視覚レイアウトを変えずに
コントロールだけ離れた場所に置きたい場合の定番パターン)が
element.formでnullになり、<form>.checkValidity()/送信データ収集からも
漏れる、という兄弟ギャップだった。
Sourcepub fn form_associated_controls(
&self,
form_idx: usize,
tags: &[&str],
) -> Vec<usize>
pub fn form_associated_controls( &self, form_idx: usize, tags: &[&str], ) -> Vec<usize>
<form id="f1">に属するtagsに含まれるタグの全フォームコントロールを
収集する。子孫に加えて、form="f1"属性でフォーム外から明示的に関連付けられた
コントロール(associated_formと対になる「form owner」機構)も含む。
checkValidity()/FormData収集/form.elementsの各<form>祖先ループが
フォーム外配置のコントロールを見落としていた兄弟ギャップの修正に使う
(呼び出し側ごとに対象タグが異なる: checkValidity/FormDataは
input/select/textareaのみ、form.elementsはそれにbuttonも含む)。
Sourcepub fn first_by_tag(&self, tag: &str) -> Option<usize>
pub fn first_by_tag(&self, tag: &str) -> Option<usize>
ドキュメント順で最初の指定タグ要素。
Sourcepub fn element_children(&self, idx: usize) -> Vec<usize>
pub fn element_children(&self, idx: usize) -> Vec<usize>
子のうち要素(非テキスト)ノードの index 一覧。
Sourcepub fn descendants_by_tag_name(&self, root: usize, tag: &str) -> Vec<usize>
pub fn descendants_by_tag_name(&self, root: usize, tag: &str) -> Vec<usize>
root 以下(自身は含まない)の子孫のうち、tag が tags のいずれかに一致するものを
文書順で収集する。フォーム配下の入力欄列挙(バリデーション)に使用。
element.getElementsByTagName(tag) 用の子孫走査。tag が "*" なら全要素。
§なぜ文書全体の検索を使わないか
query_all は is_attached で文書に繋がっていないノードを除外する。
仕様では getElementsByTagName は文書への接続に関係なく自分の子孫を
返すので、切り離した要素(createElement した直後など)では結果が
空になってしまう。
jQuery 1.8.2 の機能検出はまさにこれをやる:
切り離した <div> に innerHTML を入れ、getElementsByTagName("a")[0]
の style を触る。空が返ると undefined の style を読んで落ち、
jQuery 全体が初期化できなくなっていた。
なお is_attached は根(索引 0)まで遡る実装のため、空の DOM では
最初に作った要素自身が索引 0 になり偶然「接続済み」になる。
単体試験を空のランタイムで書くとこの不具合を再現できない
(実際に 5 回取り逃がした)。試験は実ページの DOM で確かめること。
Sourcepub fn is_disabled(&self, idx: usize) -> bool
pub fn is_disabled(&self, idx: usize) -> bool
<fieldset disabled>の子孫コントロールは、自身にdisabled属性が無くても
暗黙に無効化される(HTML5仕様の「fieldset disabling」)。以前は要素自身の
disabled属性の有無しか見ておらず、<fieldset disabled>配下の<input>は
.disabledが常にfalse、制約バリデーションも無効化されずに常に対象内の
ままになっていた。祖先をparentで遡り<fieldset disabled>が1つでも
あれば無効とみなす(<fieldset>の最初の子<legend>直下のコントロールは
無効化対象外という仕様上の例外は、この処理系のフォーム系テストでは実用上
ほぼ現れないため今回は簡略化して見送る)。
Sourcepub fn validity_flags(&self, idx: usize, value: &str) -> ValidityFlags
pub fn validity_flags(&self, idx: usize, value: &str) -> ValidityFlags
ValidityState の各フラグを個別に計算する(validate_field は最初に見つかった
違反のメッセージ1件しか返さないため、.validity.patternMismatch のような特定
制約の狙い撃ちには使えなかった)。validate_field と同じ規則を、短絡させずに
全項目評価する。
Sourcefn required_satisfied(
&self,
n: &DomNode,
input_type: &str,
trimmed_value: &str,
) -> bool
fn required_satisfied( &self, n: &DomNode, input_type: &str, trimmed_value: &str, ) -> bool
required制約が充足されているかを判定する。checkboxは自身のchecked、
radioは同じnameグループ内のいずれかがcheckedであれば充足(HTML5
仕様どおり)。それ以外のinput/select/textareaはvalue(trim後)が
空でなければ充足。validate_field/validity_flagsの両方から共通で使う。
Sourcepub fn validate_field(&self, idx: usize, value: &str) -> Option<String>
pub fn validate_field(&self, idx: usize, value: &str) -> Option<String>
HTML5 制約バリデーション。フィールド要素 idx と現在値 value を検査し、
違反があればユーザー向けメッセージを返す(None = 妥当)。
対応: setCustomValidity(_custom_validity) / required / minlength / maxlength /
pattern / type=email / type=url / type=number,range(min,max,step)。
disabled/readonly や type=submit/button/hidden は検証対象外。
Sourcefn is_valid_email(s: &str) -> bool
fn is_valid_email(s: &str) -> bool
簡易メールアドレス検証(完全な RFC ではなく実用的な近似)。
Sourcefn is_valid_email_value(n: &DomNode, value: &str) -> bool
fn is_valid_email_value(n: &DomNode, value: &str) -> bool
<input type="email" multiple>(HTML5。multiple属性がある email input は
カンマ区切りで複数アドレスを入力できる仕様だが、以前はis_valid_email(value)
を値全体にそのまま適用しており、2件目以降のアドレスやカンマ自体を含む文字列は
単一アドレスとして常に不正と誤判定されていた(逆にmultipleが無いのに
カンマ区切りを入力した場合はこのメソッドを経由しないため今までどおり単一
アドレスとして正しく不正判定される)。空要素("a@b.com,"のような末尾カンマ)
は仕様上不正。
Sourcefn pattern_matches(pat: &str, val: &str) -> bool
fn pattern_matches(pat: &str, val: &str) -> bool
<input pattern="...">(HTML Living Standard の制約検証。仕様上は値全体を
^(?:pattern)$ として完全一致させる)が、以前はメタ文字を含む複雑なパターンを
「誤検知で送信を妨げないため」全て無条件で通過させる簡易近似だった。この
エンジンには既に本物の正規表現実装(js::regex::Regex)があるため、それを
そのまま使えば近似ではなく正しく検証できる(\d/[...]/+/.* 等、
HTML pattern で使われる構文は通常の JS RegExp と同じ)。
Sourcepub fn attr_names(&self, idx: usize) -> Vec<String>
pub fn attr_names(&self, idx: usize) -> Vec<String>
属性名の一覧(id/class を先頭に、続いてその他属性)。
pub fn add_listener(&mut self, node: usize, event: &str, func: Value)
Sourcepub fn add_listener_opts(
&mut self,
node: usize,
event: &str,
func: Value,
capture: bool,
once: bool,
) -> u64
pub fn add_listener_opts( &mut self, node: usize, event: &str, func: Value, capture: bool, once: bool, ) -> u64
capture / once オプション付きでリスナを登録する。重複(同一 node+event+func+capture) は DOM 仕様どおり無視する。戻り値は発番した ID。
Sourcepub fn add_listener_opts_signal(
&mut self,
node: usize,
event: &str,
func: Value,
capture: bool,
once: bool,
signal: Option<Value>,
) -> u64
pub fn add_listener_opts_signal( &mut self, node: usize, event: &str, func: Value, capture: bool, once: bool, signal: Option<Value>, ) -> u64
add_listener_opts の {signal} 対応版。signal が既に abort 済みなら
仕様どおり登録自体を行わない。
Sourcepub fn remove_listener(
&mut self,
node: usize,
event: &str,
func: &Value,
capture: bool,
)
pub fn remove_listener( &mut self, node: usize, event: &str, func: &Value, capture: bool, )
removeEventListener: 同一 (node, event, func, capture) のリスナを削除する。
Sourcepub fn remove_listener_by_id(&mut self, id: u64)
pub fn remove_listener_by_id(&mut self, id: u64)
ID 指定でリスナを削除する(once 発火後の自動削除に使う)。
Sourcepub fn has_listener(&self, event: &str) -> bool
pub fn has_listener(&self, event: &str) -> bool
指定イベント型のリスナがページ内に1つでも登録されているか(ホバー判定の省略用)。
Sourcepub fn listeners_for(&self, node: usize, event: &str) -> Vec<Value>
pub fn listeners_for(&self, node: usize, event: &str) -> Vec<Value>
指定ノードに登録された指定イベントのリスナ関数を返す(呼び出しは呼び元で)。
バブリングフェーズ用(capture=false のみ)。{signal} が abort 済みの
リスナは除外する。
Sourcepub fn listeners_phase(
&self,
node: usize,
event: &str,
want_capture: bool,
) -> Vec<(Value, bool, u64)>
pub fn listeners_phase( &self, node: usize, event: &str, want_capture: bool, ) -> Vec<(Value, bool, u64)>
指定ノード・イベントのリスナを (func, capture, once, id) 付きで返す。
want_capture でキャプチャ/バブルのどちらのフェーズかを絞り込む。
{signal} が abort 済みのリスナは除外する。
Sourcepub fn has_listener_on(&self, node: usize, event: &str) -> bool
pub fn has_listener_on(&self, node: usize, event: &str) -> bool
指定ノードに当該イベントのリスナ(フェーズ問わず)が在るか。
Sourcepub fn apply_overrides(&self, root: &mut Node)
pub fn apply_overrides(&self, root: &mut Node)
再パースした DOM 木へ JS の変更を焼き戻す。木はビルド時と同一ドキュメント順前提。