Merge mozilla-central into mozilla-inbound

This commit is contained in:
Ehsan Akhgari 2012-11-01 10:42:41 -04:00
commit 4bb8ace1ba
15 changed files with 394 additions and 117 deletions

View File

@ -155,8 +155,10 @@ Components.utils.import('resource://gre/modules/ctypes.jsm');
})();
// =================== Debugger ====================
SettingsListener.observe('devtools.debugger.remote-enabled', false, function(enabled) {
SettingsListener.observe('devtools.debugger.remote-enabled', false, function(value) {
Services.prefs.setBoolPref('devtools.debugger.remote-enabled', value);
// This preference is consulted during startup
Services.prefs.savePrefFile(null);
});
SettingsListener.observe('devtools.debugger.log', false, function(value) {

View File

@ -867,7 +867,11 @@ function ElementEditor(aContainer, aNode)
return;
}
this._applyAttributes(aVal);
try {
this._applyAttributes(aVal);
} catch (x) {
return;
}
}.bind(this)
});
@ -962,11 +966,16 @@ ElementEditor.prototype = {
this.undo.startBatch();
// Remove the attribute stored in this editor and re-add any attributes
// parsed out of the input element.
this._removeAttribute(this.node, aAttr.name)
this._applyAttributes(aVal, attr);
this.undo.endBatch();
// parsed out of the input element. Restore original attribute if
// parsing fails.
this._removeAttribute(this.node, aAttr.name);
try {
this._applyAttributes(aVal, attr);
this.undo.endBatch();
} catch (e) {
this.undo.endBatch();
this.undo.undo();
}
}.bind(this)
});
@ -987,6 +996,7 @@ ElementEditor.prototype = {
* @param Element aAttrNode the attribute editor that created this
* set of attributes, used to place new attributes where the
* user put them.
* @throws SYNTAX_ERR if aValue is not well-formed.
*/
_applyAttributes: function EE__applyAttributes(aValue, aAttrNode)
{
@ -996,6 +1006,7 @@ ElementEditor.prototype = {
let parseTag = (this.node.namespaceURI.match(/svg/i) ? "svg" :
(this.node.namespaceURI.match(/mathml/i) ? "math" : "div"));
let parseText = "<" + parseTag + " " + aValue + "/>";
// Throws exception if parseText is not well-formed.
dummyNode.innerHTML = parseText;
let parsedNode = dummyNode.firstChild;

View File

@ -33,6 +33,9 @@
</div>
</div>
</div>
<div id="node22" class="unchanged"></div>
<div id="node23"></div>
<div id="node24"></div>
<div id="retag-me">
<div id="retag-me-2"></div>
</div>

View File

@ -73,6 +73,28 @@ function test() {
}
},
// Try change an attribute to a badly formed string
{
before: function() {
assertAttributes(doc.querySelector("#node22"), {
id: "node22",
class: "unchanged"
});
},
execute: function() {
let editor = markup.getContainer(doc.querySelector("#node22")).editor;
let attr = editor.attrs["class"].querySelector(".editable");
editField(attr, 'class="""');
},
after: function() {
assertAttributes(doc.querySelector("#node22"), {
id: "node22",
class: "unchanged"
});
}
},
// Remove an attribute
{
before: function() {
@ -114,6 +136,25 @@ function test() {
}
},
// Try add a badly formed attribute by clicking the empty space after a node
{
before: function() {
assertAttributes(doc.querySelector("#node23"), {
id: "node23",
});
},
execute: function() {
let editor = markup.getContainer(doc.querySelector("#node23")).editor;
let attr = editor.newAttr;
editField(attr, 'class="newclass" style="""');
},
after: function() {
assertAttributes(doc.querySelector("#node23"), {
id: "node23",
});
}
},
// Add attributes by adding to an existing attribute's entry
{
setup: function() {
@ -140,6 +181,25 @@ function test() {
}
},
// Try add attributes by adding to an existing attribute's entry
{
before: function() {
assertAttributes(doc.querySelector("#node24"), {
id: "node24",
});
},
execute: function() {
let editor = markup.getContainer(doc.querySelector("#node24")).editor;
let attr = editor.attrs["id"].querySelector(".editable");
editField(attr, attr.textContent + ' class="""');
},
after: function() {
assertAttributes(doc.querySelector("#node24"), {
id: "node24",
});
}
},
// Remove an element with the delete key
{
before: function() {

View File

@ -729,13 +729,16 @@ var Scratchpad = {
*/
getRecentFiles: function SP_getRecentFiles()
{
let maxRecent = Services.prefs.getIntPref(PREF_RECENT_FILES_MAX);
let branch = Services.prefs.
getBranch("devtools.scratchpad.");
let branch = Services.prefs.getBranch("devtools.scratchpad.");
let filePaths = [];
// WARNING: Do not use getCharPref here, it doesn't play nicely with
// Unicode strings.
if (branch.prefHasUserValue("recentFilePaths")) {
filePaths = JSON.parse(branch.getCharPref("recentFilePaths"));
let data = branch.getComplexValue("recentFilePaths",
Ci.nsISupportsString).data;
filePaths = JSON.parse(data);
}
return filePaths;
@ -781,10 +784,16 @@ var Scratchpad = {
filePaths.push(aFile.path);
let branch = Services.prefs.
getBranch("devtools.scratchpad.");
branch.setCharPref("recentFilePaths", JSON.stringify(filePaths));
return;
// WARNING: Do not use setCharPref here, it doesn't play nicely with
// Unicode strings.
let str = Cc["@mozilla.org/supports-string;1"]
.createInstance(Ci.nsISupportsString);
str.data = JSON.stringify(filePaths);
let branch = Services.prefs.getBranch("devtools.scratchpad.");
branch.setComplexValue("recentFilePaths",
Ci.nsISupportsString, str);
},
/**
@ -868,11 +877,19 @@ var Scratchpad = {
let filePaths = this.getRecentFiles();
if (maxRecent < filePaths.length) {
let branch = Services.prefs.
getBranch("devtools.scratchpad.");
let diff = filePaths.length - maxRecent;
filePaths.splice(0, diff);
branch.setCharPref("recentFilePaths", JSON.stringify(filePaths));
// WARNING: Do not use setCharPref here, it doesn't play nicely with
// Unicode strings.
let str = Cc["@mozilla.org/supports-string;1"]
.createInstance(Ci.nsISupportsString);
str.data = JSON.stringify(filePaths);
let branch = Services.prefs.getBranch("devtools.scratchpad.");
branch.setComplexValue("recentFilePaths",
Ci.nsISupportsString, str);
}
}
},

View File

@ -27,7 +27,7 @@ var lists = {
// Temporary file names.
let gFileName01 = "file01_ForBug651942.tmp"
let gFileName02 = "file02_ForBug651942.tmp"
let gFileName02 = "☕" // See bug 783858 for more information
let gFileName03 = "file03_ForBug651942.tmp"
let gFileName04 = "file04_ForBug651942.tmp"

View File

@ -943,15 +943,15 @@ PropertyView.prototype = {
}
if (!this.tree.viewedElement || !this.visible) {
this.valueNode.innerHTML = "";
this.valueNode.textContent = "";
this.matchedSelectorsContainer.parentNode.hidden = true;
this.matchedSelectorsContainer.innerHTML = "";
this.matchedSelectorsContainer.textContent = "";
this.matchedExpander.removeAttribute("open");
return;
}
this.tree.numVisibleProperties++;
this.valueNode.innerHTML = this.propertyInfo.value;
this.valueNode.textContent = this.propertyInfo.value;
this.refreshAllSelectors();
},

View File

@ -1124,12 +1124,16 @@ CssRuleView.prototype = {
*/
_onMenuUpdate: function CssRuleView_onMenuUpdate(aEvent)
{
let node = this.doc.popupNode;
// Copy selection.
let disable = this.doc.defaultView.getSelection().isCollapsed;
let editorSelection = node.className == "styleinspector-propertyeditor" &&
node.selectionEnd - node.selectionStart != 0;
let disable = this.doc.defaultView.getSelection().isCollapsed &&
!editorSelection;
this._copyItem.disabled = disable;
// Copy property, copy property name & copy property value.
let node = this.doc.popupNode;
if (!node) {
return;
}
@ -1159,16 +1163,26 @@ CssRuleView.prototype = {
*/
_onCopy: function CssRuleView_onCopy(aEvent)
{
let win = this.doc.defaultView;
let text = win.getSelection().toString();
let target = this.doc.popupNode || aEvent.target;
let text;
// Remove any double newlines.
text = text.replace(/(\r?\n)\r?\n/g, "$1");
if (target.nodeName == "input") {
let start = Math.min(target.selectionStart, target.selectionEnd);
let end = Math.max(target.selectionStart, target.selectionEnd);
let count = end - start;
text = target.value.substr(start, count);
} else {
let win = this.doc.defaultView;
text = win.getSelection().toString();
// Remove "inline"
let inline = _strings.GetStringFromName("rule.sourceInline");
let rx = new RegExp("^" + inline + "\\r?\\n?", "g");
text = text.replace(rx, "");
// Remove any double newlines.
text = text.replace(/(\r?\n)\r?\n/g, "$1");
// Remove "inline"
let inline = _strings.GetStringFromName("rule.sourceInline");
let rx = new RegExp("^" + inline + "\\r?\\n?", "g");
text = text.replace(rx, "");
}
clipboardHelper.copyString(text, this.doc);
@ -1277,12 +1291,13 @@ CssRuleView.prototype = {
_onCopyProperty: function CssRuleView_onCopyProperty(aEvent)
{
let node = this.doc.popupNode;
if (!node) {
return;
}
if (!node.classList.contains("ruleview-propertyname")) {
node = node.querySelector(".ruleview-propertyname");
node = node.parentNode.parentNode.querySelector(".ruleview-propertyname");
}
if (node) {
@ -1303,7 +1318,7 @@ CssRuleView.prototype = {
}
if (!node.classList.contains("ruleview-propertyvalue")) {
node = node.querySelector(".ruleview-propertyvalue");
node = node.parentNode.parentNode.querySelector(".ruleview-propertyvalue");
}
if (node) {
@ -1381,6 +1396,19 @@ RuleEditor.prototype = {
}
}.bind(this), false);
this.element.addEventListener("mousedown", function() {
let editorNodes =
this.doc.querySelectorAll(".styleinspector-propertyeditor");
if (editorNodes) {
for (let node of editorNodes) {
if (node.inplaceEditor) {
node.inplaceEditor._clear();
}
}
}
}.bind(this), false);
this.propertyList = createChild(code, "ul", {
class: "ruleview-propertylist"
});

View File

@ -88,8 +88,8 @@ function testClip()
SimpleTest.waitForClipboard(function IUI_boundCopyPropCheck() {
return checkClipboardData(expectedPattern);
},
checkCopyRule, checkCopyRuleWithEditorSelected, function() {
failedClipboard(expectedPattern, checkCopyRuleWithEditorSelected);
checkCopyRule, checkCopyProperty, function() {
failedClipboard(expectedPattern, checkCopyProperty);
});
});
}
@ -118,57 +118,6 @@ function checkCopyRule() {
menu.hidePopup();
}
function checkCopyRuleWithEditorSelected()
{
let contentDoc = ruleViewFrame().contentDocument;
let rules = contentDoc.querySelectorAll(".ruleview-rule");
let propNodes = contentDoc.querySelectorAll(".ruleview-property");
let propNode = propNodes[2];
let propNameNode = propNode.querySelector(".ruleview-propertyname");
ok(propNameNode, "we have the property name node");
info("Checking that _boundCopyRule() returns the correct clipboard value");
let expectedPattern = "element {[\\r\\n]+" +
" margin: 10em;[\\r\\n]+" +
" font-size: 14pt;[\\r\\n]+" +
" font-family: helvetica,sans-serif;[\\r\\n]+" +
" color: rgb\\(170, 170, 170\\);[\\r\\n]+" +
"}[\\r\\n]*";
let elementRuleEditor = rules[0]._ruleEditor;
waitForEditorFocus(elementRuleEditor.element, function onNewElement(aEditor) {
ok(aEditor, "we have the editor");
waitForBlur.editor = aEditor;
// We need the context menu to open in the correct place in order for
// popupNode to be propertly set.
EventUtils.synthesizeMouse(aEditor.input, 1, 1,
{ type: "contextmenu", button: 2 }, ruleViewFrame().contentWindow);
SimpleTest.waitForClipboard(function IUI_boundCopyCheckWithSelection() {
let menu = contentDoc.querySelector("#rule-view-context-menu");
ok(menu, "we have the context menu");
menu.hidePopup();
return checkClipboardData(expectedPattern);
}, ruleView()._boundCopyRule, waitForBlur, function() {
failedClipboard(expectedPattern, checkCopyProperty);
});
});
EventUtils.synthesizeMouse(propNameNode, 1, 1, { }, ruleViewFrame().contentWindow);
}
function waitForBlur()
{
waitForEditorBlur(waitForBlur.editor, function() {
waitForBlur.editor = null;
checkCopyProperty();
});
waitForBlur.editor.input.blur();
}
function checkCopyProperty()
{
let contentDoc = ruleViewFrame().contentDocument;
@ -197,7 +146,7 @@ function checkCopyPropertyName()
{
info("Checking that _onCopyProperty() returns " +
"the correct clipboard value");
let expectedPattern = "font-family";
let expectedPattern = "margin";
SimpleTest.waitForClipboard(function IUI_boundCopyPropNameCheck() {
return checkClipboardData(expectedPattern);
@ -212,7 +161,7 @@ function checkCopyPropertyValue()
{
info("Checking that _onCopyPropertyValue() " +
" returns the correct clipboard value");
let expectedPattern = "helvetica,sans-serif";
let expectedPattern = "10em";
SimpleTest.waitForClipboard(function IUI_boundCopyPropValueCheck() {
return checkClipboardData(expectedPattern);
@ -248,11 +197,61 @@ function checkCopySelection()
SimpleTest.waitForClipboard(function IUI_boundCopyCheck() {
return checkClipboardData(expectedPattern);
},ruleView()._boundCopy, finishup, function() {
failedClipboard(expectedPattern, finishup);
},ruleView()._boundCopy, testSimpleCopy, function() {
failedClipboard(expectedPattern, testSimpleCopy);
});
}
function testSimpleCopy()
{
executeSoon(function() {
info("Checking that _onCopy() returns the correct clipboard value");
let expectedPattern = "element {[\\r\\n]+" +
" margin: 10em;[\\r\\n]+" +
" font-size: 14pt;[\\r\\n]+" +
" font-family: helvetica,sans-serif;[\\r\\n]+" +
" color: rgb\\(170, 170, 170\\);[\\r\\n]+" +
"}[\\r\\n]*";
SimpleTest.waitForClipboard(function IUI_testSimpleCopy() {
return checkClipboardData(expectedPattern);
},
checkSimpleCopy, finishup, function() {
failedClipboard(expectedPattern, finishup);
});
});
}
function checkSimpleCopy() {
let contentDoc = ruleViewFrame().contentDocument;
let props = contentDoc.querySelectorAll(".ruleview-code");
is(props.length, 2, "checking property length");
let prop = props[0];
selectNode(prop);
// We need the context menu to open in the correct place in order for
// popupNode to be propertly set.
EventUtils.synthesizeMouse(prop, 1, 1, { type: "contextmenu", button: 2 },
ruleViewFrame().contentWindow);
ruleView()._boundCopy();
let menu = contentDoc.querySelector("#rule-view-context-menu");
ok(menu, "we have the context menu");
menu.hidePopup();
}
function selectNode(aNode) {
let doc = aNode.ownerDocument;
let win = doc.defaultView;
let range = doc.createRange();
range.selectNode(aNode);
win.getSelection().addRange(range);
}
function checkClipboardData(aExpectedPattern)
{
let actual = SpecialPowers.getClipboardData("text/unicode");

View File

@ -35,7 +35,7 @@ interface nsIEventListenerInfo : nsISupports
nsISupports getDebugObject();
};
[scriptable, uuid(0cf94aa6-ea9a-44cb-a063-be834afa679d)]
[scriptable, uuid(f6964bfb-dabe-4cab-9733-be0ee2bf8171)]
interface nsIEventListenerService : nsISupports
{
/**
@ -81,5 +81,16 @@ interface nsIEventListenerService : nsISupports
in DOMString type,
in nsIDOMEventListener listener,
in boolean useCapture);
void addListenerForAllEvents(in nsIDOMEventTarget target,
in nsIDOMEventListener listener,
[optional] in boolean aUseCapture,
[optional] in boolean aWantsUntrusted,
[optional] in boolean aSystemEventGroup);
void removeListenerForAllEvents(in nsIDOMEventTarget target,
in nsIDOMEventListener listener,
[optional] in boolean aUseCapture,
[optional] in boolean aSystemEventGroup);
};

View File

@ -58,9 +58,10 @@
using namespace mozilla::dom;
using namespace mozilla::hal;
#define EVENT_TYPE_EQUALS( ls, type, userType ) \
(ls->mEventType == type && \
(ls->mEventType != NS_USER_DEFINED_EVENT || ls->mTypeAtom == userType))
#define EVENT_TYPE_EQUALS(ls, type, userType, allEvents) \
((ls->mEventType == type && \
(ls->mEventType != NS_USER_DEFINED_EVENT || ls->mTypeAtom == userType)) || \
(allEvents && ls->mAllEvents))
static NS_DEFINE_CID(kDOMScriptObjectFactoryCID,
NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
@ -193,9 +194,10 @@ nsEventListenerManager::AddEventListener(nsIDOMEventListener *aListener,
uint32_t aType,
nsIAtom* aTypeAtom,
int32_t aFlags,
bool aHandler)
bool aHandler,
bool aAllEvents)
{
NS_ABORT_IF_FALSE(aType && aTypeAtom, "Missing type");
NS_ABORT_IF_FALSE((aType && aTypeAtom) || aAllEvents, "Missing type");
if (!aListener) {
return;
@ -210,7 +212,7 @@ nsEventListenerManager::AddEventListener(nsIDOMEventListener *aListener,
if (ls->mListener == aListener &&
ls->mListenerIsHandler == aHandler &&
ls->mFlags == aFlags &&
EVENT_TYPE_EQUALS(ls, aType, aTypeAtom)) {
EVENT_TYPE_EQUALS(ls, aType, aTypeAtom, aAllEvents)) {
return;
}
}
@ -218,13 +220,14 @@ nsEventListenerManager::AddEventListener(nsIDOMEventListener *aListener,
mNoListenerForEvent = NS_EVENT_TYPE_NULL;
mNoListenerForEventAtom = nullptr;
ls = mListeners.AppendElement();
ls = aAllEvents ? mListeners.InsertElementAt(0) : mListeners.AppendElement();
ls->mListener = aListener;
ls->mEventType = aType;
ls->mTypeAtom = aTypeAtom;
ls->mFlags = aFlags;
ls->mListenerIsHandler = aHandler;
ls->mHandlerIsString = false;
ls->mAllEvents = aAllEvents;
// Detect the type of event listener.
nsCOMPtr<nsIXPConnectWrappedJS> wjs;
@ -406,7 +409,8 @@ void
nsEventListenerManager::RemoveEventListener(nsIDOMEventListener *aListener,
uint32_t aType,
nsIAtom* aUserType,
int32_t aFlags)
int32_t aFlags,
bool aAllEvents)
{
if (!aListener || !aType) {
return;
@ -424,7 +428,7 @@ nsEventListenerManager::RemoveEventListener(nsIDOMEventListener *aListener,
for (uint32_t i = 0; i < count; ++i) {
ls = &mListeners.ElementAt(i);
if (EVENT_TYPE_EQUALS(ls, aType, aUserType)) {
if (EVENT_TYPE_EQUALS(ls, aType, aUserType, aAllEvents)) {
++typeCount;
if (ls->mListener == aListener &&
(ls->mFlags & ~NS_PRIV_EVENT_UNTRUSTED_PERMITTED) == aFlags) {
@ -442,14 +446,14 @@ nsEventListenerManager::RemoveEventListener(nsIDOMEventListener *aListener,
}
}
if (deviceType && typeCount == 0) {
if (!aAllEvents && deviceType && typeCount == 0) {
DisableDevice(aType);
} else if (timeChangeEvent && typeCount == 0) {
nsCOMPtr<nsPIDOMWindow> window = GetTargetAsInnerWindow();
if (window) {
window->DisableTimeChangeNotifications();
}
} else if (networkEvent && typeCount == 0) {
} else if (!aAllEvents && networkEvent && typeCount == 0) {
nsCOMPtr<nsPIDOMWindow> window = GetTargetAsInnerWindow();
if (window) {
window->DisableNetworkEvent(aType);
@ -463,9 +467,9 @@ ListenerCanHandle(nsListenerStruct* aLs, nsEvent* aEvent)
// This is slightly different from EVENT_TYPE_EQUALS in that it returns
// true even when aEvent->message == NS_USER_DEFINED_EVENT and
// aLs=>mEventType != NS_USER_DEFINED_EVENT as long as the atoms are the same
return aEvent->message == NS_USER_DEFINED_EVENT ?
return (aEvent->message == NS_USER_DEFINED_EVENT ?
(aLs->mTypeAtom == aEvent->userType) :
(aLs->mEventType == aEvent->message);
(aLs->mEventType == aEvent->message)) || aLs->mAllEvents;
}
void
@ -498,8 +502,8 @@ nsEventListenerManager::FindEventHandler(uint32_t aEventType,
uint32_t count = mListeners.Length();
for (uint32_t i = 0; i < count; ++i) {
ls = &mListeners.ElementAt(i);
if (ls->mListenerIsHandler && EVENT_TYPE_EQUALS(ls, aEventType, aTypeAtom))
{
if (ls->mListenerIsHandler &&
EVENT_TYPE_EQUALS(ls, aEventType, aTypeAtom, false)) {
return ls;
}
}
@ -992,6 +996,34 @@ nsEventListenerManager::RemoveEventListener(const nsAString& aType,
RemoveEventListenerByType(aListener, aType, flags);
}
void
nsEventListenerManager::AddListenerForAllEvents(nsIDOMEventListener* aListener,
bool aUseCapture,
bool aWantsUntrusted,
bool aSystemEventGroup)
{
PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
if (aWantsUntrusted) {
flags |= NS_PRIV_EVENT_UNTRUSTED_PERMITTED;
}
if (aSystemEventGroup) {
flags |= NS_EVENT_FLAG_SYSTEM_EVENT;
}
AddEventListener(aListener, NS_EVENT_TYPE_ALL, nullptr, flags, false, true);
}
void
nsEventListenerManager::RemoveListenerForAllEvents(nsIDOMEventListener* aListener,
bool aUseCapture,
bool aSystemEventGroup)
{
PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
if (aSystemEventGroup) {
flags |= NS_EVENT_FLAG_SYSTEM_EVENT;
}
RemoveEventListener(aListener, NS_EVENT_TYPE_ALL, nullptr, flags, true);
}
bool
nsEventListenerManager::HasMutationListeners()
{

View File

@ -46,6 +46,7 @@ struct nsListenerStruct
uint8_t mListenerType;
bool mListenerIsHandler : 1;
bool mHandlerIsString : 1;
bool mAllEvents : 1;
nsIJSEventListener* GetJSListener() const {
return (mListenerType == eJSEventListener) ?
@ -83,6 +84,14 @@ public:
nsIDOMEventListener* aListener,
bool aUseCapture);
void AddListenerForAllEvents(nsIDOMEventListener* aListener,
bool aUseCapture,
bool aWantsUntrusted,
bool aSystemEventGroup);
void RemoveListenerForAllEvents(nsIDOMEventListener* aListener,
bool aUseCapture,
bool aSystemEventGroup);
/**
* Sets events listeners of all types.
* @param an event listener
@ -292,11 +301,13 @@ protected:
uint32_t aType,
nsIAtom* aTypeAtom,
int32_t aFlags,
bool aHandler = false);
bool aHandler = false,
bool aAllEvents = false);
void RemoveEventListener(nsIDOMEventListener *aListener,
uint32_t aType,
nsIAtom* aUserType,
int32_t aFlags);
int32_t aFlags,
bool aAllEvents = false);
void RemoveAllListeners();
const EventTypeData* GetTypeDataForIID(const nsIID& aIID);
const EventTypeData* GetTypeDataForEventName(nsIAtom* aName);

View File

@ -279,6 +279,35 @@ nsEventListenerService::RemoveSystemEventListener(nsIDOMEventTarget *aTarget,
return NS_OK;
}
NS_IMETHODIMP
nsEventListenerService::AddListenerForAllEvents(nsIDOMEventTarget* aTarget,
nsIDOMEventListener* aListener,
bool aUseCapture,
bool aWantsUntrusted,
bool aSystemEventGroup)
{
NS_ENSURE_STATE(aTarget && aListener);
nsEventListenerManager* manager = aTarget->GetListenerManager(true);
NS_ENSURE_STATE(manager);
manager->AddListenerForAllEvents(aListener, aUseCapture, aWantsUntrusted,
aSystemEventGroup);
return NS_OK;
}
NS_IMETHODIMP
nsEventListenerService::RemoveListenerForAllEvents(nsIDOMEventTarget* aTarget,
nsIDOMEventListener* aListener,
bool aUseCapture,
bool aSystemEventGroup)
{
NS_ENSURE_STATE(aTarget && aListener);
nsEventListenerManager* manager = aTarget->GetListenerManager(false);
if (manager) {
manager->RemoveListenerForAllEvents(aListener, aUseCapture, aSystemEventGroup);
}
return NS_OK;
}
nsresult
NS_NewEventListenerService(nsIEventListenerService** aResult)
{

View File

@ -19,6 +19,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=448602
/** Test for Bug 448602 **/
var els, root, l2, l3;
function runTests() {
/*
@ -27,11 +28,11 @@ function runTests() {
var jsd = SpecialPowers.Components.classes['@mozilla.org/js/jsd/debugger-service;1']
.getService(jsdIDebuggerService);
*/
var els = SpecialPowers.Cc["@mozilla.org/eventlistenerservice;1"]
.getService(SpecialPowers.Ci.nsIEventListenerService);
els = SpecialPowers.Cc["@mozilla.org/eventlistenerservice;1"]
.getService(SpecialPowers.Ci.nsIEventListenerService);
// Event listener info tests
var root = document.getElementById("testroot");
root = document.getElementById("testroot");
var infos = els.getListenerInfoFor(root, {});
is(infos.length, 0, "Element shouldn't have listeners (1)");
@ -103,8 +104,8 @@ function runTests() {
is(infos[0].allowsUntrusted, true, "Should allow untrusted events (3)");
// Event target chain tests
var l2 = document.getElementById("testlevel2");
var l3 = document.getElementById("testlevel3");
l2 = document.getElementById("testlevel2");
l3 = document.getElementById("testlevel3");
var textnode = l3.firstChild;
var chain = SpecialPowers.unwrap(els.getEventTargetChainFor(textnode, {}));
ok(chain.length > 3, "Too short event target chain.");
@ -138,10 +139,82 @@ function runTests() {
} catch (ex) {
ok(true, "We should be still running.");
}
SimpleTest.finish();
setTimeout(testAllListener, 0);
}
function dispatchTrusted(t, o) {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
t.dispatchEvent(new Event("testevent", o));
}
function testAllListener() {
els = SpecialPowers.wrap(els);
var results = [];
var expectedResults =
[ { target: "testlevel3", phase: 3, trusted: false },
{ target: "testlevel3", phase: 3, trusted: false },
{ target: "testlevel3", phase: 3, trusted: true },
{ target: "testlevel3", phase: 3, trusted: true },
{ target: "testlevel3", phase: 3, trusted: true }
];
function allListener(e) {
results.push({
target: e.target.id,
phase: e.eventPhase,
trusted: e.isTrusted
});
e.stopPropagation();
}
function allListenerTrustedOnly(e) {
results.push({
target: e.target.id,
phase: e.eventPhase,
trusted: e.isTrusted
});
e.stopPropagation();
}
els.addListenerForAllEvents(root, allListener, false, true);
els.addListenerForAllEvents(root, allListener, false, true, true);
els.addListenerForAllEvents(root, allListenerTrustedOnly, false, false, true);
l3.dispatchEvent(new Event("testevent", { bubbles: true }));
dispatchTrusted(l3, { bubbles: true });
els.removeListenerForAllEvents(root, allListener, false);
els.removeListenerForAllEvents(root, allListener, false, true);
els.removeListenerForAllEvents(root, allListenerTrustedOnly, false, true);
// make sure removeListenerForAllEvents works.
l3.dispatchEvent(new Event("testevent", { bubbles: true }));
dispatchTrusted(l3, { bubbles: true });
// Test the order of event listeners.
var clickListenerCalled = false;
var allListenerCalled = false;
function clickListener() {
clickListenerCalled = true;
ok(allListenerCalled, "Should have called '*' listener before normal listener!");
}
function allListener2() {
allListenerCalled = true;
notok(clickListenerCalled, "Shouldn't have called click listener before '*' listener!");
}
root.onclick = null; // Remove the listener added in earlier tests.
root.addEventListener("click", clickListener);
els.addListenerForAllEvents(root, allListener2, false, true);
l3.dispatchEvent(new MouseEvent("click", { bubbles: true }));
root.removeEventListener("click", clickListener);
els.removeListenerForAllEvents(root, allListener2, false);
ok(allListenerCalled, "Should have called '*' listener");
ok(clickListenerCalled, "Should have called click listener");
is(results.length, expectedResults.length, "count");
for (var i = 0; i < expectedResults.length; ++i) {
for (var p in expectedResults[i]) {
is(results[i][p], expectedResults[i][p], p);
}
}
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addLoadEvent(runTests);

View File

@ -134,6 +134,7 @@ class nsHashKey;
#define NS_EVENT_BUBBLE_MASK (~(NS_EVENT_FLAG_CAPTURE | NS_EVENT_FLAG_NO_CONTENT_DISPATCH))
#define NS_EVENT_TYPE_NULL 0
#define NS_EVENT_TYPE_ALL 1 // Not a real event type
/**
* GUI MESSAGES