Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
tree: 897a20fb37
Fetching contributors…

Cannot retrieve contributors at this time

168 lines (156 sloc) 5.661 kb
# HG changeset patch
# Parent a7fadfbad93262a227f70459aa36d968aed3ae61
# User Thaddee Tyl <thaddee.tyl@gmail.com>
Bug 779415 — Autocompletion of non-objects
diff --git a/browser/devtools/webconsole/WebConsoleUtils.jsm b/browser/devtools/webconsole/WebConsoleUtils.jsm
--- a/browser/devtools/webconsole/WebConsoleUtils.jsm
+++ b/browser/devtools/webconsole/WebConsoleUtils.jsm
@@ -953,7 +953,7 @@ function JSPropertyProvider(aScope, aInp
return null;
}
- let matches = Object.keys(getMatchedProps(obj, matchProp));
+ let matches = Object.keys(getMatchedProps(obj, {matchProp:matchProp}));
return {
matchProp: matchProp,
@@ -962,51 +962,60 @@ function JSPropertyProvider(aScope, aInp
}
/**
- * Get all accessible properties on this object.
+ * Get all accessible properties on this JS value.
* Filter those properties by name.
* Take only a certain number of those.
*
- * @param object obj
- * Object whose properties we want to collect.
+ * @param mixed aObj
+ * JS value whose properties we want to collect.
*
- * @param string matchProp
- * Filter for properties that match this one.
- * Defaults to the empty string (which always matches).
+ * @param object aOptions
+ * Options that the algorithm takes.
+ * - matchProp (string): Filter for properties that match this one.
+ * Defaults to the empty string (which always matches).
*
* @return object
* Object whose keys are all accessible properties on the object.
*/
-function getMatchedProps(aObj, aMatchProp = "")
+function getMatchedProps(aObj, aOptions = {matchProp: ""})
{
+ // Argument defaults.
+ aOptions.matchProp = aOptions.matchProp || "";
+
+ if (aObj == null) { return {}; }
+ try {
+ Object.getPrototypeOf(aObj);
+ } catch(e) {
+ aObj = aObj.constructor.prototype;
+ }
let c = MAX_COMPLETIONS;
let names = {}; // Using an Object to avoid duplicates.
- let ownNames = Object.getOwnPropertyNames(aObj);
- for (let i = 0; i < ownNames.length; i++) {
- if (ownNames[i].indexOf(aMatchProp) == 0) {
- if (names[ownNames[i]] != true) {
- c--;
- if (c < 0) {
- return names;
- }
+
+ // We need to go up the prototype chain.
+ let ownNames = null;
+ while (aObj !== null) {
+ ownNames = Object.getOwnPropertyNames(aObj);
+ for (let i = 0; i < ownNames.length; i++) {
+ // Filtering happens here.
+ // If we already have it in, no need to append it.
+ if (ownNames[i].indexOf(aOptions.matchProp) != 0 ||
+ names[ownNames[i]] == true) {
+ continue;
+ }
+ c--;
+ if (c < 0) {
+ return names;
+ }
+ // If it is an array index, we can't take it.
+ // This uses a trick: converting a string to a number yields NaN if
+ // the operation failed, and NaN is not equal to itself.
+ if (+ownNames[i] != +ownNames[i]) {
names[ownNames[i]] = true;
}
}
+ aObj = Object.getPrototypeOf(aObj);
}
- // We need to recursively go up the prototype chain.
- aObj = Object.getPrototypeOf(aObj);
- if (aObj !== null) {
- let parentScope = getMatchedProps(aObj, aMatchProp);
- for (let name in parentScope) {
- if (names[name] != true) {
- c--;
- if (c < 0) {
- return names;
- }
- names[name] = true;
- }
- }
- }
return names;
}
diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_585991_autocomplete_keys.js b/browser/devtools/webconsole/test/browser_webconsole_bug_585991_autocomplete_keys.js
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_585991_autocomplete_keys.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_585991_autocomplete_keys.js
@@ -195,7 +195,7 @@ function testReturnKey()
ok(!completeNode.value, "completeNode is empty");
- executeSoon(finishTest);
+ dontShowArrayNumbers();
}, false);
EventUtils.synthesizeKey("VK_RETURN", {});
@@ -207,3 +207,30 @@ function testReturnKey()
EventUtils.synthesizeKey(".", {});
});
}
+
+function dontShowArrayNumbers()
+{
+ content.wrappedJSObject.foobarBug585991 = ["Sherlock Holmes"];
+
+ let jsterm = HUD.jsterm;
+ let popup = jsterm.autocompletePopup;
+ let completeNode = jsterm.completeNode;
+
+ popup._panel.addEventListener("popupshown", function onShown() {
+ popup._panel.removeEventListener("popupshown", onShown, false);
+
+ let sameItems = popup.getItems().map(function(e) {return e.label;});
+ ok(!sameItems.some(function(prop, index) { prop === "0"; }),
+ "Completing on an array doesn't show numbers.");
+
+ popup._panel.addEventListener("popuphidden", consoleOpened, false);
+
+ EventUtils.synthesizeKey("VK_TAB", {});
+
+ executeSoon(finishTest);
+ }, false);
+
+ jsterm.setInputValue("window.foobarBug585991");
+ EventUtils.synthesizeKey(".", {});
+}
+
diff --git a/browser/devtools/webconsole/test/browser_webconsole_completion.js b/browser/devtools/webconsole/test/browser_webconsole_completion.js
--- a/browser/devtools/webconsole/test/browser_webconsole_completion.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_completion.js
@@ -98,6 +98,13 @@ function testCompletion(hud) {
is(jsterm.completeNode.value, " \n e", "multi-line completion");
+ // Test non-object autocompletion.
+ input.value = "Object.name.sl";
+ jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext);
+ yield;
+
+ is(jsterm.completeNode.value, " ice", "non-object completion");
+
testDriver = jsterm = input = null;
executeSoon(finishTest);
yield;
Jump to Line
Something went wrong with that request. Please try again.