Skip to content

Instantly share code, notes, and snippets.

@mihaisucan
Created November 1, 2010 20:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mihaisucan/658779 to your computer and use it in GitHub Desktop.
Save mihaisucan/658779 to your computer and use it in GitHub Desktop.
diff --git a/toolkit/components/console/hudservice/HUDService.jsm b/toolkit/components/console/hudservice/HUDService.jsm
--- a/toolkit/components/console/hudservice/HUDService.jsm
+++ b/toolkit/components/console/hudservice/HUDService.jsm
@@ -1679,32 +1679,64 @@ HUD_SERVICE.prototype =
*/
adjustVisibilityForMessageType:
function HS_adjustVisibilityForMessageType(aHUDId, aMessageType, aState)
{
let displayNode = this.getOutputNodeById(aHUDId);
let outputNode = displayNode.querySelector(".hud-output-node");
let doc = outputNode.ownerDocument;
- this.liftNode(outputNode, function() {
- let xpath = ".//*[contains(@class, 'hud-msg-node') and " +
- "contains(@class, 'hud-" + aMessageType + "')]";
- let result = doc.evaluate(xpath, outputNode, null,
- Ci.nsIDOMXPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
- for (let i = 0; i < result.snapshotLength; i++) {
- if (aState) {
- result.snapshotItem(i).classList.remove("hud-filtered-by-type");
- } else {
- result.snapshotItem(i).classList.add("hud-filtered-by-type");
+ this.maintainScrollPosition(outputNode, function() {
+ this.liftNode(outputNode, function() {
+ let xpath = ".//*[contains(@class, 'hud-msg-node') and " +
+ "contains(@class, 'hud-" + aMessageType + "')]";
+ let result = doc.evaluate(xpath, outputNode, null,
+ Ci.nsIDOMXPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
+ for (let i = 0; i < result.snapshotLength; i++) {
+ if (aState) {
+ result.snapshotItem(i).classList.remove("hud-filtered-by-type");
+ }
+ else {
+ result.snapshotItem(i).classList.add("hud-filtered-by-type");
+ }
}
- }
+ });
});
},
/**
+ * Maintain the scroll position after the execution of a callback function.
+ *
+ * @param nsIDOMNode aOutputNode
+ * The outputNode for which the scroll position is rememebered.
+ * @param function aCallback
+ * The callback function you want to execute.
+ * @returns void
+ */
+ maintainScrollPosition:
+ function HS_maintainScrollPosition(aOutputNode, aCallback)
+ {
+ let oldScrollTop = aOutputNode.scrollTop;
+ let scrolledToBottom = oldScrollTop +
+ aOutputNode.clientHeight == aOutputNode.scrollHeight;
+
+ aCallback.call(this);
+
+ // Scroll to the bottom if the scroll was at the bottom.
+ if (scrolledToBottom) {
+ aOutputNode.scrollTop = aOutputNode.scrollHeight -
+ aOutputNode.clientHeight;
+ }
+ else {
+ // Remember the scroll position.
+ aOutputNode.scrollTop = Math.min(oldScrollTop, aOutputNode.scrollHeight);
+ }
+ },
+
+ /**
* Returns the source code of the XPath contains() function necessary to
* match the given query string.
*
* @param string The query string to convert.
* @returns string
*/
buildXPathFunctionForString: function HS_buildXPathFunctionForString(aStr)
{
@@ -1744,71 +1776,81 @@ HUD_SERVICE.prototype =
*/
adjustVisibilityOnSearchStringChange:
function HS_adjustVisibilityOnSearchStringChange(aHUDId, aSearchString)
{
let fn = this.buildXPathFunctionForString(aSearchString);
let displayNode = this.getOutputNodeById(aHUDId);
let outputNode = displayNode.querySelector(".hud-output-node");
let doc = outputNode.ownerDocument;
- this.liftNode(outputNode, function() {
- let xpath = './/*[contains(@class, "hud-msg-node") and ' +
- 'not(contains(@class, "hud-filtered-by-string")) and not(' + fn + ')]';
- let result = doc.evaluate(xpath, outputNode, null,
- Ci.nsIDOMXPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
- for (let i = 0; i < result.snapshotLength; i++) {
- result.snapshotItem(i).classList.add("hud-filtered-by-string");
- }
-
- xpath = './/*[contains(@class, "hud-msg-node") and contains(@class, ' +
- '"hud-filtered-by-string") and ' + fn + ']';
- result = doc.evaluate(xpath, outputNode, null,
- Ci.nsIDOMXPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
- for (let i = 0; i < result.snapshotLength; i++) {
- result.snapshotItem(i).classList.remove("hud-filtered-by-string");
- }
+
+ this.maintainScrollPosition(outputNode, function() {
+ this.liftNode(outputNode, function() {
+ let xpath = './/*[contains(@class, "hud-msg-node") and ' +
+ 'not(contains(@class, "hud-filtered-by-string")) and not(' + fn + ')]';
+ let result = doc.evaluate(xpath, outputNode, null,
+ Ci.nsIDOMXPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
+ for (let i = 0; i < result.snapshotLength; i++) {
+ result.snapshotItem(i).classList.add("hud-filtered-by-string");
+ }
+
+ xpath = './/*[contains(@class, "hud-msg-node") and contains(@class, ' +
+ '"hud-filtered-by-string") and ' + fn + ']';
+ result = doc.evaluate(xpath, outputNode, null,
+ Ci.nsIDOMXPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
+ for (let i = 0; i < result.snapshotLength; i++) {
+ result.snapshotItem(i).classList.remove("hud-filtered-by-string");
+ }
+ });
});
},
/**
* Makes a newly-inserted node invisible if the user has filtered it out.
*
* @param string aHUDId
* The ID of the HUD to alter.
* @param nsIDOMNode aNewNode
* The newly-inserted console message.
- * @returns void
+ * @returns boolean
+ * True if the new node was hidden (filtered out) or false otherwise.
*/
adjustVisibilityForNewlyInsertedNode:
function HS_adjustVisibilityForNewlyInsertedNode(aHUDId, aNewNode) {
// Filter on the search string.
let searchString = this.getFilterStringByHUDId(aHUDId);
let xpath = ".[" + this.buildXPathFunctionForString(searchString) + "]";
let doc = aNewNode.ownerDocument;
let result = doc.evaluate(xpath, aNewNode, null,
Ci.nsIDOMXPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
+ let hidden = false;
+
if (result.snapshotLength === 0) {
// The string filter didn't match, so the node is filtered.
aNewNode.classList.add("hud-filtered-by-string");
+ hidden = true;
}
// Filter by the message type.
let classes = aNewNode.classList;
let msgType = null;
for (let i = 0; i < classes.length; i++) {
let klass = classes.item(i);
if (klass !== "hud-msg-node" && klass.indexOf("hud-") === 0) {
msgType = klass.substring(4); // Strip off "hud-".
break;
}
}
if (msgType !== null && !this.getFilterState(aHUDId, msgType)) {
// The node is filtered by type.
aNewNode.classList.add("hud-filtered-by-type");
- }
+ hidden = true;
+ }
+
+ return hidden;
},
/**
* Keeps a weak reference for each HeadsUpDisplay that is created
*
*/
hudWeakReferences: {},
@@ -2109,17 +2151,16 @@ HUD_SERVICE.prototype =
if (!aMessage) {
throw new Error(ERRORS.MISSING_ARGS);
}
let lastGroupNode = this.appendGroupIfNecessary(aConsoleNode,
aMessage.timestamp);
lastGroupNode.appendChild(aMessageNode);
- ConsoleUtils.scrollToVisible(aMessageNode);
// store this message in the storage module:
this.storage.recordEntry(aMessage.hudId, aMessage);
pruneConsoleOutputIfNecessary(aConsoleNode);
},
/**
@@ -2131,17 +2172,16 @@ HUD_SERVICE.prototype =
* @param nsIDOMNode aMessageNode
* @returns void
*/
logConsoleMessage: function HS_logConsoleMessage(aMessage,
aConsoleNode,
aMessageNode)
{
aConsoleNode.appendChild(aMessageNode);
- ConsoleUtils.scrollToVisible(aMessageNode);
// store this message in the storage module:
this.storage.recordEntry(aMessage.hudId, aMessage);
},
/**
* Logs a Message.
* @param aMessage
@@ -3289,17 +3329,22 @@ HeadsUpDisplay.prototype = {
this.outputNode.addEventListener("DOMNodeInserted", function(ev) {
// DOMNodeInserted is also called when the output node is being *itself*
// (re)inserted into the DOM (which happens during a search, for
// example). For this reason, we need to ensure that we only check
// message nodes.
let node = ev.target;
if (node.nodeType === node.ELEMENT_NODE &&
node.classList.contains("hud-msg-node")) {
- HUDService.adjustVisibilityForNewlyInsertedNode(self.hudId, ev.target);
+ let hidden = HUDService.
+ adjustVisibilityForNewlyInsertedNode(self.hudId, ev.target);
+
+ if (!hidden) {
+ ConsoleUtils.scrollToVisible(node);
+ }
}
}, false);
this.filterSpacer = this.makeXULNode("spacer");
this.filterSpacer.setAttribute("flex", "1");
this.filterBox = this.makeXULNode("textbox");
this.filterBox.setAttribute("class", "compact hud-filter-box");
@@ -4312,17 +4357,16 @@ JSTerm.prototype = {
// TODO: format the aOutputObject and don't just use the
// aOuputObject.toString() function: [object object] -> Object {prop, ...}
// See bug 586249.
let textNode = this.textFactory(aOutputObject + "\n");
node.appendChild(textNode);
lastGroupNode.appendChild(node);
- ConsoleUtils.scrollToVisible(node);
pruneConsoleOutputIfNecessary(this.outputNode);
},
/**
* Writes a message to the HUD that originates from the interactive
* JavaScript console.
*
* @param string aOutputMessage
@@ -4350,19 +4394,17 @@ JSTerm.prototype = {
let classes = this.cssClassOverride.split(" ");
for (let i = 0; i < classes.length; i++) {
node.classList.add(classes[i]);
}
}
var textNode = this.textFactory(aOutputMessage + "\n");
node.appendChild(textNode);
-
lastGroupNode.appendChild(node);
- ConsoleUtils.scrollToVisible(node);
pruneConsoleOutputIfNecessary(this.outputNode);
},
clearOutput: function JST_clearOutput()
{
let outputNode = this.outputNode;
while (outputNode.firstChild) {
diff --git a/toolkit/components/console/hudservice/tests/browser/Makefile.in b/toolkit/components/console/hudservice/tests/browser/Makefile.in
--- a/toolkit/components/console/hudservice/tests/browser/Makefile.in
+++ b/toolkit/components/console/hudservice/tests/browser/Makefile.in
@@ -94,16 +94,17 @@ _BROWSER_TEST_FILES = \
browser_webconsole_bug_594477_clickable_output.js \
browser_webconsole_bug_589162_css_filter.js \
browser_webconsole_bug_597103_deactivateHUDForContext_unfocused_window.js \
browser_webconsole_bug_595350_multiple_windows_and_tabs.js \
browser_webconsole_bug_594497_history_arrow_keys.js \
browser_webconsole_bug_588342_document_focus.js \
browser_webconsole_bug_595934_message_categories.js \
browser_webconsole_bug_601352_scroll.js \
+ browser_webconsole_bug_597460_filter_scroll.js \
head.js \
$(NULL)
# compartment-disabled
# browser_webconsole_bug_593003_iframe_wrong_hud.js \
_BROWSER_TEST_PAGES = \
test-console.html \
diff --git a/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_597460_filter_scroll.js b/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_597460_filter_scroll.js
new file mode 100644
--- /dev/null
+++ b/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_597460_filter_scroll.js
@@ -0,0 +1,60 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Contributor(s):
+ * Mihai Șucan <mihai.sucan@gmail.com>
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+const TEST_URI = "http://example.com/browser/toolkit/components/console/hudservice/tests/browser/test-network.html";
+
+function tabLoad(aEvent) {
+ browser.removeEventListener(aEvent.type, arguments.callee, true);
+
+ openConsole();
+
+ let hudId = HUDService.getHudIdByWindow(content);
+ hud = HUDService.hudWeakReferences[hudId].get();
+
+ for (let i = 0; i < 200; i++) {
+ hud.console.log("test message " + i);
+ }
+
+ HUDService.setFilterState(hudId, "network", false);
+
+ hud.filterBox.value = "test message";
+ HUDService.updateFilterText(hud.filterBox);
+
+ browser.addEventListener("load", tabReload, true);
+
+ executeSoon(function() {
+ content.location.reload();
+ });
+}
+
+function tabReload(aEvent) {
+ browser.removeEventListener(aEvent.type, arguments.callee, true);
+
+ let msgNode = hud.outputNode.querySelector(".hud-network");
+ ok(msgNode, "found network message");
+ ok(msgNode.classList.contains("hud-filtered-by-type"),
+ "network message is filtered by type");
+ ok(msgNode.classList.contains("hud-filtered-by-string"),
+ "network message is filtered by string");
+
+ ok(hud.outputNode.scrollTop > 0, "scroll location is not at the top");
+
+ is(hud.outputNode.scrollTop,
+ hud.outputNode.scrollHeight - hud.outputNode.clientHeight,
+ "scroll location is correct");
+
+ executeSoon(finishTest);
+}
+
+function test() {
+ addTab(TEST_URI);
+ browser.addEventListener("load", tabLoad, true);
+}
+
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment