mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +01:00
auto merge of #1171 : jdm/servo/events2, r=jdm,metajack
Now with a split between commits that just pull in unmodified Gecko code and those that modify it.
This commit is contained in:
commit
c2a99933c9
27 changed files with 2593 additions and 171 deletions
105
src/components/script/dom/bindings/callback.rs
Normal file
105
src/components/script/dom/bindings/callback.rs
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
/* 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 http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use dom::bindings::utils::{WrapNativeParent, Reflectable};
|
||||||
|
use js::jsapi::{JSContext, JSObject, JS_WrapObject, JSVal, JS_ObjectIsCallable};
|
||||||
|
use js::jsapi::JS_GetProperty;
|
||||||
|
use js::{JSVAL_IS_OBJECT, JSVAL_TO_OBJECT};
|
||||||
|
|
||||||
|
use std::libc;
|
||||||
|
use std::ptr;
|
||||||
|
|
||||||
|
pub enum ExceptionHandling {
|
||||||
|
// Report any exception and don't throw it to the caller code.
|
||||||
|
eReportExceptions,
|
||||||
|
// Throw an exception to the caller code if the thrown exception is a
|
||||||
|
// binding object for a DOMError from the caller's scope, otherwise report
|
||||||
|
// it.
|
||||||
|
eRethrowContentExceptions,
|
||||||
|
// Throw any exception to the caller code.
|
||||||
|
eRethrowExceptions
|
||||||
|
}
|
||||||
|
|
||||||
|
#[deriving(Clone,Eq)]
|
||||||
|
pub struct CallbackInterface {
|
||||||
|
callback: *JSObject
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait CallbackContainer {
|
||||||
|
fn callback(&self) -> *JSObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CallbackContainer for CallbackInterface {
|
||||||
|
fn callback(&self) -> *JSObject {
|
||||||
|
self.callback
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CallbackInterface {
|
||||||
|
pub fn new(callback: *JSObject) -> CallbackInterface {
|
||||||
|
CallbackInterface {
|
||||||
|
callback: callback
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[fixed_stack_segment]
|
||||||
|
pub fn GetCallableProperty(&self, cx: *JSContext, name: *libc::c_char, callable: &mut JSVal) -> bool {
|
||||||
|
unsafe {
|
||||||
|
if JS_GetProperty(cx, self.callback, name, &*callable) == 0 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !JSVAL_IS_OBJECT(*callable) ||
|
||||||
|
JS_ObjectIsCallable(cx, JSVAL_TO_OBJECT(*callable)) == 0 {
|
||||||
|
//ThrowErrorMessage(cx, MSG_NOT_CALLABLE, description.get());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn GetJSObjectFromCallback<T: CallbackContainer>(callback: &T) -> *JSObject {
|
||||||
|
callback.callback()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[fixed_stack_segment]
|
||||||
|
pub fn WrapCallThisObject<T: 'static + CallbackContainer + Reflectable>(cx: *JSContext,
|
||||||
|
scope: *JSObject,
|
||||||
|
p: @mut T) -> *JSObject {
|
||||||
|
let mut obj = GetJSObjectFromCallback(p);
|
||||||
|
if obj.is_null() {
|
||||||
|
obj = WrapNativeParent(cx, scope, Some(p as @mut Reflectable));
|
||||||
|
if obj.is_null() {
|
||||||
|
return ptr::null();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
if JS_WrapObject(cx, &obj) == 0 {
|
||||||
|
return ptr::null();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CallSetup {
|
||||||
|
cx: *JSContext,
|
||||||
|
handling: ExceptionHandling
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CallSetup {
|
||||||
|
pub fn new(cx: *JSContext, handling: ExceptionHandling) -> CallSetup {
|
||||||
|
CallSetup {
|
||||||
|
cx: cx,
|
||||||
|
handling: handling
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn GetContext(&self) -> *JSContext {
|
||||||
|
self.cx
|
||||||
|
}
|
||||||
|
}
|
|
@ -182,28 +182,21 @@ DOMInterfaces = {
|
||||||
},
|
},
|
||||||
|
|
||||||
'Event': {
|
'Event': {
|
||||||
|
'nativeType': 'AbstractEvent',
|
||||||
|
'concreteType': 'Event',
|
||||||
|
'pointerType': '',
|
||||||
},
|
},
|
||||||
|
|
||||||
'EventListener': [
|
'EventListener': {
|
||||||
{
|
'nativeType': 'EventListenerBinding::EventListener',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
'workers': True,
|
|
||||||
}],
|
|
||||||
|
|
||||||
'EventTarget': [
|
'EventTarget': {
|
||||||
{
|
'nativeType': 'AbstractEventTarget',
|
||||||
# 'nativeType': 'nsDOMEventTargetHelper',
|
'concreteType': 'EventTarget',
|
||||||
# 'hasInstanceInterface': 'nsIDOMEventTarget',
|
'pointerType': '',
|
||||||
# 'concrete': False,
|
'needsAbstract': ['dispatchEvent']
|
||||||
# 'prefable': True,
|
|
||||||
},
|
},
|
||||||
#{
|
|
||||||
# 'workers': True,
|
|
||||||
# 'headerFile': 'mozilla/dom/workers/bindings/EventTarget.h',
|
|
||||||
# 'concrete': False
|
|
||||||
#}
|
|
||||||
],
|
|
||||||
|
|
||||||
'FileList': [
|
'FileList': [
|
||||||
{
|
{
|
||||||
|
@ -291,6 +284,9 @@ DOMInterfaces = {
|
||||||
}],
|
}],
|
||||||
|
|
||||||
'MouseEvent': {
|
'MouseEvent': {
|
||||||
|
'nativeType': 'AbstractEvent',
|
||||||
|
'concreteType': 'MouseEvent',
|
||||||
|
'pointerType': '',
|
||||||
},
|
},
|
||||||
|
|
||||||
'Navigator': {
|
'Navigator': {
|
||||||
|
@ -388,6 +384,9 @@ DOMInterfaces = {
|
||||||
}],
|
}],
|
||||||
|
|
||||||
'UIEvent': {
|
'UIEvent': {
|
||||||
|
'nativeType': 'AbstractEvent',
|
||||||
|
'concreteType': 'UIEvent',
|
||||||
|
'pointerType': '',
|
||||||
},
|
},
|
||||||
|
|
||||||
'ValidityState': {
|
'ValidityState': {
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -42,6 +42,8 @@ class Configuration:
|
||||||
|
|
||||||
self.enums = [e for e in parseData if e.isEnum()]
|
self.enums = [e for e in parseData if e.isEnum()]
|
||||||
self.dictionaries = [d for d in parseData if d.isDictionary()]
|
self.dictionaries = [d for d in parseData if d.isDictionary()]
|
||||||
|
self.callbacks = [c for c in parseData if
|
||||||
|
c.isCallback() and not c.isInterface()]
|
||||||
|
|
||||||
# Keep the descriptor list sorted for determinism.
|
# Keep the descriptor list sorted for determinism.
|
||||||
self.descriptors.sort(lambda x,y: cmp(x.name, y.name))
|
self.descriptors.sort(lambda x,y: cmp(x.name, y.name))
|
||||||
|
@ -66,14 +68,34 @@ class Configuration:
|
||||||
getter = lambda x: x.interface.isCallback()
|
getter = lambda x: x.interface.isCallback()
|
||||||
elif key == 'isExternal':
|
elif key == 'isExternal':
|
||||||
getter = lambda x: x.interface.isExternal()
|
getter = lambda x: x.interface.isExternal()
|
||||||
|
elif key == 'isJSImplemented':
|
||||||
|
getter = lambda x: x.interface.isJSImplemented()
|
||||||
else:
|
else:
|
||||||
getter = lambda x: getattr(x, key)
|
getter = lambda x: getattr(x, key)
|
||||||
curr = filter(lambda x: getter(x) == val, curr)
|
curr = filter(lambda x: getter(x) == val, curr)
|
||||||
return curr
|
return curr
|
||||||
def getEnums(self, webIDLFile):
|
def getEnums(self, webIDLFile):
|
||||||
return filter(lambda e: e.filename() == webIDLFile, self.enums)
|
return filter(lambda e: e.filename() == webIDLFile, self.enums)
|
||||||
def getDictionaries(self, webIDLFile):
|
|
||||||
return filter(lambda d: d.filename() == webIDLFile, self.dictionaries)
|
@staticmethod
|
||||||
|
def _filterForFileAndWorkers(items, filters):
|
||||||
|
"""Gets the items that match the given filters."""
|
||||||
|
for key, val in filters.iteritems():
|
||||||
|
if key == 'webIDLFile':
|
||||||
|
items = filter(lambda x: x.filename() == val, items)
|
||||||
|
elif key == 'workers':
|
||||||
|
if val:
|
||||||
|
items = filter(lambda x: x.getUserData("workers", False), items)
|
||||||
|
else:
|
||||||
|
items = filter(lambda x: x.getUserData("mainThread", False), items)
|
||||||
|
else:
|
||||||
|
assert(0) # Unknown key
|
||||||
|
return items
|
||||||
|
def getDictionaries(self, **filters):
|
||||||
|
return self._filterForFileAndWorkers(self.dictionaries, filters)
|
||||||
|
def getCallbacks(self, **filters):
|
||||||
|
return self._filterForFileAndWorkers(self.callbacks, filters)
|
||||||
|
|
||||||
def getDescriptor(self, interfaceName, workers):
|
def getDescriptor(self, interfaceName, workers):
|
||||||
"""
|
"""
|
||||||
Gets the appropriate descriptor for the given interface name
|
Gets the appropriate descriptor for the given interface name
|
||||||
|
|
|
@ -58,8 +58,8 @@ interface Document : Node {
|
||||||
[Throws]
|
[Throws]
|
||||||
Node adoptNode(Node node);*/
|
Node adoptNode(Node node);*/
|
||||||
|
|
||||||
// [Creator, Throws]
|
[Creator, Throws]
|
||||||
// Event createEvent(DOMString interface_);
|
Event createEvent(DOMString interface_);
|
||||||
|
|
||||||
/*[Creator, Throws]
|
/*[Creator, Throws]
|
||||||
Range createRange();*/
|
Range createRange();*/
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* 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 http://mozilla.org/MPL/2.0/.
|
||||||
|
*
|
||||||
|
* The origin of this IDL file is
|
||||||
|
* http://www.w3.org/TR/2012/WD-dom-20120105/
|
||||||
|
*
|
||||||
|
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
|
||||||
|
* liability, trademark and document use rules apply.
|
||||||
|
*/
|
||||||
|
|
||||||
|
callback interface EventListener {
|
||||||
|
void handleEvent(Event event);
|
||||||
|
};
|
||||||
|
|
|
@ -11,4 +11,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
interface EventTarget {
|
interface EventTarget {
|
||||||
|
void addEventListener(DOMString type,
|
||||||
|
EventListener? listener,
|
||||||
|
optional boolean capture = false);
|
||||||
|
void removeEventListener(DOMString type,
|
||||||
|
EventListener? listener,
|
||||||
|
optional boolean capture = false);
|
||||||
|
[Throws]
|
||||||
|
boolean dispatchEvent(Event event);
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
interface URI;
|
interface URI;
|
||||||
interface UserDataHandler;*/
|
interface UserDataHandler;*/
|
||||||
|
|
||||||
interface Node /*: EventTarget*/ {
|
interface Node : EventTarget {
|
||||||
const unsigned short ELEMENT_NODE = 1;
|
const unsigned short ELEMENT_NODE = 1;
|
||||||
const unsigned short ATTRIBUTE_NODE = 2; // historical
|
const unsigned short ATTRIBUTE_NODE = 2; // historical
|
||||||
const unsigned short TEXT_NODE = 3;
|
const unsigned short TEXT_NODE = 3;
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
[NamedPropertiesObject]
|
[NamedPropertiesObject]
|
||||||
/*sealed*/ interface Window /*: EventTarget*/ {
|
/*sealed*/ interface Window : EventTarget {
|
||||||
// the current browsing context
|
// the current browsing context
|
||||||
/*[Unforgeable] readonly attribute WindowProxy window;
|
/*[Unforgeable] readonly attribute WindowProxy window;
|
||||||
[Replaceable] readonly attribute WindowProxy self;*/
|
[Replaceable] readonly attribute WindowProxy self;*/
|
||||||
|
|
|
@ -146,6 +146,23 @@ class IDLObject(object):
|
||||||
def isCallback(self):
|
def isCallback(self):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def isSingleOperationInterface(self):
|
||||||
|
assert self.isCallback() or self.isJSImplemented()
|
||||||
|
return (
|
||||||
|
# JS-implemented things should never need the
|
||||||
|
# this-handling weirdness of single-operation interfaces.
|
||||||
|
not self.isJSImplemented() and
|
||||||
|
# Not inheriting from another interface
|
||||||
|
not self.parent and
|
||||||
|
# No consequential interfaces
|
||||||
|
len(self.getConsequentialInterfaces()) == 0 and
|
||||||
|
# No attributes of any kinds
|
||||||
|
not any(m.isAttr() for m in self.members) and
|
||||||
|
# There is at least one regular operation, and all regular
|
||||||
|
# operations have the same identifier
|
||||||
|
len(set(m.identifier.name for m in self.members if
|
||||||
|
m.isMethod() and not m.isStatic())) == 1)
|
||||||
|
|
||||||
def isType(self):
|
def isType(self):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -167,6 +184,38 @@ class IDLObject(object):
|
||||||
def handleExtendedAttribute(self, attr):
|
def handleExtendedAttribute(self, attr):
|
||||||
assert False # Override me!
|
assert False # Override me!
|
||||||
|
|
||||||
|
def _getDependentObjects(self):
|
||||||
|
assert False # Override me!
|
||||||
|
|
||||||
|
def getDeps(self, visited=None):
|
||||||
|
""" Return a set of files that this object depends on. If any of
|
||||||
|
these files are changed the parser needs to be rerun to regenerate
|
||||||
|
a new IDLObject.
|
||||||
|
|
||||||
|
The visited argument is a set of all the objects already visited.
|
||||||
|
We must test to see if we are in it, and if so, do nothing. This
|
||||||
|
prevents infinite recursion."""
|
||||||
|
|
||||||
|
# NB: We can't use visited=set() above because the default value is
|
||||||
|
# evaluated when the def statement is evaluated, not when the function
|
||||||
|
# is executed, so there would be one set for all invocations.
|
||||||
|
if visited == None:
|
||||||
|
visited = set()
|
||||||
|
|
||||||
|
if self in visited:
|
||||||
|
return set()
|
||||||
|
|
||||||
|
visited.add(self)
|
||||||
|
|
||||||
|
deps = set()
|
||||||
|
if self.filename() != "<builtin>":
|
||||||
|
deps.add(self.filename())
|
||||||
|
|
||||||
|
for d in self._getDependentObjects():
|
||||||
|
deps = deps.union(d.getDeps(visited))
|
||||||
|
|
||||||
|
return deps
|
||||||
|
|
||||||
class IDLScope(IDLObject):
|
class IDLScope(IDLObject):
|
||||||
def __init__(self, location, parentScope, identifier):
|
def __init__(self, location, parentScope, identifier):
|
||||||
IDLObject.__init__(self, location)
|
IDLObject.__init__(self, location)
|
||||||
|
@ -428,6 +477,15 @@ class IDLExternalInterface(IDLObjectWithIdentifier):
|
||||||
def resolve(self, parentScope):
|
def resolve(self, parentScope):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def getJSImplementation(self):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def isJSImplemented(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _getDependentObjects(self):
|
||||||
|
return set()
|
||||||
|
|
||||||
class IDLInterface(IDLObjectWithScope):
|
class IDLInterface(IDLObjectWithScope):
|
||||||
def __init__(self, location, parentScope, name, parent, members,
|
def __init__(self, location, parentScope, name, parent, members,
|
||||||
isPartial):
|
isPartial):
|
||||||
|
@ -777,6 +835,24 @@ class IDLInterface(IDLObjectWithScope):
|
||||||
# Put the new members at the beginning
|
# Put the new members at the beginning
|
||||||
self.members = members + self.members
|
self.members = members + self.members
|
||||||
|
|
||||||
|
def getJSImplementation(self):
|
||||||
|
classId = self.getExtendedAttribute("JSImplementation")
|
||||||
|
if not classId:
|
||||||
|
return classId
|
||||||
|
assert isinstance(classId, list)
|
||||||
|
assert len(classId) == 1
|
||||||
|
return classId[0]
|
||||||
|
|
||||||
|
def isJSImplemented(self):
|
||||||
|
return bool(self.getJSImplementation())
|
||||||
|
|
||||||
|
def _getDependentObjects(self):
|
||||||
|
deps = set(self.members)
|
||||||
|
deps.union(self.implementedInterfaces)
|
||||||
|
if self.parent:
|
||||||
|
deps.add(self.parent)
|
||||||
|
return deps
|
||||||
|
|
||||||
class IDLDictionary(IDLObjectWithScope):
|
class IDLDictionary(IDLObjectWithScope):
|
||||||
def __init__(self, location, parentScope, name, parent, members):
|
def __init__(self, location, parentScope, name, parent, members):
|
||||||
assert isinstance(parentScope, IDLScope)
|
assert isinstance(parentScope, IDLScope)
|
||||||
|
@ -847,6 +923,11 @@ class IDLDictionary(IDLObjectWithScope):
|
||||||
def addExtendedAttributes(self, attrs):
|
def addExtendedAttributes(self, attrs):
|
||||||
assert len(attrs) == 0
|
assert len(attrs) == 0
|
||||||
|
|
||||||
|
def _getDependentObjects(self):
|
||||||
|
deps = set(self.members)
|
||||||
|
if (self.parent):
|
||||||
|
deps.add(self.parent)
|
||||||
|
return deps
|
||||||
|
|
||||||
class IDLEnum(IDLObjectWithIdentifier):
|
class IDLEnum(IDLObjectWithIdentifier):
|
||||||
def __init__(self, location, parentScope, name, values):
|
def __init__(self, location, parentScope, name, values):
|
||||||
|
@ -875,6 +956,9 @@ class IDLEnum(IDLObjectWithIdentifier):
|
||||||
def addExtendedAttributes(self, attrs):
|
def addExtendedAttributes(self, attrs):
|
||||||
assert len(attrs) == 0
|
assert len(attrs) == 0
|
||||||
|
|
||||||
|
def _getDependentObjects(self):
|
||||||
|
return set()
|
||||||
|
|
||||||
class IDLType(IDLObject):
|
class IDLType(IDLObject):
|
||||||
Tags = enum(
|
Tags = enum(
|
||||||
# The integer types
|
# The integer types
|
||||||
|
@ -893,6 +977,7 @@ class IDLType(IDLObject):
|
||||||
# Other types
|
# Other types
|
||||||
'any',
|
'any',
|
||||||
'domstring',
|
'domstring',
|
||||||
|
'bytestring',
|
||||||
'object',
|
'object',
|
||||||
'date',
|
'date',
|
||||||
'void',
|
'void',
|
||||||
|
@ -930,6 +1015,12 @@ class IDLType(IDLObject):
|
||||||
def isString(self):
|
def isString(self):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def isByteString(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def isDOMString(self):
|
||||||
|
return False
|
||||||
|
|
||||||
def isVoid(self):
|
def isVoid(self):
|
||||||
return self.name == "Void"
|
return self.name == "Void"
|
||||||
|
|
||||||
|
@ -1075,6 +1166,12 @@ class IDLNullableType(IDLType):
|
||||||
def isString(self):
|
def isString(self):
|
||||||
return self.inner.isString()
|
return self.inner.isString()
|
||||||
|
|
||||||
|
def isByteString(self):
|
||||||
|
return self.inner.isByteString()
|
||||||
|
|
||||||
|
def isDOMString(self):
|
||||||
|
return self.inner.isDOMString()
|
||||||
|
|
||||||
def isFloat(self):
|
def isFloat(self):
|
||||||
return self.inner.isFloat()
|
return self.inner.isFloat()
|
||||||
|
|
||||||
|
@ -1163,6 +1260,9 @@ class IDLNullableType(IDLType):
|
||||||
return False
|
return False
|
||||||
return self.inner.isDistinguishableFrom(other)
|
return self.inner.isDistinguishableFrom(other)
|
||||||
|
|
||||||
|
def _getDependentObjects(self):
|
||||||
|
return self.inner._getDependentObjects()
|
||||||
|
|
||||||
class IDLSequenceType(IDLType):
|
class IDLSequenceType(IDLType):
|
||||||
def __init__(self, location, parameterType):
|
def __init__(self, location, parameterType):
|
||||||
assert not parameterType.isVoid()
|
assert not parameterType.isVoid()
|
||||||
|
@ -1231,6 +1331,9 @@ class IDLSequenceType(IDLType):
|
||||||
other.isDictionary() or other.isDate() or
|
other.isDictionary() or other.isDate() or
|
||||||
other.isNonCallbackInterface())
|
other.isNonCallbackInterface())
|
||||||
|
|
||||||
|
def _getDependentObjects(self):
|
||||||
|
return self.inner._getDependentObjects()
|
||||||
|
|
||||||
class IDLUnionType(IDLType):
|
class IDLUnionType(IDLType):
|
||||||
def __init__(self, location, memberTypes):
|
def __init__(self, location, memberTypes):
|
||||||
IDLType.__init__(self, location, "")
|
IDLType.__init__(self, location, "")
|
||||||
|
@ -1317,6 +1420,9 @@ class IDLUnionType(IDLType):
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def _getDependentObjects(self):
|
||||||
|
return set(self.memberTypes)
|
||||||
|
|
||||||
class IDLArrayType(IDLType):
|
class IDLArrayType(IDLType):
|
||||||
def __init__(self, location, parameterType):
|
def __init__(self, location, parameterType):
|
||||||
assert not parameterType.isVoid()
|
assert not parameterType.isVoid()
|
||||||
|
@ -1393,6 +1499,9 @@ class IDLArrayType(IDLType):
|
||||||
other.isDictionary() or other.isDate() or
|
other.isDictionary() or other.isDate() or
|
||||||
other.isNonCallbackInterface())
|
other.isNonCallbackInterface())
|
||||||
|
|
||||||
|
def _getDependentObjects(self):
|
||||||
|
return self.inner._getDependentObjects()
|
||||||
|
|
||||||
class IDLTypedefType(IDLType, IDLObjectWithIdentifier):
|
class IDLTypedefType(IDLType, IDLObjectWithIdentifier):
|
||||||
def __init__(self, location, innerType, name):
|
def __init__(self, location, innerType, name):
|
||||||
IDLType.__init__(self, location, innerType.name)
|
IDLType.__init__(self, location, innerType.name)
|
||||||
|
@ -1478,6 +1587,9 @@ class IDLTypedefType(IDLType, IDLObjectWithIdentifier):
|
||||||
def isDistinguishableFrom(self, other):
|
def isDistinguishableFrom(self, other):
|
||||||
return self.inner.isDistinguishableFrom(other)
|
return self.inner.isDistinguishableFrom(other)
|
||||||
|
|
||||||
|
def _getDependentObjects(self):
|
||||||
|
return self.inner._getDependentObjects()
|
||||||
|
|
||||||
class IDLWrapperType(IDLType):
|
class IDLWrapperType(IDLType):
|
||||||
def __init__(self, location, inner):
|
def __init__(self, location, inner):
|
||||||
IDLType.__init__(self, location, inner.identifier.name)
|
IDLType.__init__(self, location, inner.identifier.name)
|
||||||
|
@ -1583,6 +1695,23 @@ class IDLWrapperType(IDLType):
|
||||||
assert other.isObject()
|
assert other.isObject()
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def _getDependentObjects(self):
|
||||||
|
# NB: The codegen for an interface type depends on
|
||||||
|
# a) That the identifier is in fact an interface (as opposed to
|
||||||
|
# a dictionary or something else).
|
||||||
|
# b) The native type of the interface.
|
||||||
|
# If we depend on the interface object we will also depend on
|
||||||
|
# anything the interface depends on which is undesirable. We
|
||||||
|
# considered implementing a dependency just on the interface type
|
||||||
|
# file, but then every modification to an interface would cause this
|
||||||
|
# to be regenerated which is still undesirable. We decided not to
|
||||||
|
# depend on anything, reasoning that:
|
||||||
|
# 1) Changing the concrete type of the interface requires modifying
|
||||||
|
# Bindings.conf, which is still a global dependency.
|
||||||
|
# 2) Changing an interface to a dictionary (or vice versa) with the
|
||||||
|
# same identifier should be incredibly rare.
|
||||||
|
return set()
|
||||||
|
|
||||||
class IDLBuiltinType(IDLType):
|
class IDLBuiltinType(IDLType):
|
||||||
|
|
||||||
Types = enum(
|
Types = enum(
|
||||||
|
@ -1602,6 +1731,7 @@ class IDLBuiltinType(IDLType):
|
||||||
# Other types
|
# Other types
|
||||||
'any',
|
'any',
|
||||||
'domstring',
|
'domstring',
|
||||||
|
'bytestring',
|
||||||
'object',
|
'object',
|
||||||
'date',
|
'date',
|
||||||
'void',
|
'void',
|
||||||
|
@ -1633,6 +1763,7 @@ class IDLBuiltinType(IDLType):
|
||||||
Types.double: IDLType.Tags.double,
|
Types.double: IDLType.Tags.double,
|
||||||
Types.any: IDLType.Tags.any,
|
Types.any: IDLType.Tags.any,
|
||||||
Types.domstring: IDLType.Tags.domstring,
|
Types.domstring: IDLType.Tags.domstring,
|
||||||
|
Types.bytestring: IDLType.Tags.bytestring,
|
||||||
Types.object: IDLType.Tags.object,
|
Types.object: IDLType.Tags.object,
|
||||||
Types.date: IDLType.Tags.date,
|
Types.date: IDLType.Tags.date,
|
||||||
Types.void: IDLType.Tags.void,
|
Types.void: IDLType.Tags.void,
|
||||||
|
@ -1658,6 +1789,13 @@ class IDLBuiltinType(IDLType):
|
||||||
return self._typeTag <= IDLBuiltinType.Types.double
|
return self._typeTag <= IDLBuiltinType.Types.double
|
||||||
|
|
||||||
def isString(self):
|
def isString(self):
|
||||||
|
return self._typeTag == IDLBuiltinType.Types.domstring or \
|
||||||
|
self._typeTag == IDLBuiltinType.Types.bytestring
|
||||||
|
|
||||||
|
def isByteString(self):
|
||||||
|
return self._typeTag == IDLBuiltinType.Types.bytestring
|
||||||
|
|
||||||
|
def isDOMString(self):
|
||||||
return self._typeTag == IDLBuiltinType.Types.domstring
|
return self._typeTag == IDLBuiltinType.Types.domstring
|
||||||
|
|
||||||
def isInteger(self):
|
def isInteger(self):
|
||||||
|
@ -1733,6 +1871,9 @@ class IDLBuiltinType(IDLType):
|
||||||
(self.isTypedArray() and not other.isArrayBufferView() and not
|
(self.isTypedArray() and not other.isArrayBufferView() and not
|
||||||
(other.isTypedArray() and other.name == self.name)))))
|
(other.isTypedArray() and other.name == self.name)))))
|
||||||
|
|
||||||
|
def _getDependentObjects(self):
|
||||||
|
return set()
|
||||||
|
|
||||||
BuiltinTypes = {
|
BuiltinTypes = {
|
||||||
IDLBuiltinType.Types.byte:
|
IDLBuiltinType.Types.byte:
|
||||||
IDLBuiltinType(BuiltinLocation("<builtin type>"), "Byte",
|
IDLBuiltinType(BuiltinLocation("<builtin type>"), "Byte",
|
||||||
|
@ -1877,6 +2018,9 @@ class IDLValue(IDLObject):
|
||||||
raise WebIDLError("Cannot coerce type %s to type %s." %
|
raise WebIDLError("Cannot coerce type %s to type %s." %
|
||||||
(self.type, type), [location])
|
(self.type, type), [location])
|
||||||
|
|
||||||
|
def _getDependentObjects(self):
|
||||||
|
return set()
|
||||||
|
|
||||||
class IDLNullValue(IDLObject):
|
class IDLNullValue(IDLObject):
|
||||||
def __init__(self, location):
|
def __init__(self, location):
|
||||||
IDLObject.__init__(self, location)
|
IDLObject.__init__(self, location)
|
||||||
|
@ -1895,6 +2039,9 @@ class IDLNullValue(IDLObject):
|
||||||
nullValue.type = type
|
nullValue.type = type
|
||||||
return nullValue
|
return nullValue
|
||||||
|
|
||||||
|
def _getDependentObjects(self):
|
||||||
|
return set()
|
||||||
|
|
||||||
|
|
||||||
class IDLInterfaceMember(IDLObjectWithIdentifier):
|
class IDLInterfaceMember(IDLObjectWithIdentifier):
|
||||||
|
|
||||||
|
@ -1966,6 +2113,9 @@ class IDLConst(IDLInterfaceMember):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def _getDependentObjects(self):
|
||||||
|
return set([self.type, self.value])
|
||||||
|
|
||||||
class IDLAttribute(IDLInterfaceMember):
|
class IDLAttribute(IDLInterfaceMember):
|
||||||
def __init__(self, location, identifier, type, readonly, inherit,
|
def __init__(self, location, identifier, type, readonly, inherit,
|
||||||
static=False):
|
static=False):
|
||||||
|
@ -2052,6 +2202,9 @@ class IDLAttribute(IDLInterfaceMember):
|
||||||
def hasLenientThis(self):
|
def hasLenientThis(self):
|
||||||
return self.lenientThis
|
return self.lenientThis
|
||||||
|
|
||||||
|
def _getDependentObjects(self):
|
||||||
|
return set([self.type])
|
||||||
|
|
||||||
class IDLArgument(IDLObjectWithIdentifier):
|
class IDLArgument(IDLObjectWithIdentifier):
|
||||||
def __init__(self, location, identifier, type, optional=False, defaultValue=None, variadic=False, dictionaryMember=False):
|
def __init__(self, location, identifier, type, optional=False, defaultValue=None, variadic=False, dictionaryMember=False):
|
||||||
IDLObjectWithIdentifier.__init__(self, location, None, identifier)
|
IDLObjectWithIdentifier.__init__(self, location, None, identifier)
|
||||||
|
@ -2124,6 +2277,12 @@ class IDLArgument(IDLObjectWithIdentifier):
|
||||||
self.location)
|
self.location)
|
||||||
assert self.defaultValue
|
assert self.defaultValue
|
||||||
|
|
||||||
|
def _getDependentObjects(self):
|
||||||
|
deps = set([self.type])
|
||||||
|
if self.defaultValue:
|
||||||
|
deps.add(self.defaultValue)
|
||||||
|
return deps
|
||||||
|
|
||||||
class IDLCallbackType(IDLType, IDLObjectWithScope):
|
class IDLCallbackType(IDLType, IDLObjectWithScope):
|
||||||
def __init__(self, location, parentScope, identifier, returnType, arguments):
|
def __init__(self, location, parentScope, identifier, returnType, arguments):
|
||||||
assert isinstance(returnType, IDLType)
|
assert isinstance(returnType, IDLType)
|
||||||
|
@ -2179,6 +2338,9 @@ class IDLCallbackType(IDLType, IDLObjectWithScope):
|
||||||
return (other.isPrimitive() or other.isString() or other.isEnum() or
|
return (other.isPrimitive() or other.isString() or other.isEnum() or
|
||||||
other.isNonCallbackInterface() or other.isDate())
|
other.isNonCallbackInterface() or other.isDate())
|
||||||
|
|
||||||
|
def _getDependentObjects(self):
|
||||||
|
return set([self._returnType] + self._arguments)
|
||||||
|
|
||||||
class IDLMethodOverload:
|
class IDLMethodOverload:
|
||||||
"""
|
"""
|
||||||
A class that represents a single overload of a WebIDL method. This is not
|
A class that represents a single overload of a WebIDL method. This is not
|
||||||
|
@ -2194,6 +2356,11 @@ class IDLMethodOverload:
|
||||||
self.arguments = list(arguments)
|
self.arguments = list(arguments)
|
||||||
self.location = location
|
self.location = location
|
||||||
|
|
||||||
|
def _getDependentObjects(self):
|
||||||
|
deps = set(self.arguments)
|
||||||
|
deps.add(self.returnType)
|
||||||
|
return deps
|
||||||
|
|
||||||
class IDLMethod(IDLInterfaceMember, IDLScope):
|
class IDLMethod(IDLInterfaceMember, IDLScope):
|
||||||
|
|
||||||
Special = enum(
|
Special = enum(
|
||||||
|
@ -2494,6 +2661,12 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
||||||
[attr.location, self.location])
|
[attr.location, self.location])
|
||||||
IDLInterfaceMember.handleExtendedAttribute(self, attr)
|
IDLInterfaceMember.handleExtendedAttribute(self, attr)
|
||||||
|
|
||||||
|
def _getDependentObjects(self):
|
||||||
|
deps = set()
|
||||||
|
for overload in self._overloads:
|
||||||
|
deps.union(overload._getDependentObjects())
|
||||||
|
return deps
|
||||||
|
|
||||||
class IDLImplementsStatement(IDLObject):
|
class IDLImplementsStatement(IDLObject):
|
||||||
def __init__(self, location, implementor, implementee):
|
def __init__(self, location, implementor, implementee):
|
||||||
IDLObject.__init__(self, location)
|
IDLObject.__init__(self, location)
|
||||||
|
|
|
@ -50,7 +50,7 @@ impl Traceable for Node<ScriptView> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
debug!("tracing {:p}?:", self.reflector_.get_jsobject());
|
debug!("tracing {:p}?:", self.reflector().get_jsobject());
|
||||||
trace_node(tracer, self.parent_node, "parent");
|
trace_node(tracer, self.parent_node, "parent");
|
||||||
trace_node(tracer, self.first_child, "first child");
|
trace_node(tracer, self.first_child, "first child");
|
||||||
trace_node(tracer, self.last_child, "last child");
|
trace_node(tracer, self.last_child, "last child");
|
||||||
|
|
|
@ -4,8 +4,8 @@
|
||||||
|
|
||||||
use dom::bindings::codegen::PrototypeList;
|
use dom::bindings::codegen::PrototypeList;
|
||||||
use dom::bindings::codegen::PrototypeList::MAX_PROTO_CHAIN_LENGTH;
|
use dom::bindings::codegen::PrototypeList::MAX_PROTO_CHAIN_LENGTH;
|
||||||
use dom::window;
|
|
||||||
use dom::node::{AbstractNode, ScriptView};
|
use dom::node::{AbstractNode, ScriptView};
|
||||||
|
use dom::window;
|
||||||
|
|
||||||
use std::libc::c_uint;
|
use std::libc::c_uint;
|
||||||
use std::cast;
|
use std::cast;
|
||||||
|
@ -22,6 +22,7 @@ use js::glue::{js_IsObjectProxyClass, js_IsFunctionProxyClass, IsProxyHandlerFam
|
||||||
use js::jsapi::{JS_AlreadyHasOwnProperty, JS_NewObject, JS_NewFunction, JS_GetGlobalObject};
|
use js::jsapi::{JS_AlreadyHasOwnProperty, JS_NewObject, JS_NewFunction, JS_GetGlobalObject};
|
||||||
use js::jsapi::{JS_DefineProperties, JS_WrapValue, JS_ForwardGetPropertyTo};
|
use js::jsapi::{JS_DefineProperties, JS_WrapValue, JS_ForwardGetPropertyTo};
|
||||||
use js::jsapi::{JS_GetClass, JS_LinkConstructorAndPrototype, JS_GetStringCharsAndLength};
|
use js::jsapi::{JS_GetClass, JS_LinkConstructorAndPrototype, JS_GetStringCharsAndLength};
|
||||||
|
use js::jsapi::{JS_ObjectIsRegExp, JS_ObjectIsDate};
|
||||||
use js::jsapi::{JS_GetFunctionPrototype, JS_InternString, JS_GetFunctionObject};
|
use js::jsapi::{JS_GetFunctionPrototype, JS_InternString, JS_GetFunctionObject};
|
||||||
use js::jsapi::{JS_HasPropertyById, JS_GetPrototype, JS_GetGlobalForObject};
|
use js::jsapi::{JS_HasPropertyById, JS_GetPrototype, JS_GetGlobalForObject};
|
||||||
use js::jsapi::{JS_NewUCStringCopyN, JS_DefineFunctions, JS_DefineProperty};
|
use js::jsapi::{JS_NewUCStringCopyN, JS_DefineFunctions, JS_DefineProperty};
|
||||||
|
@ -30,7 +31,7 @@ use js::jsapi::{JSContext, JSObject, JSBool, jsid, JSClass, JSNative, JSTracer};
|
||||||
use js::jsapi::{JSFunctionSpec, JSPropertySpec, JSVal, JSPropertyDescriptor};
|
use js::jsapi::{JSFunctionSpec, JSPropertySpec, JSVal, JSPropertyDescriptor};
|
||||||
use js::jsapi::{JSPropertyOp, JSStrictPropertyOp, JS_NewGlobalObject, JS_InitStandardClasses};
|
use js::jsapi::{JSPropertyOp, JSStrictPropertyOp, JS_NewGlobalObject, JS_InitStandardClasses};
|
||||||
use js::jsfriendapi::bindgen::JS_NewObjectWithUniqueType;
|
use js::jsfriendapi::bindgen::JS_NewObjectWithUniqueType;
|
||||||
use js::{JSPROP_ENUMERATE, JSVAL_NULL};
|
use js::{JSPROP_ENUMERATE, JSVAL_NULL, JSCLASS_IS_GLOBAL, JSCLASS_IS_DOMJSCLASS};
|
||||||
use js::{JSPROP_PERMANENT, JSID_VOID, JSPROP_NATIVE_ACCESSORS, JSPROP_GETTER};
|
use js::{JSPROP_PERMANENT, JSID_VOID, JSPROP_NATIVE_ACCESSORS, JSPROP_GETTER};
|
||||||
use js::{JSPROP_SETTER, JSVAL_VOID, JSVAL_TRUE, JSVAL_FALSE};
|
use js::{JSPROP_SETTER, JSVAL_VOID, JSVAL_TRUE, JSVAL_FALSE};
|
||||||
use js::{JS_THIS_OBJECT, JSFUN_CONSTRUCTOR, JS_CALLEE, JSPROP_READONLY};
|
use js::{JS_THIS_OBJECT, JSFUN_CONSTRUCTOR, JS_CALLEE, JSPROP_READONLY};
|
||||||
|
@ -767,6 +768,8 @@ pub enum Error {
|
||||||
NotFound,
|
NotFound,
|
||||||
HierarchyRequest,
|
HierarchyRequest,
|
||||||
InvalidCharacter,
|
InvalidCharacter,
|
||||||
|
NotSupported,
|
||||||
|
InvalidState
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Fallible<T> = Result<T, Error>;
|
pub type Fallible<T> = Result<T, Error>;
|
||||||
|
@ -819,6 +822,13 @@ pub fn HasPropertyOnPrototype(cx: *JSContext, proxy: *JSObject, id: jsid) -> boo
|
||||||
return !GetPropertyOnPrototype(cx, proxy, id, &mut found, ptr::null()) || found;
|
return !GetPropertyOnPrototype(cx, proxy, id, &mut found, ptr::null()) || found;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[fixed_stack_segment]
|
||||||
|
pub fn IsConvertibleToCallbackInterface(cx: *JSContext, obj: *JSObject) -> bool {
|
||||||
|
unsafe {
|
||||||
|
JS_ObjectIsDate(cx, obj) == 0 && JS_ObjectIsRegExp(cx, obj) == 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[fixed_stack_segment]
|
#[fixed_stack_segment]
|
||||||
pub fn CreateDOMGlobal(cx: *JSContext, class: *JSClass) -> *JSObject {
|
pub fn CreateDOMGlobal(cx: *JSContext, class: *JSClass) -> *JSObject {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -832,6 +842,30 @@ pub fn CreateDOMGlobal(cx: *JSContext, class: *JSClass) -> *JSObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[fixed_stack_segment]
|
||||||
|
fn cx_for_dom_reflector(obj: *JSObject) -> *JSContext {
|
||||||
|
unsafe {
|
||||||
|
let global = GetGlobalForObjectCrossCompartment(obj);
|
||||||
|
let clasp = JS_GetClass(global);
|
||||||
|
assert!(((*clasp).flags & (JSCLASS_IS_DOMJSCLASS | JSCLASS_IS_GLOBAL)) != 0);
|
||||||
|
//XXXjdm either don't hardcode or sanity assert prototype stuff
|
||||||
|
let win = unwrap_object::<*Box<window::Window>>(global, PrototypeList::id::Window, 1);
|
||||||
|
match win {
|
||||||
|
Ok(win) => {
|
||||||
|
match (*win).data.page.js_info {
|
||||||
|
Some(ref info) => info.js_context.ptr,
|
||||||
|
None => fail!("no JS context for DOM global")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => fail!("found DOM global that doesn't unwrap to Window")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cx_for_dom_object<T: Reflectable>(obj: &mut T) -> *JSContext {
|
||||||
|
cx_for_dom_reflector(obj.reflector().get_jsobject())
|
||||||
|
}
|
||||||
|
|
||||||
/// Check if an element name is valid. See http://www.w3.org/TR/xml/#NT-Name
|
/// Check if an element name is valid. See http://www.w3.org/TR/xml/#NT-Name
|
||||||
/// for details.
|
/// for details.
|
||||||
pub fn is_valid_element_name(name: &str) -> bool {
|
pub fn is_valid_element_name(name: &str) -> bool {
|
||||||
|
|
|
@ -5,15 +5,20 @@
|
||||||
use dom::comment::Comment;
|
use dom::comment::Comment;
|
||||||
use dom::bindings::codegen::DocumentBinding;
|
use dom::bindings::codegen::DocumentBinding;
|
||||||
use dom::bindings::utils::{DOMString, ErrorResult, Fallible};
|
use dom::bindings::utils::{DOMString, ErrorResult, Fallible};
|
||||||
use dom::bindings::utils::{Reflectable, Reflector, DerivedWrapper};
|
use dom::bindings::utils::{Reflectable, Reflector, DerivedWrapper, NotSupported};
|
||||||
use dom::bindings::utils::{is_valid_element_name, InvalidCharacter, Traceable, null_str_as_empty, null_str_as_word_null};
|
use dom::bindings::utils::{is_valid_element_name, InvalidCharacter, Traceable};
|
||||||
|
use dom::bindings::utils::{null_str_as_empty_ref, null_str_as_empty, null_str_as_word_null};
|
||||||
use dom::documentfragment::DocumentFragment;
|
use dom::documentfragment::DocumentFragment;
|
||||||
use dom::element::{Element};
|
use dom::element::{Element};
|
||||||
use dom::element::{HTMLHeadElementTypeId, HTMLTitleElementTypeId};
|
use dom::element::{HTMLHeadElementTypeId, HTMLTitleElementTypeId};
|
||||||
|
use dom::event::{AbstractEvent, Event, HTMLEventTypeId, UIEventTypeId};
|
||||||
use dom::htmlcollection::HTMLCollection;
|
use dom::htmlcollection::HTMLCollection;
|
||||||
use dom::htmldocument::HTMLDocument;
|
use dom::htmldocument::HTMLDocument;
|
||||||
|
use dom::htmlelement::HTMLElement;
|
||||||
|
use dom::mouseevent::MouseEvent;
|
||||||
use dom::node::{AbstractNode, ScriptView, Node, ElementNodeTypeId, DocumentNodeTypeId};
|
use dom::node::{AbstractNode, ScriptView, Node, ElementNodeTypeId, DocumentNodeTypeId};
|
||||||
use dom::text::Text;
|
use dom::text::Text;
|
||||||
|
use dom::uievent::UIEvent;
|
||||||
use dom::window::Window;
|
use dom::window::Window;
|
||||||
use dom::htmltitleelement::HTMLTitleElement;
|
use dom::htmltitleelement::HTMLTitleElement;
|
||||||
use html::hubbub_html_parser::build_element_from_tag;
|
use html::hubbub_html_parser::build_element_from_tag;
|
||||||
|
@ -255,6 +260,15 @@ impl Document {
|
||||||
Comment::new(null_str_as_word_null(data), abstract_self)
|
Comment::new(null_str_as_word_null(data), abstract_self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn CreateEvent(&self, interface: &DOMString) -> Fallible<AbstractEvent> {
|
||||||
|
match null_str_as_empty_ref(interface) {
|
||||||
|
"UIEvents" => Ok(UIEvent::new(self.window, UIEventTypeId)),
|
||||||
|
"MouseEvents" => Ok(MouseEvent::new(self.window)),
|
||||||
|
"HTMLEvents" => Ok(Event::new(self.window, HTMLEventTypeId)),
|
||||||
|
_ => Err(NotSupported)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn Title(&self, _: AbstractDocument) -> DOMString {
|
pub fn Title(&self, _: AbstractDocument) -> DOMString {
|
||||||
let mut title = ~"";
|
let mut title = ~"";
|
||||||
match self.doctype {
|
match self.doctype {
|
||||||
|
|
|
@ -2,17 +2,23 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use dom::eventtarget::EventTarget;
|
use dom::eventtarget::AbstractEventTarget;
|
||||||
use dom::window::Window;
|
use dom::window::Window;
|
||||||
use dom::bindings::codegen::EventBinding;
|
use dom::bindings::codegen::EventBinding;
|
||||||
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
|
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object, DerivedWrapper};
|
||||||
use dom::bindings::utils::{DOMString, ErrorResult, Fallible};
|
use dom::bindings::utils::{DOMString, ErrorResult, Fallible, null_str_as_word_null};
|
||||||
|
use dom::mouseevent::MouseEvent;
|
||||||
|
use dom::uievent::UIEvent;
|
||||||
|
|
||||||
use geom::point::Point2D;
|
use geom::point::Point2D;
|
||||||
use js::jsapi::{JSObject, JSContext};
|
use js::jsapi::{JSObject, JSContext, JSVal};
|
||||||
|
use js::glue::RUST_OBJECT_TO_JSVAL;
|
||||||
|
|
||||||
use script_task::page_from_context;
|
use script_task::page_from_context;
|
||||||
|
|
||||||
|
use std::cast;
|
||||||
|
use std::unstable::raw::Box;
|
||||||
|
|
||||||
pub enum Event_ {
|
pub enum Event_ {
|
||||||
ResizeEvent(uint, uint),
|
ResizeEvent(uint, uint),
|
||||||
ReflowEvent,
|
ReflowEvent,
|
||||||
|
@ -21,45 +27,194 @@ pub enum Event_ {
|
||||||
MouseUpEvent(uint, Point2D<f32>),
|
MouseUpEvent(uint, Point2D<f32>),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Event {
|
pub struct AbstractEvent {
|
||||||
reflector_: Reflector,
|
event: *mut Box<Event>
|
||||||
type_: DOMString,
|
|
||||||
default_prevented: bool,
|
|
||||||
cancelable: bool,
|
|
||||||
bubbles: bool,
|
|
||||||
trusted: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Event {
|
pub enum EventPhase {
|
||||||
pub fn new_inherited(type_: &DOMString) -> Event {
|
Phase_None = 0,
|
||||||
Event {
|
Phase_Capturing,
|
||||||
reflector_: Reflector::new(),
|
Phase_At_Target,
|
||||||
type_: (*type_).clone(),
|
Phase_Bubbling
|
||||||
default_prevented: false,
|
}
|
||||||
cancelable: true,
|
|
||||||
bubbles: true,
|
impl AbstractEvent {
|
||||||
trusted: false
|
pub fn from_box(box: *mut Box<Event>) -> AbstractEvent {
|
||||||
|
AbstractEvent {
|
||||||
|
event: box
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(window: @mut Window, type_: &DOMString) -> @mut Event {
|
//
|
||||||
reflect_dom_object(@mut Event::new_inherited(type_), window, EventBinding::Wrap)
|
// Downcasting borrows
|
||||||
|
//
|
||||||
|
|
||||||
|
fn transmute<'a, T>(&'a self) -> &'a T {
|
||||||
|
unsafe {
|
||||||
|
let box: *Box<T> = self.event as *Box<T>;
|
||||||
|
&(*box).data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transmute_mut<'a, T>(&'a self) -> &'a mut T {
|
||||||
|
unsafe {
|
||||||
|
let box: *mut Box<T> = self.event as *mut Box<T>;
|
||||||
|
&mut (*box).data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn type_id(&self) -> EventTypeId {
|
||||||
|
self.event().type_id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn event<'a>(&'a self) -> &'a Event {
|
||||||
|
self.transmute()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mut_event<'a>(&'a self) -> &'a mut Event {
|
||||||
|
self.transmute_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_uievent(&self) -> bool {
|
||||||
|
self.type_id() == UIEventTypeId
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn uievent<'a>(&'a self) -> &'a UIEvent {
|
||||||
|
assert!(self.is_uievent());
|
||||||
|
self.transmute()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mut_uievent<'a>(&'a self) -> &'a mut UIEvent {
|
||||||
|
assert!(self.is_uievent());
|
||||||
|
self.transmute_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_mouseevent(&self) -> bool {
|
||||||
|
self.type_id() == MouseEventTypeId
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mouseevent<'a>(&'a self) -> &'a MouseEvent {
|
||||||
|
assert!(self.is_mouseevent());
|
||||||
|
self.transmute()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mut_mouseevent<'a>(&'a self) -> &'a mut MouseEvent {
|
||||||
|
assert!(self.is_mouseevent());
|
||||||
|
self.transmute_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn propagation_stopped(&self) -> bool {
|
||||||
|
self.event().stop_propagation
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bubbles(&self) -> bool {
|
||||||
|
self.event().bubbles
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerivedWrapper for AbstractEvent {
|
||||||
|
#[fixed_stack_segment]
|
||||||
|
fn wrap(&mut self, _cx: *JSContext, _scope: *JSObject, vp: *mut JSVal) -> i32 {
|
||||||
|
let wrapper = self.reflector().get_jsobject();
|
||||||
|
if wrapper.is_not_null() {
|
||||||
|
unsafe { *vp = RUST_OBJECT_TO_JSVAL(wrapper) };
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Reflectable for AbstractEvent {
|
||||||
|
fn reflector<'a>(&'a self) -> &'a Reflector {
|
||||||
|
self.event().reflector()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mut_reflector<'a>(&'a mut self) -> &'a mut Reflector {
|
||||||
|
self.mut_event().mut_reflector()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wrap_object_shared(@mut self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
|
||||||
|
fail!(~"doesn't make any sense");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn GetParentObject(&self, cx: *JSContext) -> Option<@mut Reflectable> {
|
||||||
|
self.event().GetParentObject(cx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[deriving(Eq)]
|
||||||
|
pub enum EventTypeId {
|
||||||
|
HTMLEventTypeId,
|
||||||
|
UIEventTypeId,
|
||||||
|
MouseEventTypeId,
|
||||||
|
KeyEventTypeId
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Event {
|
||||||
|
type_id: EventTypeId,
|
||||||
|
reflector_: Reflector,
|
||||||
|
current_target: Option<AbstractEventTarget>,
|
||||||
|
target: Option<AbstractEventTarget>,
|
||||||
|
type_: ~str,
|
||||||
|
phase: EventPhase,
|
||||||
|
default_prevented: bool,
|
||||||
|
stop_propagation: bool,
|
||||||
|
stop_immediate: bool,
|
||||||
|
cancelable: bool,
|
||||||
|
bubbles: bool,
|
||||||
|
trusted: bool,
|
||||||
|
dispatching: bool,
|
||||||
|
initialized: bool
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Event {
|
||||||
|
pub fn new_inherited(type_id: EventTypeId) -> Event {
|
||||||
|
Event {
|
||||||
|
type_id: type_id,
|
||||||
|
reflector_: Reflector::new(),
|
||||||
|
current_target: None,
|
||||||
|
target: None,
|
||||||
|
phase: Phase_None,
|
||||||
|
type_: ~"",
|
||||||
|
default_prevented: false,
|
||||||
|
cancelable: true,
|
||||||
|
bubbles: true,
|
||||||
|
trusted: false,
|
||||||
|
dispatching: false,
|
||||||
|
stop_propagation: false,
|
||||||
|
stop_immediate: false,
|
||||||
|
initialized: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//FIXME: E should be bounded by some trait that is only implemented for Event types
|
||||||
|
pub fn as_abstract<E>(event: @mut E) -> AbstractEvent {
|
||||||
|
// This surrenders memory management of the event!
|
||||||
|
AbstractEvent {
|
||||||
|
event: unsafe { cast::transmute(event) },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(window: @mut Window, type_id: EventTypeId) -> AbstractEvent {
|
||||||
|
let ev = reflect_dom_object(@mut Event::new_inherited(type_id), window,
|
||||||
|
EventBinding::Wrap);
|
||||||
|
Event::as_abstract(ev)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn EventPhase(&self) -> u16 {
|
pub fn EventPhase(&self) -> u16 {
|
||||||
0
|
self.phase as u16
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn Type(&self) -> DOMString {
|
pub fn Type(&self) -> DOMString {
|
||||||
self.type_.clone()
|
Some(self.type_.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn GetTarget(&self) -> Option<@mut EventTarget> {
|
pub fn GetTarget(&self) -> Option<AbstractEventTarget> {
|
||||||
None
|
self.target
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn GetCurrentTarget(&self) -> Option<@mut EventTarget> {
|
pub fn GetCurrentTarget(&self) -> Option<AbstractEventTarget> {
|
||||||
None
|
self.current_target
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn DefaultPrevented(&self) -> bool {
|
pub fn DefaultPrevented(&self) -> bool {
|
||||||
|
@ -67,13 +222,18 @@ impl Event {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn PreventDefault(&mut self) {
|
pub fn PreventDefault(&mut self) {
|
||||||
self.default_prevented = true
|
if self.cancelable {
|
||||||
|
self.default_prevented = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn StopPropagation(&mut self) {
|
pub fn StopPropagation(&mut self) {
|
||||||
|
self.stop_propagation = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn StopImmediatePropagation(&mut self) {
|
pub fn StopImmediatePropagation(&mut self) {
|
||||||
|
self.stop_immediate = true;
|
||||||
|
self.stop_propagation = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn Bubbles(&self) -> bool {
|
pub fn Bubbles(&self) -> bool {
|
||||||
|
@ -92,9 +252,10 @@ impl Event {
|
||||||
type_: &DOMString,
|
type_: &DOMString,
|
||||||
bubbles: bool,
|
bubbles: bool,
|
||||||
cancelable: bool) -> ErrorResult {
|
cancelable: bool) -> ErrorResult {
|
||||||
self.type_ = (*type_).clone();
|
self.type_ = null_str_as_word_null(type_);
|
||||||
self.cancelable = cancelable;
|
self.cancelable = cancelable;
|
||||||
self.bubbles = bubbles;
|
self.bubbles = bubbles;
|
||||||
|
self.initialized = true;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,9 +264,11 @@ impl Event {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn Constructor(global: @mut Window,
|
pub fn Constructor(global: @mut Window,
|
||||||
type_: &DOMString,
|
type_: &DOMString,
|
||||||
_init: &EventBinding::EventInit) -> Fallible<@mut Event> {
|
init: &EventBinding::EventInit) -> Fallible<AbstractEvent> {
|
||||||
Ok(Event::new(global, type_))
|
let ev = Event::new(global, HTMLEventTypeId);
|
||||||
|
ev.mut_event().InitEvent(type_, init.bubbles, init.cancelable);
|
||||||
|
Ok(ev)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
111
src/components/script/dom/eventdispatcher.rs
Normal file
111
src/components/script/dom/eventdispatcher.rs
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
/* 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 http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use dom::bindings::callback::eReportExceptions;
|
||||||
|
use dom::eventtarget::{AbstractEventTarget, Capturing, Bubbling};
|
||||||
|
use dom::event::{AbstractEvent, Phase_At_Target, Phase_None, Phase_Bubbling, Phase_Capturing};
|
||||||
|
use dom::node::AbstractNode;
|
||||||
|
use servo_util::tree::{TreeNodeRef};
|
||||||
|
|
||||||
|
// See http://dom.spec.whatwg.org/#concept-event-dispatch for the full dispatch algorithm
|
||||||
|
pub fn dispatch_event(target: AbstractEventTarget, event: AbstractEvent) -> bool {
|
||||||
|
assert!(!event.event().dispatching);
|
||||||
|
|
||||||
|
{
|
||||||
|
let event = event.mut_event();
|
||||||
|
event.target = Some(target);
|
||||||
|
event.dispatching = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let type_ = event.event().type_.clone();
|
||||||
|
let mut chain = ~[];
|
||||||
|
|
||||||
|
//TODO: no chain if not participating in a tree
|
||||||
|
if target.is_node() {
|
||||||
|
for ancestor in AbstractNode::from_eventtarget(target).ancestors() {
|
||||||
|
chain.push(AbstractEventTarget::from_node(ancestor));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event.mut_event().phase = Phase_Capturing;
|
||||||
|
|
||||||
|
//FIXME: The "callback this value" should be currentTarget
|
||||||
|
|
||||||
|
/* capturing */
|
||||||
|
for &cur_target in chain.rev_iter() {
|
||||||
|
//XXX bad clone
|
||||||
|
let stopped = match cur_target.eventtarget().get_listeners_for(type_.clone(), Capturing) {
|
||||||
|
Some(listeners) => {
|
||||||
|
event.mut_event().current_target = Some(cur_target);
|
||||||
|
for listener in listeners.iter() {
|
||||||
|
listener.HandleEvent__(event, eReportExceptions);
|
||||||
|
|
||||||
|
if event.event().stop_immediate {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event.propagation_stopped()
|
||||||
|
}
|
||||||
|
None => false
|
||||||
|
};
|
||||||
|
|
||||||
|
if stopped {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* at target */
|
||||||
|
if !event.propagation_stopped() {
|
||||||
|
{
|
||||||
|
let event = event.mut_event();
|
||||||
|
event.phase = Phase_At_Target;
|
||||||
|
event.current_target = Some(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
let opt_listeners = target.eventtarget().get_listeners(type_.clone());
|
||||||
|
for listeners in opt_listeners.iter() {
|
||||||
|
for listener in listeners.iter() {
|
||||||
|
listener.HandleEvent__(event, eReportExceptions);
|
||||||
|
if event.event().stop_immediate {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* bubbling */
|
||||||
|
if event.bubbles() && !event.propagation_stopped() {
|
||||||
|
event.mut_event().phase = Phase_Bubbling;
|
||||||
|
|
||||||
|
for &cur_target in chain.iter() {
|
||||||
|
//XXX bad clone
|
||||||
|
let stopped = match cur_target.eventtarget().get_listeners_for(type_.clone(), Bubbling) {
|
||||||
|
Some(listeners) => {
|
||||||
|
event.mut_event().current_target = Some(cur_target);
|
||||||
|
for listener in listeners.iter() {
|
||||||
|
listener.HandleEvent__(event, eReportExceptions);
|
||||||
|
|
||||||
|
if event.event().stop_immediate {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event.propagation_stopped()
|
||||||
|
}
|
||||||
|
None => false
|
||||||
|
};
|
||||||
|
if stopped {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let event = event.mut_event();
|
||||||
|
event.dispatching = false;
|
||||||
|
event.phase = Phase_None;
|
||||||
|
event.current_target = None;
|
||||||
|
|
||||||
|
!event.DefaultPrevented()
|
||||||
|
}
|
|
@ -3,24 +3,196 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use dom::bindings::codegen::EventTargetBinding;
|
use dom::bindings::codegen::EventTargetBinding;
|
||||||
use dom::bindings::utils::{Reflectable, Reflector};
|
use dom::bindings::utils::{Reflectable, Reflector, DOMString, Fallible, DerivedWrapper};
|
||||||
|
use dom::bindings::utils::{null_str_as_word_null, InvalidState};
|
||||||
|
use dom::bindings::codegen::EventListenerBinding::EventListener;
|
||||||
|
use dom::event::AbstractEvent;
|
||||||
|
use dom::eventdispatcher::dispatch_event;
|
||||||
|
use dom::node::{AbstractNode, ScriptView};
|
||||||
use script_task::page_from_context;
|
use script_task::page_from_context;
|
||||||
|
|
||||||
use js::jsapi::{JSObject, JSContext};
|
use js::jsapi::{JSObject, JSContext, JSVal};
|
||||||
|
use js::glue::RUST_OBJECT_TO_JSVAL;
|
||||||
|
|
||||||
pub struct EventTarget {
|
use std::cast;
|
||||||
reflector_: Reflector
|
use std::hashmap::HashMap;
|
||||||
|
use std::unstable::raw::Box;
|
||||||
|
|
||||||
|
#[deriving(Eq)]
|
||||||
|
pub enum ListenerPhase {
|
||||||
|
Capturing,
|
||||||
|
Bubbling,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventTarget {
|
#[deriving(Eq)]
|
||||||
pub fn new() -> ~EventTarget {
|
pub enum EventTargetTypeId {
|
||||||
~EventTarget {
|
WindowTypeId,
|
||||||
reflector_: Reflector::new()
|
NodeTypeId
|
||||||
|
}
|
||||||
|
|
||||||
|
#[deriving(Eq)]
|
||||||
|
struct EventListenerEntry {
|
||||||
|
phase: ListenerPhase,
|
||||||
|
listener: EventListener
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct EventTarget {
|
||||||
|
type_id: EventTargetTypeId,
|
||||||
|
reflector_: Reflector,
|
||||||
|
handlers: HashMap<~str, ~[EventListenerEntry]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AbstractEventTarget {
|
||||||
|
eventtarget: *mut Box<EventTarget>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AbstractEventTarget {
|
||||||
|
pub fn from_box<T>(box: *mut Box<T>) -> AbstractEventTarget {
|
||||||
|
AbstractEventTarget {
|
||||||
|
eventtarget: box as *mut Box<EventTarget>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init_wrapper(@mut self, cx: *JSContext, scope: *JSObject) {
|
pub fn from_node(node: AbstractNode<ScriptView>) -> AbstractEventTarget {
|
||||||
self.wrap_object_shared(cx, scope);
|
unsafe {
|
||||||
|
cast::transmute(node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn type_id(&self) -> EventTargetTypeId {
|
||||||
|
self.eventtarget().type_id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_window(&self) -> bool {
|
||||||
|
self.type_id() == WindowTypeId
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_node(&self) -> bool {
|
||||||
|
self.type_id() == NodeTypeId
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Downcasting borrows
|
||||||
|
//
|
||||||
|
|
||||||
|
fn transmute<'a, T>(&'a self) -> &'a T {
|
||||||
|
unsafe {
|
||||||
|
let box: *Box<T> = self.eventtarget as *Box<T>;
|
||||||
|
&(*box).data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transmute_mut<'a, T>(&'a mut self) -> &'a mut T {
|
||||||
|
unsafe {
|
||||||
|
let box: *mut Box<T> = self.eventtarget as *mut Box<T>;
|
||||||
|
&mut (*box).data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn eventtarget<'a>(&'a self) -> &'a EventTarget {
|
||||||
|
self.transmute()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mut_eventtarget<'a>(&'a mut self) -> &'a mut EventTarget {
|
||||||
|
self.transmute_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerivedWrapper for AbstractEventTarget {
|
||||||
|
#[fixed_stack_segment]
|
||||||
|
fn wrap(&mut self, _cx: *JSContext, _scope: *JSObject, vp: *mut JSVal) -> i32 {
|
||||||
|
let wrapper = self.reflector().get_jsobject();
|
||||||
|
if wrapper.is_not_null() {
|
||||||
|
unsafe { *vp = RUST_OBJECT_TO_JSVAL(wrapper) };
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Reflectable for AbstractEventTarget {
|
||||||
|
fn reflector<'a>(&'a self) -> &'a Reflector {
|
||||||
|
self.eventtarget().reflector()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mut_reflector<'a>(&'a mut self) -> &'a mut Reflector {
|
||||||
|
self.mut_eventtarget().mut_reflector()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wrap_object_shared(@mut self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn GetParentObject(&self, cx: *JSContext) -> Option<@mut Reflectable> {
|
||||||
|
self.eventtarget().GetParentObject(cx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EventTarget {
|
||||||
|
pub fn new_inherited(type_id: EventTargetTypeId) -> EventTarget {
|
||||||
|
EventTarget {
|
||||||
|
type_id: type_id,
|
||||||
|
reflector_: Reflector::new(),
|
||||||
|
handlers: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_listeners(&self, type_: ~str) -> Option<~[EventListener]> {
|
||||||
|
do self.handlers.find_equiv(&type_).map |listeners| {
|
||||||
|
listeners.iter().map(|entry| entry.listener).collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_listeners_for(&self, type_: ~str, desired_phase: ListenerPhase)
|
||||||
|
-> Option<~[EventListener]> {
|
||||||
|
do self.handlers.find_equiv(&type_).map |listeners| {
|
||||||
|
let filtered = listeners.iter().filter(|entry| entry.phase == desired_phase);
|
||||||
|
filtered.map(|entry| entry.listener).collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn AddEventListener(&mut self,
|
||||||
|
ty: &DOMString,
|
||||||
|
listener: Option<EventListener>,
|
||||||
|
capture: bool) {
|
||||||
|
for &listener in listener.iter() {
|
||||||
|
let entry = self.handlers.find_or_insert_with(null_str_as_word_null(ty), |_| ~[]);
|
||||||
|
let phase = if capture { Capturing } else { Bubbling };
|
||||||
|
let new_entry = EventListenerEntry {
|
||||||
|
phase: phase,
|
||||||
|
listener: listener
|
||||||
|
};
|
||||||
|
if entry.position_elem(&new_entry).is_none() {
|
||||||
|
entry.push(new_entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn RemoveEventListener(&mut self,
|
||||||
|
ty: &DOMString,
|
||||||
|
listener: Option<EventListener>,
|
||||||
|
capture: bool) {
|
||||||
|
for &listener in listener.iter() {
|
||||||
|
let mut entry = self.handlers.find_mut(&null_str_as_word_null(ty));
|
||||||
|
for entry in entry.mut_iter() {
|
||||||
|
let phase = if capture { Capturing } else { Bubbling };
|
||||||
|
let old_entry = EventListenerEntry {
|
||||||
|
phase: phase,
|
||||||
|
listener: listener
|
||||||
|
};
|
||||||
|
let position = entry.position_elem(&old_entry);
|
||||||
|
for &position in position.iter() {
|
||||||
|
entry.remove(position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn DispatchEvent(&self, abstract_self: AbstractEventTarget, event: AbstractEvent) -> Fallible<bool> {
|
||||||
|
if event.event().dispatching || !event.event().initialized {
|
||||||
|
return Err(InvalidState);
|
||||||
|
}
|
||||||
|
Ok(dispatch_event(abstract_self, event))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
use dom::bindings::codegen::MouseEventBinding;
|
use dom::bindings::codegen::MouseEventBinding;
|
||||||
use dom::bindings::utils::{ErrorResult, Fallible, DOMString};
|
use dom::bindings::utils::{ErrorResult, Fallible, DOMString};
|
||||||
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
|
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
|
||||||
use dom::eventtarget::EventTarget;
|
use dom::event::{AbstractEvent, Event, MouseEventTypeId};
|
||||||
|
use dom::eventtarget::AbstractEventTarget;
|
||||||
use dom::uievent::UIEvent;
|
use dom::uievent::UIEvent;
|
||||||
use dom::window::Window;
|
use dom::window::Window;
|
||||||
use dom::windowproxy::WindowProxy;
|
use dom::windowproxy::WindowProxy;
|
||||||
|
@ -23,38 +24,42 @@ pub struct MouseEvent {
|
||||||
alt_key: bool,
|
alt_key: bool,
|
||||||
meta_key: bool,
|
meta_key: bool,
|
||||||
button: u16,
|
button: u16,
|
||||||
related_target: Option<@mut EventTarget>
|
related_target: Option<AbstractEventTarget>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MouseEvent {
|
impl MouseEvent {
|
||||||
pub fn new(window: @mut Window, type_: &DOMString, can_bubble: bool, cancelable: bool,
|
pub fn new_inherited() -> MouseEvent {
|
||||||
view: Option<@mut WindowProxy>, detail: i32, screen_x: i32,
|
MouseEvent {
|
||||||
screen_y: i32, client_x: i32, client_y: i32, ctrl_key: bool,
|
parent: UIEvent::new_inherited(MouseEventTypeId),
|
||||||
shift_key: bool, alt_key: bool, meta_key: bool, button: u16,
|
screen_x: 0,
|
||||||
_buttons: u16, related_target: Option<@mut EventTarget>) -> @mut MouseEvent {
|
screen_y: 0,
|
||||||
let ev = @mut MouseEvent {
|
client_x: 0,
|
||||||
parent: UIEvent::new_inherited(type_, can_bubble, cancelable, view, detail),
|
client_y: 0,
|
||||||
screen_x: screen_x,
|
ctrl_key: false,
|
||||||
screen_y: screen_y,
|
shift_key: false,
|
||||||
client_x: client_x,
|
alt_key: false,
|
||||||
client_y: client_y,
|
meta_key: false,
|
||||||
ctrl_key: ctrl_key,
|
button: 0,
|
||||||
shift_key: shift_key,
|
related_target: None
|
||||||
alt_key: alt_key,
|
}
|
||||||
meta_key: meta_key,
|
}
|
||||||
button: button,
|
|
||||||
related_target: related_target
|
pub fn new(window: @mut Window) -> AbstractEvent {
|
||||||
};
|
Event::as_abstract(reflect_dom_object(@mut MouseEvent::new_inherited(),
|
||||||
reflect_dom_object(ev, window, MouseEventBinding::Wrap)
|
window,
|
||||||
|
MouseEventBinding::Wrap))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn Constructor(owner: @mut Window,
|
pub fn Constructor(owner: @mut Window,
|
||||||
type_: &DOMString,
|
type_: &DOMString,
|
||||||
init: &MouseEventBinding::MouseEventInit) -> Fallible<@mut MouseEvent> {
|
init: &MouseEventBinding::MouseEventInit) -> Fallible<AbstractEvent> {
|
||||||
Ok(MouseEvent::new(owner, type_, init.bubbles, init.cancelable, init.view, init.detail,
|
let ev = MouseEvent::new(owner);
|
||||||
init.screenX, init.screenY, init.clientX, init.clientY,
|
ev.mut_mouseevent().InitMouseEvent(type_, init.bubbles, init.cancelable, init.view,
|
||||||
init.ctrlKey, init.shiftKey, init.altKey, init.metaKey,
|
init.detail, init.screenX, init.screenY,
|
||||||
init.button, init.buttons, init.relatedTarget))
|
init.clientX, init.clientY, init.ctrlKey,
|
||||||
|
init.altKey, init.shiftKey, init.metaKey,
|
||||||
|
init.button, init.relatedTarget);
|
||||||
|
Ok(ev)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ScreenX(&self) -> i32 {
|
pub fn ScreenX(&self) -> i32 {
|
||||||
|
@ -98,7 +103,7 @@ impl MouseEvent {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn GetRelatedTarget(&self) -> Option<@mut EventTarget> {
|
pub fn GetRelatedTarget(&self) -> Option<AbstractEventTarget> {
|
||||||
self.related_target
|
self.related_target
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,7 +127,7 @@ impl MouseEvent {
|
||||||
shiftKeyArg: bool,
|
shiftKeyArg: bool,
|
||||||
metaKeyArg: bool,
|
metaKeyArg: bool,
|
||||||
buttonArg: u16,
|
buttonArg: u16,
|
||||||
relatedTargetArg: Option<@mut EventTarget>) -> ErrorResult {
|
relatedTargetArg: Option<AbstractEventTarget>) -> ErrorResult {
|
||||||
self.parent.InitUIEvent(typeArg, canBubbleArg, cancelableArg, viewArg, detailArg);
|
self.parent.InitUIEvent(typeArg, canBubbleArg, cancelableArg, viewArg, detailArg);
|
||||||
self.screen_x = screenXArg;
|
self.screen_x = screenXArg;
|
||||||
self.screen_y = screenYArg;
|
self.screen_y = screenYArg;
|
||||||
|
|
|
@ -12,6 +12,7 @@ use dom::document::{AbstractDocument, DocumentTypeId};
|
||||||
use dom::documenttype::DocumentType;
|
use dom::documenttype::DocumentType;
|
||||||
use dom::element::{Element, ElementTypeId, HTMLImageElementTypeId, HTMLIframeElementTypeId};
|
use dom::element::{Element, ElementTypeId, HTMLImageElementTypeId, HTMLIframeElementTypeId};
|
||||||
use dom::element::{HTMLStyleElementTypeId};
|
use dom::element::{HTMLStyleElementTypeId};
|
||||||
|
use dom::eventtarget::{AbstractEventTarget, EventTarget, NodeTypeId};
|
||||||
use dom::nodelist::{NodeList};
|
use dom::nodelist::{NodeList};
|
||||||
use dom::htmlimageelement::HTMLImageElement;
|
use dom::htmlimageelement::HTMLImageElement;
|
||||||
use dom::htmliframeelement::HTMLIFrameElement;
|
use dom::htmliframeelement::HTMLIFrameElement;
|
||||||
|
@ -63,7 +64,7 @@ pub struct AbstractNodeChildrenIterator<View> {
|
||||||
/// `LayoutData`.
|
/// `LayoutData`.
|
||||||
pub struct Node<View> {
|
pub struct Node<View> {
|
||||||
/// The JavaScript reflector for this node.
|
/// The JavaScript reflector for this node.
|
||||||
reflector_: Reflector,
|
eventtarget: EventTarget,
|
||||||
|
|
||||||
/// The type of node that this is.
|
/// The type of node that this is.
|
||||||
type_id: NodeTypeId,
|
type_id: NodeTypeId,
|
||||||
|
@ -210,6 +211,13 @@ impl<'self, View> AbstractNode<View> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_eventtarget(target: AbstractEventTarget) -> AbstractNode<View> {
|
||||||
|
assert!(target.is_node());
|
||||||
|
unsafe {
|
||||||
|
cast::transmute(target)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Convenience accessors
|
// Convenience accessors
|
||||||
|
|
||||||
/// Returns the type ID of this node. Fails if this node is borrowed mutably.
|
/// Returns the type ID of this node. Fails if this node is borrowed mutably.
|
||||||
|
@ -521,7 +529,7 @@ impl Node<ScriptView> {
|
||||||
|
|
||||||
fn new_(type_id: NodeTypeId, doc: Option<AbstractDocument>) -> Node<ScriptView> {
|
fn new_(type_id: NodeTypeId, doc: Option<AbstractDocument>) -> Node<ScriptView> {
|
||||||
Node {
|
Node {
|
||||||
reflector_: Reflector::new(),
|
eventtarget: EventTarget::new_inherited(NodeTypeId),
|
||||||
type_id: type_id,
|
type_id: type_id,
|
||||||
|
|
||||||
abstract: None,
|
abstract: None,
|
||||||
|
@ -1042,11 +1050,11 @@ impl Node<ScriptView> {
|
||||||
|
|
||||||
impl Reflectable for Node<ScriptView> {
|
impl Reflectable for Node<ScriptView> {
|
||||||
fn reflector<'a>(&'a self) -> &'a Reflector {
|
fn reflector<'a>(&'a self) -> &'a Reflector {
|
||||||
&self.reflector_
|
self.eventtarget.reflector()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mut_reflector<'a>(&'a mut self) -> &'a mut Reflector {
|
fn mut_reflector<'a>(&'a mut self) -> &'a mut Reflector {
|
||||||
&mut self.reflector_
|
self.eventtarget.mut_reflector()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wrap_object_shared(@mut self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
|
fn wrap_object_shared(@mut self, _cx: *JSContext, _scope: *JSObject) -> *JSObject {
|
||||||
|
|
|
@ -6,7 +6,7 @@ use dom::bindings::codegen::UIEventBinding;
|
||||||
use dom::bindings::utils::{DOMString, Fallible};
|
use dom::bindings::utils::{DOMString, Fallible};
|
||||||
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
|
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
|
||||||
use dom::node::{AbstractNode, ScriptView};
|
use dom::node::{AbstractNode, ScriptView};
|
||||||
use dom::event::Event;
|
use dom::event::{AbstractEvent, Event, EventTypeId, UIEventTypeId};
|
||||||
use dom::window::Window;
|
use dom::window::Window;
|
||||||
use dom::windowproxy::WindowProxy;
|
use dom::windowproxy::WindowProxy;
|
||||||
|
|
||||||
|
@ -14,36 +14,33 @@ use js::jsapi::{JSObject, JSContext};
|
||||||
|
|
||||||
pub struct UIEvent {
|
pub struct UIEvent {
|
||||||
parent: Event,
|
parent: Event,
|
||||||
can_bubble: bool,
|
|
||||||
cancelable: bool,
|
|
||||||
view: Option<@mut WindowProxy>,
|
view: Option<@mut WindowProxy>,
|
||||||
detail: i32
|
detail: i32
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UIEvent {
|
impl UIEvent {
|
||||||
pub fn new_inherited(type_: &DOMString, can_bubble: bool, cancelable: bool,
|
pub fn new_inherited(type_id: EventTypeId) -> UIEvent {
|
||||||
view: Option<@mut WindowProxy>, detail: i32) -> UIEvent {
|
|
||||||
UIEvent {
|
UIEvent {
|
||||||
parent: Event::new_inherited(type_),
|
parent: Event::new_inherited(type_id),
|
||||||
can_bubble: can_bubble,
|
view: None,
|
||||||
cancelable: cancelable,
|
detail: 0
|
||||||
view: view,
|
|
||||||
detail: detail
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(window: @mut Window, type_: &DOMString, can_bubble: bool, cancelable: bool,
|
pub fn new(window: @mut Window, type_id: EventTypeId) -> AbstractEvent {
|
||||||
view: Option<@mut WindowProxy>, detail: i32) -> @mut UIEvent {
|
let ev = reflect_dom_object(@mut UIEvent::new_inherited(type_id),
|
||||||
reflect_dom_object(@mut UIEvent::new_inherited(type_, can_bubble, cancelable, view, detail),
|
window,
|
||||||
window,
|
UIEventBinding::Wrap);
|
||||||
UIEventBinding::Wrap)
|
Event::as_abstract(ev)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn Constructor(owner: @mut Window,
|
pub fn Constructor(owner: @mut Window,
|
||||||
type_: &DOMString,
|
type_: &DOMString,
|
||||||
init: &UIEventBinding::UIEventInit) -> Fallible<@mut UIEvent> {
|
init: &UIEventBinding::UIEventInit) -> Fallible<AbstractEvent> {
|
||||||
Ok(UIEvent::new(owner, type_, init.parent.bubbles, init.parent.cancelable,
|
let ev = UIEvent::new(owner, UIEventTypeId);
|
||||||
init.view, init.detail))
|
ev.mut_uievent().InitUIEvent(type_, init.parent.bubbles, init.parent.cancelable,
|
||||||
|
init.view, init.detail);
|
||||||
|
Ok(ev)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn GetView(&self) -> Option<@mut WindowProxy> {
|
pub fn GetView(&self) -> Option<@mut WindowProxy> {
|
||||||
|
@ -61,8 +58,6 @@ impl UIEvent {
|
||||||
view: Option<@mut WindowProxy>,
|
view: Option<@mut WindowProxy>,
|
||||||
detail: i32) {
|
detail: i32) {
|
||||||
self.parent.InitEvent(type_, can_bubble, cancelable);
|
self.parent.InitEvent(type_, can_bubble, cancelable);
|
||||||
self.can_bubble = can_bubble;
|
|
||||||
self.cancelable = cancelable;
|
|
||||||
self.view = view;
|
self.view = view;
|
||||||
self.detail = detail;
|
self.detail = detail;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ use dom::bindings::codegen::WindowBinding;
|
||||||
use dom::bindings::utils::{Reflectable, Reflector};
|
use dom::bindings::utils::{Reflectable, Reflector};
|
||||||
use dom::bindings::utils::{DOMString, null_str_as_empty, Traceable};
|
use dom::bindings::utils::{DOMString, null_str_as_empty, Traceable};
|
||||||
use dom::document::AbstractDocument;
|
use dom::document::AbstractDocument;
|
||||||
|
use dom::eventtarget::{EventTarget, WindowTypeId};
|
||||||
use dom::node::{AbstractNode, ScriptView};
|
use dom::node::{AbstractNode, ScriptView};
|
||||||
use dom::navigator::Navigator;
|
use dom::navigator::Navigator;
|
||||||
|
|
||||||
|
@ -37,10 +38,10 @@ pub enum TimerControlMsg {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
|
eventtarget: EventTarget,
|
||||||
page: @mut Page,
|
page: @mut Page,
|
||||||
script_chan: ScriptChan,
|
script_chan: ScriptChan,
|
||||||
compositor: @ScriptListener,
|
compositor: @ScriptListener,
|
||||||
reflector_: Reflector,
|
|
||||||
timer_chan: SharedChan<TimerControlMsg>,
|
timer_chan: SharedChan<TimerControlMsg>,
|
||||||
navigator: Option<@mut Navigator>,
|
navigator: Option<@mut Navigator>,
|
||||||
image_cache_task: ImageCacheTask,
|
image_cache_task: ImageCacheTask,
|
||||||
|
@ -140,11 +141,11 @@ impl Window {
|
||||||
|
|
||||||
impl Reflectable for Window {
|
impl Reflectable for Window {
|
||||||
fn reflector<'a>(&'a self) -> &'a Reflector {
|
fn reflector<'a>(&'a self) -> &'a Reflector {
|
||||||
&self.reflector_
|
self.eventtarget.reflector()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mut_reflector<'a>(&'a mut self) -> &'a mut Reflector {
|
fn mut_reflector<'a>(&'a mut self) -> &'a mut Reflector {
|
||||||
&mut self.reflector_
|
self.eventtarget.mut_reflector()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wrap_object_shared(@mut self, cx: *JSContext, scope: *JSObject) -> *JSObject {
|
fn wrap_object_shared(@mut self, cx: *JSContext, scope: *JSObject) -> *JSObject {
|
||||||
|
@ -204,10 +205,10 @@ impl Window {
|
||||||
image_cache_task: ImageCacheTask)
|
image_cache_task: ImageCacheTask)
|
||||||
-> @mut Window {
|
-> @mut Window {
|
||||||
let win = @mut Window {
|
let win = @mut Window {
|
||||||
|
eventtarget: EventTarget::new_inherited(WindowTypeId),
|
||||||
page: page,
|
page: page,
|
||||||
script_chan: script_chan.clone(),
|
script_chan: script_chan.clone(),
|
||||||
compositor: compositor,
|
compositor: compositor,
|
||||||
reflector_: Reflector::new(),
|
|
||||||
timer_chan: {
|
timer_chan: {
|
||||||
let (timer_port, timer_chan) = comm::stream::<TimerControlMsg>();
|
let (timer_port, timer_chan) = comm::stream::<TimerControlMsg>();
|
||||||
let id = page.id.clone();
|
let id = page.id.clone();
|
||||||
|
|
|
@ -28,6 +28,7 @@ pub mod dom {
|
||||||
pub mod element;
|
pub mod element;
|
||||||
pub mod node;
|
pub mod node;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
pub mod callback;
|
||||||
pub mod conversions;
|
pub mod conversions;
|
||||||
pub mod proxyhandler;
|
pub mod proxyhandler;
|
||||||
pub mod codegen {
|
pub mod codegen {
|
||||||
|
@ -54,6 +55,7 @@ pub mod dom {
|
||||||
pub mod domparser;
|
pub mod domparser;
|
||||||
pub mod element;
|
pub mod element;
|
||||||
pub mod event;
|
pub mod event;
|
||||||
|
pub mod eventdispatcher;
|
||||||
pub mod eventtarget;
|
pub mod eventtarget;
|
||||||
pub mod formdata;
|
pub mod formdata;
|
||||||
pub mod htmlanchorelement;
|
pub mod htmlanchorelement;
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 1df26877d82d9722785de91ff59ab069a5acc180
|
Subproject commit 566c2af971abaa5e8c51b59fa400a7e07835b257
|
|
@ -4,7 +4,7 @@
|
||||||
<script>
|
<script>
|
||||||
is_function(Event, "Event");
|
is_function(Event, "Event");
|
||||||
|
|
||||||
let ev = new Event("foopy");
|
let ev = new Event("foopy", {cancelable: true});
|
||||||
is_a(ev, Event);
|
is_a(ev, Event);
|
||||||
|
|
||||||
is(ev.type, 'foopy');
|
is(ev.type, 'foopy');
|
||||||
|
|
51
src/test/html/content/test_event_dispatch.html
Normal file
51
src/test/html/content/test_event_dispatch.html
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<script src="harness.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<span>Paragraph containing <div>event listener</div>.</span>
|
||||||
|
<script>
|
||||||
|
var bodyTimes = 0;
|
||||||
|
function bodyListener(ev) {
|
||||||
|
bodyTimes++;
|
||||||
|
is(ev.currentTarget, document.getElementsByTagName('body')[0]);
|
||||||
|
is(ev.target, document.getElementsByTagName('div')[0]);
|
||||||
|
if (bodyTimes == 1) {
|
||||||
|
is(ev.eventPhase, ev.CAPTURING_PHASE);
|
||||||
|
} else if (bodyTimes == 2) {
|
||||||
|
is(ev.eventPhase, ev.BUBBLING_PHASE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var spanTimes = 0;
|
||||||
|
function spanListener(ev) {
|
||||||
|
is(ev.currentTarget, document.getElementsByTagName('span')[0]);
|
||||||
|
is(ev.target, document.getElementsByTagName('div')[0]);
|
||||||
|
is(ev.eventPhase, ev.BUBBLING_PHASE);
|
||||||
|
spanTimes++;
|
||||||
|
}
|
||||||
|
|
||||||
|
var divTimes = 0;
|
||||||
|
function divListener(ev) {
|
||||||
|
var self = document.getElementsByTagName('div')[0];
|
||||||
|
is(ev.currentTarget, self);
|
||||||
|
is(ev.target, self);
|
||||||
|
is(ev.eventPhase, ev.AT_TARGET);
|
||||||
|
divTimes++;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementsByTagName('body')[0].addEventListener("foopy", bodyListener, true);
|
||||||
|
document.getElementsByTagName('body')[0].addEventListener("foopy", bodyListener, false);
|
||||||
|
document.getElementsByTagName('span')[0].addEventListener("foopy", spanListener, false);
|
||||||
|
document.getElementsByTagName('div')[0].addEventListener("foopy", divListener, false);
|
||||||
|
var ev = new Event('foopy', {bubbles: true});
|
||||||
|
is(ev.bubbles, true);
|
||||||
|
document.getElementsByTagName('div')[0].dispatchEvent(ev);
|
||||||
|
is(bodyTimes, 2, 'body listener should be called multiple times');
|
||||||
|
is(divTimes, 1, 'target listener should be called once');
|
||||||
|
is(spanTimes, 1, 'span listener should be called while bubbling');
|
||||||
|
|
||||||
|
finish();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
21
src/test/html/content/test_event_dispatch_dynamic.html
Normal file
21
src/test/html/content/test_event_dispatch_dynamic.html
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<script src="harness.js"></script>
|
||||||
|
<b><b><b></b></b></b>
|
||||||
|
<script>
|
||||||
|
var sawmiddle = -1;
|
||||||
|
var sawouter = -1;
|
||||||
|
var step = 0;
|
||||||
|
var outerb = document.getElementsByTagName('b')[0];
|
||||||
|
var middleb = outerb.firstChild;
|
||||||
|
var innerb = middleb.firstChild;
|
||||||
|
outerb.addEventListener("x", function() {
|
||||||
|
middleb.addEventListener("x", function() {
|
||||||
|
sawmiddle = step++;
|
||||||
|
}, true);
|
||||||
|
sawouter = step++;
|
||||||
|
}, true);
|
||||||
|
innerb.dispatchEvent(new Event("x"));
|
||||||
|
is(sawmiddle, 1);
|
||||||
|
is(sawouter, 0);
|
||||||
|
finish();
|
||||||
|
</script>
|
42
src/test/html/content/test_event_dispatch_order.html
Normal file
42
src/test/html/content/test_event_dispatch_order.html
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<script src="harness.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="foo"></div>
|
||||||
|
<script>
|
||||||
|
var sawBubble = false;
|
||||||
|
var sawCapture = false;
|
||||||
|
var sawBubbleTwice = false;
|
||||||
|
function handler(ev) {
|
||||||
|
is(ev.eventPhase, ev.AT_TARGET);
|
||||||
|
is(sawBubble, false);
|
||||||
|
is(sawCapture, false);
|
||||||
|
sawBubble = true;
|
||||||
|
}
|
||||||
|
function handler2(ev) {
|
||||||
|
is(ev.eventPhase, ev.AT_TARGET);
|
||||||
|
is(sawBubble, true);
|
||||||
|
is(sawCapture, false);
|
||||||
|
sawCapture = true;
|
||||||
|
}
|
||||||
|
function handler3(ev) {
|
||||||
|
is(ev.eventPhase, ev.AT_TARGET);
|
||||||
|
is(sawBubble, true);
|
||||||
|
is(sawCapture, true);
|
||||||
|
sawBubbleTwice = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var target = document.getElementById('foo');
|
||||||
|
target.addEventListener('foopy', handler, false);
|
||||||
|
target.addEventListener('foopy', handler2, true);
|
||||||
|
target.addEventListener('foopy', handler3, false);
|
||||||
|
var ev = new Event('foopy', {bubbles: true});
|
||||||
|
target.dispatchEvent(ev);
|
||||||
|
is(sawBubble, true);
|
||||||
|
is(sawCapture, true);
|
||||||
|
is(sawBubbleTwice, true);
|
||||||
|
finish();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
39
src/test/html/content/test_event_listener.html
Normal file
39
src/test/html/content/test_event_listener.html
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<script src="harness.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script>
|
||||||
|
function onFoopy(ev) {
|
||||||
|
window.removeEventListener('foopy', onFoopy);
|
||||||
|
is(ev instanceof expected, true);
|
||||||
|
is(ev.type, 'foopy');
|
||||||
|
}
|
||||||
|
|
||||||
|
var expected;
|
||||||
|
var events = [['HTMLEvents', Event, function(ev) { ev.initEvent('foopy', true, true); }],
|
||||||
|
['UIEvents', UIEvent, function(ev) { ev.initUIEvent('foopy', true, true, null, 0); }],
|
||||||
|
['MouseEvents', MouseEvent,
|
||||||
|
function(ev) { ev.initMouseEvent('foopy', true, true, null, 0,
|
||||||
|
0, 0, 0, 0, false, false,
|
||||||
|
false, false, 0, null); }]];
|
||||||
|
for (var i = 0; i < events.length; i++) {
|
||||||
|
addEventListener('foopy', onFoopy);
|
||||||
|
expected = events[i][1];
|
||||||
|
var ev = document.createEvent(events[i][0]);
|
||||||
|
events[i][2](ev);
|
||||||
|
window.dispatchEvent(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
var constructors = [Event, UIEvent, MouseEvent];
|
||||||
|
for (var i = 0; i < constructors.length; i++) {
|
||||||
|
addEventListener('foopy', onFoopy);
|
||||||
|
expected = constructors[i];
|
||||||
|
var ev = new constructors[i]('foopy', {cancelable: true, bubbles: true});
|
||||||
|
window.dispatchEvent(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
finish();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Add table
Add a link
Reference in a new issue