/
githubmirror
/
servo
Обзор
Документация
Войти
/
githubmirror
/
servo
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
components/script/dom/domtokenlist.rs
243 строки
8 KB
Tim van der Lippe
script: Replace `get_attribute` with `with_attribute` (#45081)
23 май 2026, 13:56
Не верифицирован
23 май 2026, 13:56
e966597
Код
Авторство
О чём код?
/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use dom_struct::dom_struct; use html5ever::LocalName; use js::context::JSContext; use script_bindings::reflector::{Reflector, reflect_dom_object_with_cx}; use style::str::HTML_SPACE_CHARACTERS; use stylo_atoms::Atom; use crate::dom::bindings::codegen::Bindings::DOMTokenListBinding::DOMTokenListMethods; use crate::dom::bindings::error::{Error, ErrorResult, Fallible}; use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::bindings::str::DOMString; use crate::dom::element::Element; use crate::dom::node::NodeTraits; #[dom_struct] pub(crate) struct DOMTokenList { reflector_: Reflector, element: Dom<Element>, #[no_trace] local_name: LocalName, #[no_trace] supported_tokens: Option<Vec<Atom>>, } impl DOMTokenList { pub(crate) fn new_inherited( element: &Element, local_name: LocalName, supported_tokens: Option<Vec<Atom>>, ) -> DOMTokenList { DOMTokenList { reflector_: Reflector::new(), element: Dom::from_ref(element), local_name, supported_tokens, } } pub(crate) fn new( cx: &mut JSContext, element: &Element, local_name: &LocalName, supported_tokens: Option<Vec<Atom>>, ) -> DomRoot<DOMTokenList> { reflect_dom_object_with_cx( Box::new(DOMTokenList::new_inherited( element, local_name.clone(), supported_tokens, )), &*element.owner_window(), cx, ) } fn check_token_exceptions(&self, token: &DOMString) -> Fallible<Atom> { let token = token.str(); match &*token { "" => Err(Error::Syntax(None)), slice if slice.find(HTML_SPACE_CHARACTERS).is_some() => { Err(Error::InvalidCharacter(None)) }, slice => Ok(Atom::from(slice)), } } /// <https://dom.spec.whatwg.org/#concept-dtl-update> fn perform_update_steps(&self, cx: &mut JSContext, atoms: Vec<Atom>) { // Step 1 if !self.element.has_attribute(&self.local_name) && atoms.is_empty() { return; } // step 2 self.element .set_attribute(cx, &self.local_name, atoms.into()) } /// <https://dom.spec.whatwg.org/#concept-domtokenlist-validation> fn validation_steps(&self, token: &str) -> Fallible<bool> { match &self.supported_tokens { None => Err(Error::Type( c"This attribute has no supported tokens".to_owned(), )), Some(supported_tokens) => { let token = Atom::from(token).to_ascii_lowercase(); if supported_tokens.contains(&token) { return Ok(true); } Ok(false) }, } } } /// <https://dom.spec.whatwg.org/#domtokenlist> impl DOMTokenListMethods<crate::DomTypeHolder> for DOMTokenList { /// <https://dom.spec.whatwg.org/#dom-domtokenlist-length> fn Length(&self) -> u32 { self.element.get_tokenlist_attribute(&self.local_name).len() as u32 } /// <https://dom.spec.whatwg.org/#dom-domtokenlist-item> fn Item(&self, index: u32) -> Option<DOMString> { self.element .get_tokenlist_attribute(&self.local_name) .get(index as usize) .map(|token| DOMString::from(&**token)) } /// <https://dom.spec.whatwg.org/#dom-domtokenlist-contains> fn Contains(&self, token: DOMString) -> bool { self.element .get_tokenlist_attribute(&self.local_name) .contains(&Atom::from(token)) } /// <https://dom.spec.whatwg.org/#dom-domtokenlist-add> fn Add(&self, cx: &mut JSContext, tokens: Vec<DOMString>) -> ErrorResult { let mut atoms = self.element.get_tokenlist_attribute(&self.local_name); for token in &tokens { let token = self.check_token_exceptions(token)?; if !atoms.contains(&token) { atoms.push(token); } } self.perform_update_steps(cx, atoms); Ok(()) } /// <https://dom.spec.whatwg.org/#dom-domtokenlist-remove> fn Remove(&self, cx: &mut JSContext, tokens: Vec<DOMString>) -> ErrorResult { let mut atoms = self.element.get_tokenlist_attribute(&self.local_name); for token in &tokens { let token = self.check_token_exceptions(token)?; atoms .iter() .position(|atom| *atom == token) .map(|index| atoms.remove(index)); } self.perform_update_steps(cx, atoms); Ok(()) } /// <https://dom.spec.whatwg.org/#dom-domtokenlist-toggle> fn Toggle(&self, cx: &mut JSContext, token: DOMString, force: Option<bool>) -> Fallible<bool> { let mut atoms = self.element.get_tokenlist_attribute(&self.local_name); let token = self.check_token_exceptions(&token)?; match atoms.iter().position(|atom| *atom == token) { Some(index) => match force { Some(true) => Ok(true), _ => { atoms.remove(index); self.perform_update_steps(cx, atoms); Ok(false) }, }, None => match force { Some(false) => Ok(false), _ => { atoms.push(token); self.perform_update_steps(cx, atoms); Ok(true) }, }, } } /// <https://dom.spec.whatwg.org/#dom-domtokenlist-value> fn Value(&self) -> DOMString { self.element.get_string_attribute(&self.local_name) } /// <https://dom.spec.whatwg.org/#dom-domtokenlist-value> fn SetValue(&self, cx: &mut JSContext, value: DOMString) { self.element .set_tokenlist_attribute(cx, &self.local_name, value); } /// <https://dom.spec.whatwg.org/#dom-domtokenlist-replace> fn Replace( &self, cx: &mut JSContext, token: DOMString, new_token: DOMString, ) -> Fallible<bool> { if token.is_empty() || new_token.is_empty() { // Step 1. return Err(Error::Syntax(None)); } if token.contains_html_space_characters() || new_token.contains_html_space_characters() { // Step 2. return Err(Error::InvalidCharacter(None)); } // Steps 3-4. let token = Atom::from(token); let new_token = Atom::from(new_token); let mut atoms = self.element.get_tokenlist_attribute(&self.local_name); let mut result = false; if let Some(pos) = atoms.iter().position(|atom| *atom == token) { match atoms.iter().position(|atom| *atom == new_token) { Some(redundant_pos) if redundant_pos > pos => { // The replacement is already in the list, later, // so we perform the replacement and remove the // later copy. atoms[pos] = new_token; atoms.remove(redundant_pos); }, Some(redundant_pos) if redundant_pos < pos => { // The replacement is already in the list, earlier, // so we remove the index where we'd be putting the // later copy. atoms.remove(pos); }, Some(_) => { // Else we are replacing the token with itself, nothing to change }, None => { // The replacement is not in the list already atoms[pos] = new_token; }, } // Step 5. self.perform_update_steps(cx, atoms); result = true; } Ok(result) } /// <https://dom.spec.whatwg.org/#dom-domtokenlist-supports> fn Supports(&self, token: DOMString) -> Fallible<bool> { self.validation_steps(&token.str()) } // check-tidy: no specs after this line fn IndexedGetter(&self, index: u32) -> Option<DOMString> { self.Item(index) } }