prototype: Merge -r7242:HEAD from ../branches/1-6-0-events. Adds support for DOM-based custom events with Event.fire/Element.Methods.fire, cross-browser DOMContentLoaded support, extended and normalized event objects, and improvements to the observe and stopObserving APIs.
This commit is contained in:
parent
52cf3f2550
commit
aa4602b459
14
CHANGELOG
14
CHANGELOG
@ -1,5 +1,19 @@
|
||||
*SVN*
|
||||
|
||||
* Make the eventName and handler arguments to Event.stopObserving optional. If no handler is specified, all handlers for the given event are unregistered. If no event name is specified, all observed events on the element are unregistered. [sam]
|
||||
|
||||
* Add cross-support for the DOMContentLoaded event through a Prototype custom event on document called "contentloaded". The DOMContentLoaded event fires before window.load, when the entire HTML document, but not necessarily its images, stylesheets or other assets, has loaded. Based on [6596]. [sam, Mislav Marohnić]
|
||||
Example:
|
||||
document.observe("contentloaded", function() {
|
||||
$$("a").invoke("identify"); // give all <a> tags an ID
|
||||
});
|
||||
|
||||
* Add Event.fire and Element.Methods.fire for firing custom events. Prototype custom events piggyback on a real DOM event ("ondataavailable"), so they bubble and cancel. You can fire custom events from any element, or fire global events on the document object. Observe custom events just as you'd observe a regular DOM event. [sam, Seth Dillingham]
|
||||
|
||||
* Extend the event object with methods from Event.Methods and normalize it in IE. [sam, Mislav Marohnić]
|
||||
|
||||
* Remove support for observing the capturing phase of DOM events, since we can't support it in all browsers. [sam]
|
||||
|
||||
* Add Ajax.Response object which supports the following methods: responseJSON, headerJSON, getHeader, getAllHeaders and handles browser discrepancies in the other response methods. Add sanitizeJSON, evalJS and evalJSON to Ajax.Request. Closes #8122, #8006, #7295. [Tobie Langel]
|
||||
|
||||
* Add an isRunningFromRake property to unit tests. [Tobie Langel]
|
||||
|
58
src/dom.js
58
src/dom.js
@ -22,10 +22,28 @@ if (Prototype.BrowserFeatures.XPath) {
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
if (!window.Node)
|
||||
var Node = { };
|
||||
|
||||
Object.extend(Node, {
|
||||
ELEMENT_NODE: 1,
|
||||
ATTRIBUTE_NODE: 2,
|
||||
TEXT_NODE: 3,
|
||||
CDATA_SECTION_NODE: 4,
|
||||
ENTITY_REFERENCE_NODE: 5,
|
||||
ENTITY_NODE: 6,
|
||||
PROCESSING_INSTRUCTION_NODE: 7,
|
||||
COMMENT_NODE: 8,
|
||||
DOCUMENT_NODE: 9,
|
||||
DOCUMENT_TYPE_NODE: 10,
|
||||
DOCUMENT_FRAGMENT_NODE: 11,
|
||||
NOTATION_NODE: 12
|
||||
});
|
||||
|
||||
(function() {
|
||||
var element = this.Element;
|
||||
this.Element = function(tagName, attributes) {
|
||||
attributes = attributes || {};
|
||||
attributes = attributes || { };
|
||||
tagName = tagName.toLowerCase();
|
||||
var cache = Element.cache;
|
||||
if (Prototype.Browser.IE && attributes.name) {
|
||||
@ -36,10 +54,10 @@ if (Prototype.BrowserFeatures.XPath) {
|
||||
if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName));
|
||||
return Element.writeAttribute(cache[tagName].cloneNode(false), attributes);
|
||||
};
|
||||
Object.extend(this.Element, element || {});
|
||||
Object.extend(this.Element, element || { });
|
||||
}).call(window);
|
||||
|
||||
Element.cache = {};
|
||||
Element.cache = { };
|
||||
|
||||
Element.Methods = {
|
||||
visible: function(element) {
|
||||
@ -127,7 +145,7 @@ Element.Methods = {
|
||||
wrap: function(element, wrapper, attributes) {
|
||||
element = $(element);
|
||||
if (Object.isElement(wrapper))
|
||||
$(wrapper).writeAttribute(attributes || {});
|
||||
$(wrapper).writeAttribute(attributes || { });
|
||||
else if (typeof wrapper == 'string') wrapper = new Element(wrapper, attributes);
|
||||
else wrapper = new Element('div', wrapper);
|
||||
if (element.parentNode)
|
||||
@ -259,7 +277,7 @@ Element.Methods = {
|
||||
|
||||
writeAttribute: function(element, name, value) {
|
||||
element = $(element);
|
||||
var attributes = {}, t = Element._attributeTranslations.write;
|
||||
var attributes = { }, t = Element._attributeTranslations.write;
|
||||
|
||||
if (typeof name == 'object') attributes = name;
|
||||
else attributes[name] = value === undefined ? true : value;
|
||||
@ -315,16 +333,6 @@ Element.Methods = {
|
||||
'removeClassName' : 'addClassName'](className);
|
||||
},
|
||||
|
||||
observe: function() {
|
||||
Event.observe.apply(Event, arguments);
|
||||
return $A(arguments).first();
|
||||
},
|
||||
|
||||
stopObserving: function() {
|
||||
Event.stopObserving.apply(Event, arguments);
|
||||
return $A(arguments).first();
|
||||
},
|
||||
|
||||
// removes whitespace-only text node children
|
||||
cleanWhitespace: function(element) {
|
||||
element = $(element);
|
||||
@ -585,7 +593,7 @@ Element.Methods = {
|
||||
setHeight: true,
|
||||
offsetTop: 0,
|
||||
offsetLeft: 0
|
||||
}, arguments[2] || {});
|
||||
}, arguments[2] || { });
|
||||
|
||||
// find page position of source
|
||||
source = $(source);
|
||||
@ -663,7 +671,7 @@ Element._attributeTranslations = {
|
||||
className: 'class',
|
||||
htmlFor: 'for'
|
||||
},
|
||||
values: {}
|
||||
values: { }
|
||||
}
|
||||
};
|
||||
|
||||
@ -868,7 +876,7 @@ else if (Prototype.Browser.WebKit) {
|
||||
var n = document.createTextNode(' ');
|
||||
element.appendChild(n);
|
||||
element.removeChild(n);
|
||||
} catch (e) {}
|
||||
} catch (e) { }
|
||||
|
||||
return element;
|
||||
}
|
||||
@ -1019,13 +1027,13 @@ Element.Methods.Simulated = {
|
||||
}
|
||||
};
|
||||
|
||||
Element.Methods.ByTag = {};
|
||||
Element.Methods.ByTag = { };
|
||||
|
||||
Object.extend(Element, Element.Methods);
|
||||
|
||||
if (!Prototype.BrowserFeatures.ElementExtensions &&
|
||||
document.createElement('div').__proto__) {
|
||||
window.HTMLElement = {};
|
||||
window.HTMLElement = { };
|
||||
window.HTMLElement.prototype = document.createElement('div').__proto__;
|
||||
Prototype.BrowserFeatures.ElementExtensions = true;
|
||||
}
|
||||
@ -1034,7 +1042,7 @@ Element.extend = (function() {
|
||||
if (Prototype.BrowserFeatures.SpecificElementExtensions)
|
||||
return Prototype.K;
|
||||
|
||||
var Methods = {}, ByTag = Element.Methods.ByTag;
|
||||
var Methods = { }, ByTag = Element.Methods.ByTag;
|
||||
|
||||
var extend = Object.extend(function(element) {
|
||||
if (!element || element._extendedByPrototype ||
|
||||
@ -1093,7 +1101,7 @@ Element.addMethods = function(methods) {
|
||||
methods = arguments[1];
|
||||
}
|
||||
|
||||
if (!tagName) Object.extend(Element.Methods, methods || {});
|
||||
if (!tagName) Object.extend(Element.Methods, methods || { });
|
||||
else {
|
||||
if (Object.isArray(tagName)) tagName.each(extend);
|
||||
else extend(tagName);
|
||||
@ -1102,7 +1110,7 @@ Element.addMethods = function(methods) {
|
||||
function extend(tagName) {
|
||||
tagName = tagName.toUpperCase();
|
||||
if (!Element.Methods.ByTag[tagName])
|
||||
Element.Methods.ByTag[tagName] = {};
|
||||
Element.Methods.ByTag[tagName] = { };
|
||||
Object.extend(Element.Methods.ByTag[tagName], methods);
|
||||
}
|
||||
|
||||
@ -1136,7 +1144,7 @@ Element.addMethods = function(methods) {
|
||||
klass = 'HTML' + tagName.capitalize() + 'Element';
|
||||
if (window[klass]) return window[klass];
|
||||
|
||||
window[klass] = {};
|
||||
window[klass] = { };
|
||||
window[klass].prototype = document.createElement(tagName).__proto__;
|
||||
return window[klass];
|
||||
}
|
||||
@ -1158,5 +1166,5 @@ Element.addMethods = function(methods) {
|
||||
delete Element.ByTag;
|
||||
|
||||
if (Element.extend.refresh) Element.extend.refresh();
|
||||
Element.cache = {};
|
||||
Element.cache = { };
|
||||
};
|
||||
|
336
src/event.js
336
src/event.js
@ -1,6 +1,4 @@
|
||||
if (!window.Event) {
|
||||
var Event = new Object();
|
||||
}
|
||||
if (!window.Event) var Event = { };
|
||||
|
||||
Object.extend(Event, {
|
||||
KEY_BACKSPACE: 8,
|
||||
@ -16,34 +14,32 @@ Object.extend(Event, {
|
||||
KEY_END: 35,
|
||||
KEY_PAGEUP: 33,
|
||||
KEY_PAGEDOWN: 34,
|
||||
KEY_INSERT: 45,
|
||||
|
||||
DOMEvents: ['click', 'dblclick', 'mousedown', 'mouseup', 'mouseover',
|
||||
'mousemove', 'mouseout', 'keypress', 'keydown', 'keyup',
|
||||
'load', 'unload', 'abort', 'error', 'resize', 'scroll',
|
||||
'select', 'change', 'submit', 'reset', 'focus', 'blur',
|
||||
'DOMFocusIn', 'DOMFocusOut', 'DOMActivate',
|
||||
'DOMSubtreeModified', 'DOMNodeInserted',
|
||||
'NodeInsertedIntoDocument', 'DOMAttrModified',
|
||||
'DOMCharacterDataModified'],
|
||||
|
||||
element: function(event) {
|
||||
return $(event.target || event.srcElement);
|
||||
},
|
||||
|
||||
isLeftClick: function(event) {
|
||||
return (((event.which) && (event.which == 1)) ||
|
||||
((event.button) && (event.button == 1)));
|
||||
},
|
||||
|
||||
pointerX: function(event) {
|
||||
return event.pageX || (event.clientX +
|
||||
(document.documentElement.scrollLeft || document.body.scrollLeft));
|
||||
},
|
||||
|
||||
pointerY: function(event) {
|
||||
return event.pageY || (event.clientY +
|
||||
(document.documentElement.scrollTop || document.body.scrollTop));
|
||||
},
|
||||
|
||||
stop: function(event) {
|
||||
if (event.preventDefault) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
} else {
|
||||
event.returnValue = false;
|
||||
event.cancelBubble = true;
|
||||
relatedTarget: function(event) {
|
||||
var element;
|
||||
switch(event.type) {
|
||||
case 'mouseover': element = event.fromElement; break;
|
||||
case 'mouseout': element = event.toElement; break;
|
||||
default: return null;
|
||||
}
|
||||
return Element.extend(element);
|
||||
}
|
||||
});
|
||||
|
||||
Event.Methods = {
|
||||
element: function(event) {
|
||||
var node = event.target;
|
||||
return Element.extend(node.nodeType == Node.TEXT_NODE ? node.parentNode : node);
|
||||
},
|
||||
|
||||
findElement: function(event, expression) {
|
||||
@ -51,57 +47,251 @@ Object.extend(Event, {
|
||||
return element.match(expression) ? element : element.up(expression);
|
||||
},
|
||||
|
||||
observers: false,
|
||||
|
||||
_observeAndCache: function(element, name, observer, useCapture) {
|
||||
if (!this.observers) this.observers = [];
|
||||
if (element.addEventListener) {
|
||||
this.observers.push([element, name, observer, useCapture]);
|
||||
element.addEventListener(name, observer, useCapture);
|
||||
} else if (element.attachEvent) {
|
||||
this.observers.push([element, name, observer, useCapture]);
|
||||
element.attachEvent('on' + name, observer);
|
||||
}
|
||||
},
|
||||
|
||||
unloadCache: function() {
|
||||
if (!Event.observers) return;
|
||||
for (var i = 0, length = Event.observers.length; i < length; i++) {
|
||||
Event.stopObserving.apply(this, Event.observers[i]);
|
||||
Event.observers[i][0] = null;
|
||||
}
|
||||
Event.observers = false;
|
||||
isLeftClick: function(event) {
|
||||
return (((event.which) && (event.which == 1)) ||
|
||||
((event.button) && (event.button == 1)));
|
||||
},
|
||||
|
||||
observe: function(element, name, observer, useCapture) {
|
||||
element = $(element);
|
||||
useCapture = useCapture || false;
|
||||
|
||||
if (name == 'keypress' &&
|
||||
(Prototype.Browser.WebKit || element.attachEvent))
|
||||
name = 'keydown';
|
||||
|
||||
Event._observeAndCache(element, name, observer, useCapture);
|
||||
pointer: function(event) {
|
||||
return {
|
||||
x: event.pageX || (event.clientX +
|
||||
(document.documentElement.scrollLeft || document.body.scrollLeft)),
|
||||
y: event.pageY || (event.clientY +
|
||||
(document.documentElement.scrollTop || document.body.scrollTop))
|
||||
};
|
||||
},
|
||||
|
||||
stopObserving: function(element, name, observer, useCapture) {
|
||||
element = $(element);
|
||||
useCapture = useCapture || false;
|
||||
pointerX: function(event) { return Event.pointer(event).x },
|
||||
pointerY: function(event) { return Event.pointer(event).y },
|
||||
|
||||
stop: function(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
};
|
||||
|
||||
Event.extend = (function() {
|
||||
var methods = Object.keys(Event.Methods).inject({ }, function(m, name) {
|
||||
m[name] = Event.Methods[name].methodize();
|
||||
return m;
|
||||
});
|
||||
|
||||
if (Prototype.Browser.IE) {
|
||||
Object.extend(methods, {
|
||||
stopPropagation: function() { this.cancelBubble = true },
|
||||
preventDefault: function() { this.returnValue = false },
|
||||
inspect: function() { return "[object Event]" }
|
||||
});
|
||||
|
||||
return function(event) {
|
||||
if (!event) return false;
|
||||
if (event._extendedByPrototype) return event;
|
||||
|
||||
event._extendedByPrototype = Prototype.emptyFunction;
|
||||
var pointer = Event.pointer(event);
|
||||
Object.extend(event, {
|
||||
target: event.srcElement,
|
||||
relatedTarget: Event.relatedTarget(event),
|
||||
pageX: pointer.x,
|
||||
pageY: pointer.y
|
||||
});
|
||||
return Object.extend(event, methods);
|
||||
};
|
||||
|
||||
if (name == 'keypress' &&
|
||||
(Prototype.Browser.WebKit || element.attachEvent))
|
||||
name = 'keydown';
|
||||
} else {
|
||||
Event.prototype = Event.prototype || document.createEvent("Events").__proto__;
|
||||
Object.extend(Event.prototype, methods);
|
||||
return Prototype.K;
|
||||
}
|
||||
})();
|
||||
|
||||
Object.extend(Event, (function() {
|
||||
var cache = { };
|
||||
|
||||
function getEventID(element) {
|
||||
if (element._eventID) return element._eventID;
|
||||
arguments.callee.id = arguments.callee.id || 1;
|
||||
return element._eventID = ++arguments.callee.id;
|
||||
}
|
||||
|
||||
function getDOMEventName(eventName) {
|
||||
if (!Event.DOMEvents.include(eventName)) return "dataavailable";
|
||||
return { keypress: "keydown" }[eventName] || eventName;
|
||||
}
|
||||
|
||||
function getCacheForID(id) {
|
||||
return cache[id] = cache[id] || { };
|
||||
}
|
||||
|
||||
function getWrappersForEventName(id, eventName) {
|
||||
var c = getCacheForID(id);
|
||||
return c[eventName] = c[eventName] || [];
|
||||
}
|
||||
|
||||
function createWrapper(id, eventName, handler) {
|
||||
var c = getWrappersForEventName(id, eventName);
|
||||
if (c.pluck("handler").include(handler)) return false;
|
||||
|
||||
if (element.removeEventListener) {
|
||||
element.removeEventListener(name, observer, useCapture);
|
||||
} else if (element.detachEvent) {
|
||||
try {
|
||||
element.detachEvent('on' + name, observer);
|
||||
} catch (e) {}
|
||||
var wrapper = function(event) {
|
||||
if (event.eventName && event.eventName != eventName)
|
||||
return false;
|
||||
|
||||
Event.extend(event);
|
||||
handler.call(event.target, event);
|
||||
};
|
||||
|
||||
wrapper.handler = handler;
|
||||
c.push(wrapper);
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
function findWrapper(id, eventName, handler) {
|
||||
var c = getWrappersForEventName(id, eventName);
|
||||
return c.find(function(wrapper) { return wrapper.handler == handler });
|
||||
}
|
||||
|
||||
function destroyWrapper(id, eventName, handler) {
|
||||
var c = getCacheForID(id), name = getDOMEventName(eventName);
|
||||
if (!c[name]) return false;
|
||||
c[name] = c[name].without(findWrapper(id, eventName, handler));
|
||||
}
|
||||
|
||||
function destroyCache() {
|
||||
for (var id in cache)
|
||||
for (var eventName in cache[id])
|
||||
cache[id][eventName] = null;
|
||||
}
|
||||
|
||||
if (window.attachEvent) {
|
||||
window.attachEvent("onunload", destroyCache);
|
||||
}
|
||||
|
||||
return {
|
||||
observe: function(element, eventName, handler) {
|
||||
element = $(element);
|
||||
var id = getEventID(element), name = getDOMEventName(eventName);
|
||||
|
||||
var wrapper = createWrapper(id, eventName, handler);
|
||||
if (!wrapper) return false;
|
||||
|
||||
if (element.addEventListener) {
|
||||
element.addEventListener(name, wrapper, false);
|
||||
} else {
|
||||
element.attachEvent("on" + name, wrapper);
|
||||
}
|
||||
},
|
||||
|
||||
stopObserving: function(element, eventName, handler) {
|
||||
element = $(element);
|
||||
var id = getEventID(element), name = getDOMEventName(eventName);
|
||||
|
||||
if (!handler && eventName) {
|
||||
return getWrappersForEventName(id, eventName).each(function(wrapper) {
|
||||
element.stopObserving(eventName, wrapper.handler);
|
||||
}) && false;
|
||||
|
||||
} else if (!eventName) {
|
||||
return Object.keys(getCacheForID(id)).each(function(eventName) {
|
||||
element.stopObserving(eventName);
|
||||
}) && false;
|
||||
}
|
||||
|
||||
var wrapper = findWrapper(id, eventName, handler);
|
||||
if (!wrapper) return false;
|
||||
|
||||
if (element.removeEventListener) {
|
||||
element.removeEventListener(name, wrapper, false);
|
||||
} else {
|
||||
element.detachEvent("on" + name, wrapper);
|
||||
}
|
||||
},
|
||||
|
||||
fire: function(element, eventName, memo) {
|
||||
element = $(element);
|
||||
if (element == document && document.createEvent && !element.dispatchEvent)
|
||||
element = document.documentElement;
|
||||
|
||||
if (document.createEvent) {
|
||||
var event = document.createEvent("Events");
|
||||
event.initEvent("dataavailable", true, true);
|
||||
} else {
|
||||
var event = document.createEventObject();
|
||||
event.eventType = "ondataavailable";
|
||||
}
|
||||
|
||||
event.eventName = eventName;
|
||||
event.memo = memo || {};
|
||||
|
||||
if (document.createEvent) {
|
||||
element.dispatchEvent(event);
|
||||
} else {
|
||||
element.fireEvent(event.eventType, event);
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
};
|
||||
})());
|
||||
|
||||
Object.extend(Event, Event.Methods);
|
||||
|
||||
Element.addMethods({
|
||||
fire: function() {
|
||||
Event.fire.apply(Event, arguments);
|
||||
return $A(arguments).first();
|
||||
},
|
||||
|
||||
observe: function() {
|
||||
Event.observe.apply(Event, arguments);
|
||||
return $A(arguments).first();
|
||||
},
|
||||
|
||||
stopObserving: function() {
|
||||
Event.stopObserving.apply(Event, arguments);
|
||||
return $A(arguments).first();
|
||||
}
|
||||
});
|
||||
|
||||
/* prevent memory leaks in IE */
|
||||
if (Prototype.Browser.IE)
|
||||
Event.observe(window, 'unload', Event.unloadCache, false);
|
||||
Object.extend(document, {
|
||||
fire: Element.Methods.fire.methodize(),
|
||||
observe: Element.Methods.observe.methodize(),
|
||||
stopObserving: Element.Methods.stopObserving.methodize()
|
||||
});
|
||||
|
||||
(function() {
|
||||
/* Support for the DOMContentLoaded event is based on work by Dan Webb,
|
||||
Matthias Miller, Dean Edwards and John Resig. */
|
||||
|
||||
var timer, fired = false;
|
||||
|
||||
function fireContentLoadedEvent() {
|
||||
if (fired) return;
|
||||
if (timer) window.clearInterval(timer);
|
||||
document.fire("contentloaded");
|
||||
fired = true;
|
||||
}
|
||||
|
||||
if (document.addEventListener) {
|
||||
if (Prototype.Browser.WebKit) {
|
||||
timer = window.setInterval(function() {
|
||||
if (/loaded|complete/.test(document.readyState))
|
||||
fireContentLoadedEvent();
|
||||
}, 0);
|
||||
|
||||
Event.observe(window, "load", fireContentLoadedEvent);
|
||||
|
||||
} else {
|
||||
document.addEventListener("DOMContentLoaded", fireContentLoadedEvent, false);
|
||||
}
|
||||
|
||||
} else {
|
||||
var dummy = location.protocol == "https:" ? "https://javascript:void(0)" : "javascript:void(0)";
|
||||
document.write("<script id=__onDOMContentLoaded defer src='" + dummy + "'><\/script>");
|
||||
$("__onDOMContentLoaded").onreadystatechange = function() {
|
||||
if (this.readyState == "complete") {
|
||||
this.onreadystatechange = null;
|
||||
fireContentLoadedEvent();
|
||||
}
|
||||
};
|
||||
}
|
||||
})();
|
||||
|
@ -165,7 +165,9 @@ Test.Unit.Runner.prototype = {
|
||||
}
|
||||
this.currentTest = 0;
|
||||
this.logger = new Test.Unit.Logger(this.options.testLog);
|
||||
setTimeout(this.runTests.bind(this), 1000);
|
||||
Event.observe(window, "load", function() {
|
||||
setTimeout(this.runTests.bind(this), 100);
|
||||
}.bind(this));
|
||||
},
|
||||
parseResultsURLQueryParameter: function() {
|
||||
return window.location.search.parseQuery()["resultsURL"];
|
||||
|
201
test/unit/event.html
Normal file
201
test/unit/event.html
Normal file
@ -0,0 +1,201 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<title>Prototype Unit test file</title>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||
<script src="../../dist/prototype.js" type="text/javascript"></script>
|
||||
<script src="../lib/unittest.js" type="text/javascript"></script>
|
||||
<link rel="stylesheet" href="../test.css" type="text/css" />
|
||||
<style type="text/css" media="screen">
|
||||
/* <![CDATA[ */
|
||||
#testcss1 { font-size:11px; color: #f00; }
|
||||
#testcss2 { font-size:12px; color: #0f0; display: none; }
|
||||
/* ]]> */
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Prototype Unit test file</h1>
|
||||
<p>
|
||||
Test of event handling code in event.js
|
||||
</p>
|
||||
|
||||
<!-- Log output -->
|
||||
<div id="testlog"> </div>
|
||||
|
||||
<div id="outer" style="display: none">
|
||||
<p id="inner">One two three <span id="span">four</span></p>
|
||||
</div>
|
||||
|
||||
<!-- Tests follow -->
|
||||
<script type="text/javascript" language="javascript" charset="utf-8">
|
||||
// <![CDATA[
|
||||
|
||||
var eventResults = { };
|
||||
|
||||
new Test.Unit.Runner({
|
||||
|
||||
// test firing an event and observing it on the element it's fired from
|
||||
testCustomEventFiring: function() { with(this) {
|
||||
var span = $("span"), fired = false, observer = function(event) {
|
||||
assertEqual(span, event.element());
|
||||
assertEqual(1, event.memo.index);
|
||||
fired = true;
|
||||
}
|
||||
|
||||
span.observe("somethingHappened", observer);
|
||||
span.fire("somethingHappened", { index: 1 });
|
||||
assert(fired);
|
||||
|
||||
fired = false;
|
||||
span.fire("somethingElseHappened");
|
||||
assert(!fired);
|
||||
|
||||
span.stopObserving("somethingHappened", observer);
|
||||
span.fire("somethingHappened");
|
||||
assert(!fired);
|
||||
}},
|
||||
|
||||
// test firing an event and observing it on a containing element
|
||||
testCustomEventBubbling: function() { with(this) {
|
||||
var span = $("span"), outer = $("outer"), fired = false, observer = function(event) {
|
||||
assertEqual(span, event.element());
|
||||
fired = true;
|
||||
};
|
||||
|
||||
outer.observe("somethingHappened", observer);
|
||||
span.fire("somethingHappened");
|
||||
assert(fired);
|
||||
|
||||
fired = false;
|
||||
span.fire("somethingElseHappened");
|
||||
assert(!fired);
|
||||
|
||||
outer.stopObserving("somethingHappened", observer);
|
||||
span.fire("somethingHappened");
|
||||
assert(!fired);
|
||||
}},
|
||||
|
||||
testCustomEventCanceling: function() { with(this) {
|
||||
var span = $("span"), outer = $("outer"), inner = $("inner");
|
||||
var fired = false, stopped = false;
|
||||
|
||||
function outerObserver(event) {
|
||||
fired = span == event.element();
|
||||
}
|
||||
|
||||
function innerObserver(event) {
|
||||
event.stop();
|
||||
stopped = true;
|
||||
}
|
||||
|
||||
inner.observe("somethingHappened", innerObserver);
|
||||
outer.observe("somethingHappened", outerObserver);
|
||||
span.fire("somethingHappened");
|
||||
assert(stopped);
|
||||
assert(!fired);
|
||||
|
||||
fired = stopped = false;
|
||||
inner.stopObserving("somethingHappened", innerObserver);
|
||||
span.fire("somethingHappened");
|
||||
assert(!stopped);
|
||||
assert(fired);
|
||||
|
||||
outer.stopObserving("somethingHappened", outerObserver);
|
||||
}},
|
||||
|
||||
testEventObjectIsExtended: function() { with(this) {
|
||||
var span = $("span"), event, observer = function(e) { event = e };
|
||||
span.observe("somethingHappened", observer);
|
||||
span.fire("somethingHappened");
|
||||
assertEqual(Event.Methods.stop.methodize(), event.stop);
|
||||
span.stopObserving("somethingHappened", observer);
|
||||
}},
|
||||
|
||||
testEventObserversAreBoundToTheTargetElement: function() { with(this) {
|
||||
var span = $("span"), target, observer = function() { target = this };
|
||||
|
||||
span.observe("somethingHappened", observer);
|
||||
span.fire("somethingHappened");
|
||||
span.stopObserving("somethingHappened", observer);
|
||||
assertEqual(span, target);
|
||||
target = null;
|
||||
|
||||
var outer = $("outer");
|
||||
outer.observe("somethingHappened", observer);
|
||||
span.fire("somethingHappened");
|
||||
outer.stopObserving("somethingHappened", observer);
|
||||
assertEqual(span, target);
|
||||
}},
|
||||
|
||||
testMultipleCustomEventObserversWithTheSameHandler: function() { with(this) {
|
||||
var span = $("span"), count = 0, observer = function() { count++ };
|
||||
|
||||
span.observe("somethingHappened", observer);
|
||||
span.observe("somethingElseHappened", observer);
|
||||
span.fire("somethingHappened");
|
||||
assertEqual(1, count);
|
||||
span.fire("somethingElseHappened");
|
||||
assertEqual(2, count);
|
||||
}},
|
||||
|
||||
testStopObservingWithoutArguments: function() { with(this) {
|
||||
var span = $("span"), count = 0, observer = function() { count++ };
|
||||
|
||||
span.observe("somethingHappened", observer);
|
||||
span.observe("somethingElseHappened", observer);
|
||||
span.stopObserving();
|
||||
span.fire("somethingHappened");
|
||||
assertEqual(0, count);
|
||||
span.fire("somethingElseHappened");
|
||||
assertEqual(0, count);
|
||||
}},
|
||||
|
||||
testStopObservingWithoutHandlerArgument: function() { with(this) {
|
||||
var span = $("span"), count = 0, observer = function() { count++ };
|
||||
|
||||
span.observe("somethingHappened", observer);
|
||||
span.observe("somethingElseHappened", observer);
|
||||
span.stopObserving("somethingHappened");
|
||||
span.fire("somethingHappened");
|
||||
assertEqual(0, count);
|
||||
span.fire("somethingElseHappened");
|
||||
assertEqual(1, count);
|
||||
span.stopObserving("somethingElseHappened");
|
||||
span.fire("somethingElseHappened");
|
||||
assertEqual(1, count);
|
||||
}},
|
||||
|
||||
testDocumentContentLoadedEventFiresBeforeWindowLoad: function() { with(this) {
|
||||
assert(eventResults.contentLoaded, "contentLoaded");
|
||||
assert(eventResults.contentLoaded.endOfDocument, "contentLoaded.endOfDocument");
|
||||
assert(!eventResults.contentLoaded.windowLoad, "!contentLoaded.windowLoad");
|
||||
assert(eventResults.windowLoad, "windowLoad");
|
||||
assert(eventResults.windowLoad.endOfDocument, "windowLoad.endOfDocument");
|
||||
assert(eventResults.windowLoad.contentLoaded, "windowLoad.contentLoaded");
|
||||
}}
|
||||
|
||||
}, 'testlog');
|
||||
|
||||
document.observe("contentloaded", function(event) {
|
||||
eventResults.contentLoaded = {
|
||||
endOfDocument: eventResults.endOfDocument,
|
||||
windowLoad: eventResults.windowLoad
|
||||
};
|
||||
});
|
||||
|
||||
Event.observe(window, "load", function(event) {
|
||||
eventResults.windowLoad = {
|
||||
endOfDocument: eventResults.endOfDocument,
|
||||
contentLoaded: eventResults.contentLoaded
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
// ]]>
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
<script type="text/javascript">
|
||||
eventResults.endOfDocument = true;
|
||||
</script>
|
Loading…
Reference in New Issue
Block a user