mirror of
https://github.com/servo/servo.git
synced 2025-06-24 00:54:32 +01:00
Make sure getElementById always returns the first element with the given ID in tree order.(fixes #1822)
This commit is contained in:
parent
86c83f7bfc
commit
50aea70f98
3 changed files with 77 additions and 8 deletions
|
@ -7,6 +7,7 @@ use dom::bindings::codegen::InheritTypes::{DocumentBase, NodeCast, DocumentCast}
|
||||||
use dom::bindings::codegen::InheritTypes::{HTMLHeadElementCast, TextCast, ElementCast};
|
use dom::bindings::codegen::InheritTypes::{HTMLHeadElementCast, TextCast, ElementCast};
|
||||||
use dom::bindings::codegen::InheritTypes::{DocumentTypeCast, HTMLHtmlElementCast};
|
use dom::bindings::codegen::InheritTypes::{DocumentTypeCast, HTMLHtmlElementCast};
|
||||||
use dom::bindings::codegen::DocumentBinding;
|
use dom::bindings::codegen::DocumentBinding;
|
||||||
|
use dom::bindings::codegen::NodeBinding::NodeConstants::{DOCUMENT_POSITION_CONTAINS, DOCUMENT_POSITION_PRECEDING};
|
||||||
use dom::bindings::js::JS;
|
use dom::bindings::js::JS;
|
||||||
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
|
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
|
||||||
use dom::bindings::error::{ErrorResult, Fallible, NotSupported, InvalidCharacter, HierarchyRequest};
|
use dom::bindings::error::{ErrorResult, Fallible, NotSupported, InvalidCharacter, HierarchyRequest};
|
||||||
|
@ -58,7 +59,7 @@ pub struct Document {
|
||||||
node: Node,
|
node: Node,
|
||||||
reflector_: Reflector,
|
reflector_: Reflector,
|
||||||
window: JS<Window>,
|
window: JS<Window>,
|
||||||
idmap: HashMap<DOMString, JS<Element>>,
|
idmap: HashMap<DOMString, ~[JS<Element>]>,
|
||||||
implementation: Option<JS<DOMImplementation>>,
|
implementation: Option<JS<DOMImplementation>>,
|
||||||
content_type: DOMString,
|
content_type: DOMString,
|
||||||
encoding_name: DOMString,
|
encoding_name: DOMString,
|
||||||
|
@ -248,7 +249,7 @@ impl Document {
|
||||||
// http://dom.spec.whatwg.org/#dom-document-getelementbyid.
|
// http://dom.spec.whatwg.org/#dom-document-getelementbyid.
|
||||||
match self.idmap.find_equiv(&id) {
|
match self.idmap.find_equiv(&id) {
|
||||||
None => None,
|
None => None,
|
||||||
Some(node) => Some(node.clone()),
|
Some(ref elements) => Some(elements[0].clone()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -600,8 +601,22 @@ impl Document {
|
||||||
|
|
||||||
/// Remove any existing association between the provided id and any elements in this document.
|
/// Remove any existing association between the provided id and any elements in this document.
|
||||||
pub fn unregister_named_element(&mut self,
|
pub fn unregister_named_element(&mut self,
|
||||||
|
abstract_self: &JS<Element>,
|
||||||
id: DOMString) {
|
id: DOMString) {
|
||||||
self.idmap.remove(&id);
|
let mut is_empty = false;
|
||||||
|
match self.idmap.find_mut(&id) {
|
||||||
|
None => {},
|
||||||
|
Some(elements) => {
|
||||||
|
let position = elements.iter()
|
||||||
|
.position(|element| element == abstract_self)
|
||||||
|
.expect("This element should be in registered.");
|
||||||
|
elements.remove(position);
|
||||||
|
is_empty = elements.is_empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if is_empty {
|
||||||
|
self.idmap.remove(&id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Associate an element present in this document with the provided id.
|
/// Associate an element present in this document with the provided id.
|
||||||
|
@ -618,12 +633,26 @@ impl Document {
|
||||||
// FIXME https://github.com/mozilla/rust/issues/13195
|
// FIXME https://github.com/mozilla/rust/issues/13195
|
||||||
// Use mangle() when it exists again.
|
// Use mangle() when it exists again.
|
||||||
match self.idmap.find_mut(&id) {
|
match self.idmap.find_mut(&id) {
|
||||||
Some(v) => {
|
Some(elements) => {
|
||||||
*v = element.clone();
|
let new_node = NodeCast::from(element);
|
||||||
|
let mut head : uint = 0u;
|
||||||
|
let mut tail : uint = elements.len();
|
||||||
|
while head < tail {
|
||||||
|
let middle = ((head + tail) / 2) as int;
|
||||||
|
let elem = &elements[middle];
|
||||||
|
let js_node = NodeCast::from(elem);
|
||||||
|
let position = elem.get().node.CompareDocumentPosition(&js_node, &new_node);
|
||||||
|
if position == DOCUMENT_POSITION_PRECEDING || position == DOCUMENT_POSITION_PRECEDING + DOCUMENT_POSITION_CONTAINS {
|
||||||
|
tail = middle as uint;
|
||||||
|
} else {
|
||||||
|
head = middle as uint + 1u;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elements.insert(tail, element.clone());
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
None => (),
|
None => (),
|
||||||
}
|
}
|
||||||
self.idmap.insert(id, element.clone());
|
self.idmap.insert(id, ~[element.clone()]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -352,7 +352,7 @@ impl AttributeHandlers for JS<Element> {
|
||||||
// "borrowed value does not live long enough"
|
// "borrowed value does not live long enough"
|
||||||
let mut doc = node.get().owner_doc().clone();
|
let mut doc = node.get().owner_doc().clone();
|
||||||
let doc = doc.get_mut();
|
let doc = doc.get_mut();
|
||||||
doc.unregister_named_element(old_value);
|
doc.unregister_named_element(self, old_value);
|
||||||
}
|
}
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
|
@ -640,7 +640,7 @@ impl IElement for JS<Element> {
|
||||||
match self.get_attribute(Null, "id") {
|
match self.get_attribute(Null, "id") {
|
||||||
Some(attr) => {
|
Some(attr) => {
|
||||||
let mut doc = document_from_node(self);
|
let mut doc = document_from_node(self);
|
||||||
doc.get_mut().unregister_named_element(attr.get().Value());
|
doc.get_mut().unregister_named_element(self, attr.get().Value());
|
||||||
}
|
}
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<script src="harness.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="a">
|
||||||
|
</div>
|
||||||
|
<div id="b">
|
||||||
|
<p id="b">P</p>
|
||||||
|
<input id="b" type="submit" value="Submit">
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
{
|
||||||
|
var b = document.getElementById("b");
|
||||||
|
is_a(b, HTMLDivElement);
|
||||||
|
var a = document.getElementById("a");
|
||||||
|
var p = document.createElement("p");
|
||||||
|
p.id = "b";
|
||||||
|
a.appendChild(p);
|
||||||
|
var newB = document.getElementById("b");
|
||||||
|
is_a(newB, HTMLParagraphElement);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
var gbody = document.getElementsByTagName("body")[0];
|
||||||
|
var div = document.createElement("div");
|
||||||
|
div.setAttribute("id", "c");
|
||||||
|
var h1 = document.createElement("h1");
|
||||||
|
h1.setAttribute("id", "c");
|
||||||
|
gbody.appendChild(div);
|
||||||
|
gbody.appendChild(h1);
|
||||||
|
var c = document.getElementById("c");
|
||||||
|
is_a(c, HTMLDivElement);
|
||||||
|
gbody.removeChild(div);
|
||||||
|
var newC = document.getElementById("c");
|
||||||
|
is_a(newC, HTMLHeadingElement);
|
||||||
|
}
|
||||||
|
finish();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Add table
Add a link
Reference in a new issue