Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
...
  • 14 commits
  • 4 files changed
  • 0 commit comments
  • 1 contributor
Commits on Mar 08, 2011
@Mardak Mardak Closes #173: Reduce the number of objects created for adding an image…
… node

Move the constant array of attribute/styles to a shared object and loop without using .forEach callbacks.
6eb3e6e
@Mardak Mardak Closes #172: Conditionally slice arguments for delayable functions to…
… avoid new arrays

Special case 0 and 1 parameter functions and fall back to slicing for more complex functions.
f18c3b4
@Mardak Mardak Closes #180: Don't bother slicing a 0-length unloader
Just short circuit if the length is 0.
c438789
@Mardak Mardak Closes #179: Save spec to local variable to avoid creating a new object
Avoid a double 4 level object dereference and do it just once.
c9fbdf5
@Mardak Mardak Closes #171: Reduce the number of objects created for matching pages
Conditionally create new strings and lazily generate lowercase versions. Cache a shared regex and use plain for loops.
69bda8b
@Mardak Mardak Closes #170: Don't require an title/url object for queryMatchesPage
Just take the title and url as separate strings without an object and fix up callers.
201eb64
@Mardak Mardak Closes #178: Remove the closure on queryMatchesPage cold path to avoi…
…d Call object

This last closure removes the Call object that would have been created at the entrance to the function. Don't bother optimizing other things on this cold path like the regex.
28b4c5a
@Mardak Mardak Closes #177: Avoid unnecessary tab lookup and title checks for fake tabs
Ignore title changes to about:blank pages that are likely to be the fake pages.
4a3e9c7
@Mardak Mardak Closes #169: Process fewer history results in javascript to reduce me…
…mory usage

Call AUTOCOMPLETE_MATCH with the title and url and dummy other values to match on boundary.
67166dd
@Mardak Mardak Closes #174: Shorten the wait for reshowing sites and tabs
Immediately show main data on open and wait 10x shorter (100ms) to reshow.
d663d8e
@Mardak Mardak Closes #175: Show the tab's title when it changes (including Connecti…
…ng... and switching tabs)

Remove the tab progress listener and just take the title from the tab that changes to Connecting.. on TabAttrModified. Also update when switching tabs. Show these background messages for 10 seconds.
be965fd
Commits on Mar 09, 2011
@Mardak Mardak Closes #168: Be smarter about when to run the notification timer
Avoid various objects like function callbacks every 100ms. Switch a number of .forEach callbacks to plain for loops.
4c72a54
@Mardak Mardak Closes #176: Soft reset happens too early before the full screen slid…
…er moves off

Just wait a little longer for the full screen slider animation to finish.
ca03255
@Mardak Mardak Bump Home Dash version to 7. a142f7c
View
259 homeDash/bootstrap.js
@@ -58,6 +58,9 @@ XPCOMUtils.defineLazyGetter(global, "prefs", function() {
return new Preferences("extensions.prospector.homeDash.");
});
+// How long to wait before reshowing other data on leaving another data
+const RESHOW_DELAY = 100;
+
/**
* Remove all existing chrome of the browser window
*/
@@ -256,6 +259,9 @@ function addDashboard(window) {
// Run each unload callback and clear them
function runUnload() {
+ if (unloadCallbacks.length == 0)
+ return;
+
unloadCallbacks.slice().forEach(function(callback) callback());
unloadCallbacks.length = 0;
}
@@ -1011,10 +1017,10 @@ function addDashboard(window) {
searchPreview1.reset();
searchPreview2.reset();
- // Immediately show history but wait to show sites and tabs
+ // Immediately show various data in the dashboard
history.show();
- sites.show(1000);
- tabs.show(1000);
+ sites.show();
+ tabs.show();
// Filter out the sites display as well as get the top sites
let topMatch = sites.search(query)[0];
@@ -1526,10 +1532,10 @@ function addDashboard(window) {
entryBox.unemphasize = function() {
entryBox.style.textDecoration = "";
- sites.show(1000);
- statusLine.reset();
pagePreview.reset();
- tabs.show(1000);
+ sites.show(RESHOW_DELAY);
+ statusLine.reset();
+ tabs.show(RESHOW_DELAY);
};
// Save the page preview when clicked
@@ -1593,6 +1599,7 @@ function addDashboard(window) {
history.allPagesByFrecency = Svc.History.DBConnection.createAsyncStatement(
"SELECT title, url " +
"FROM moz_places " +
+ "WHERE AUTOCOMPLETE_MATCH(:query, url, title, '', 0, 0, 0, 0, 2, 0) " +
"ORDER BY frecency DESC " +
"LIMIT :offset, " + PAGES_PER_CHUNK);
@@ -1657,8 +1664,9 @@ function addDashboard(window) {
if (query.indexOf(history.lastQuery) == 0) {
// Make a copy before iterating as we're removing unwanted entries
Array.slice(history.childNodes).forEach(function(entryBox) {
- if (!queryMatchesPage(query, entryBox.pageInfo)) {
- delete history.resultMap[entryBox.pageInfo.url];
+ let {title, url} = entryBox.pageInfo;
+ if (!queryMatchesPage(query, title, url)) {
+ delete history.resultMap[url];
history.removeChild(entryBox);
}
});
@@ -1704,6 +1712,7 @@ function addDashboard(window) {
history.searchPlaces = function(offset) {
let statement = history.allPagesByFrecency;
statement.params.offset = offset;
+ statement.params.query = history.lastQuery;
// Filter out history results based on the current query
let thisSearch = history.activeSearch = statement.executeAsync({
@@ -1749,16 +1758,20 @@ function addDashboard(window) {
// Keep track of how many rows we see to know where to continue
numProcessed++;
- // Construct a page info to test and potentially add
- let pageInfo = {
- title: row.getResultByName("title") || "",
- url: row.getResultByName("url")
- };
+ // Extract the relevant page information for matching
+ let title = row.getResultByName("title") || "";
+ let url = row.getResultByName("url");
// Determine if we should show add the result
- if (!queryMatchesPage(query, pageInfo))
+ if (!queryMatchesPage(query, title, url))
continue;
+ // Construct a page info now that we know it matches
+ let pageInfo = {
+ title: title,
+ url: url,
+ };
+
// Fill in some more page info values now that we want it
let URI = Services.io.newURI(pageInfo.url, null, null);
if (pageInfo.title == "")
@@ -2149,7 +2162,7 @@ function addDashboard(window) {
siteIcon.collapsed = true;
pagePreview.reset();
statusLine.reset();
- tabs.show(1000);
+ tabs.show(RESHOW_DELAY);
// Revert to the highlighting behavior of the last query
sites.search({repeat: true});
@@ -2189,6 +2202,7 @@ function addDashboard(window) {
// Find out which pages match the query
let pageMatches = [];
Array.forEach(sites.childNodes, function(siteBox) {
+ let {title, url} = siteBox.pageInfo;
let opacity;
// Just show the site if there's no query
if (query == "") {
@@ -2196,7 +2210,7 @@ function addDashboard(window) {
siteBox.style.pointerEvents = "auto";
}
// Emphasize the match and record it
- else if (queryMatchesPage(query, siteBox.pageInfo)) {
+ else if (queryMatchesPage(query, title, url)) {
opacity = 1;
siteBox.style.pointerEvents = "auto";
pageMatches.push(siteBox.pageInfo);
@@ -2208,7 +2222,7 @@ function addDashboard(window) {
}
// Set the desired opacity, but wait if it's a repeat search
- siteBox.setOpacity(opacity + "", repeat ? 1000 : 0);
+ siteBox.setOpacity(opacity + "", repeat ? RESHOW_DELAY : 0);
});
return pageMatches;
};
@@ -2239,14 +2253,12 @@ function addDashboard(window) {
return false;
// Allow exact url matches to succeed without checking others
- if (tab.linkedBrowser.currentURI.spec == query)
+ let url = tab.linkedBrowser.currentURI.spec;
+ if (url == query)
return true;
// For other queries, do the same filtering as other page matches
- return queryMatchesPage(query, {
- title: tab.getAttribute("label"),
- url: tab.linkedBrowser.currentURI.spec
- });
+ return queryMatchesPage(query, tab.getAttribute("label"), url);
});
};
@@ -2457,7 +2469,7 @@ function addDashboard(window) {
// Clear out the preview of this tab
pinBox.addEventListener("mouseout", function() {
- sites.show(1000);
+ sites.show(RESHOW_DELAY);
statusLine.reset();
tabPreview.reset();
}, false);
@@ -2777,7 +2789,7 @@ function addDashboard(window) {
// Only reshow sites if it was supposed to be shown
if (tabs.reshowSites)
- sites.show(1000);
+ sites.show(RESHOW_DELAY);
};
// Keep track of what tabs we're still waiting to take a thumbnail
@@ -2998,42 +3010,38 @@ function addDashboard(window) {
statusLine.value = text;
};
- // Show loading status of the current tab
- statusLine.setLoading = function(state) {
- switch (state) {
- // Only show start when transitioning from stopped
- case "start":
- if (statusLine.loadingState == null)
- break;
- return;
+ // Set the status text of a background status
+ statusLine.setBackground = function(text) {
+ // Ignore duplicate background statuses
+ if (statusLine.backgroundText == text)
+ return;
- // Only show stop if not already stopped
- case "stop":
- if (statusLine.loadingState == null)
- return;
- state = null;
- break;
+ // Show this status immediately
+ statusLine.backgroundText = text;
+ statusLine.collapsed = false;
+ statusLine.value = text;
- // Only show load when transitioning from start
- case "load":
- if (statusLine.loadingState == "start")
- break;
- return;
+ // Cancel any previous timers
+ if (statusLine.backgroundTimer != null)
+ statusLine.backgroundTimer();
- default:
- return;
- }
+ // Start a timer that will clear out the background status
+ statusLine.backgroundTimer = async(function() {
+ statusLine.backgroundTimer = null;
- // Update the current state and show it (or remove it)
- statusLine.loadingState = state;
- statusLine.reset();
+ // Clear out the background text if it's still being shown
+ if (statusLine.value == statusLine.backgroundText)
+ statusLine.reset();
+
+ statusLine.backgroundText = "";
+ }, 10000);
};
// Clear out the status line when closing or resetting
statusLine.reset = function() {
- // Show a connecting or loading state instead of just clearing
- if (statusLine.loadingState != null) {
- statusLine.set("progress" + statusLine.loadingState);
+ // Show the background status instead of nothing
+ if (statusLine.backgroundTimer != null) {
+ statusLine.value = statusLine.backgroundText;
return;
}
@@ -3061,33 +3069,18 @@ function addDashboard(window) {
// Initialize and get rid of any status
onClose(statusLine.reset);
- // Track the state and progress of the current tab
- let progressListener = {
- onLocationChange: function() {},
-
- // Indicate that the page is loading
- onProgressChange: function() {
- statusLine.setLoading("load");
- },
-
- onSecurityChange: function() {},
-
- onStateChange: function(progress, request, state, status) {
- // Only care about the top level state changes
- if (!(state & Ci.nsIWebProgressListener.STATE_IS_WINDOW))
- return;
-
- // Track only starts and stops
- if (state & Ci.nsIWebProgressListener.STATE_START)
- statusLine.setLoading("start");
- else if (state & Ci.nsIWebProgressListener.STATE_STOP)
- statusLine.setLoading("stop");
- },
+ // Show the title when the tab is selected or focused
+ listen(window, window, "focus", function(event) {
+ // Ignore non-window targets
+ let targetWindow = event.target.top;
+ if (targetWindow == null)
+ return;
- onStatusChange: function() {}
- };
- gBrowser.addProgressListener(progressListener);
- unload(function() gBrowser.removeProgressListener(progressListener), window);
+ // Only care about focus to the selected tab
+ let tab = gBrowser.selectedTab;
+ if (targetWindow == tab.linkedBrowser.contentWindow)
+ statusLine.setBackground(tab.label);
+ });
// Detect when we start shifting
listen(window, window, "keydown", function(event) {
@@ -3101,9 +3094,11 @@ function addDashboard(window) {
statusLine.shifted = false;
});
- // Clear out any existing loading status when switching tabs
- listen(window, gBrowser.tabContainer, "TabSelect", function(event) {
- statusLine.setLoading("stop");
+ // Show the title when it changes for the current tab
+ listen(window, gBrowser.tabContainer, "TabAttrModified", function(event) {
+ let tab = gBrowser.selectedTab;
+ if (event.target == tab)
+ statusLine.setBackground(tab.label);
});
// Don't allow opening new windows while clicking with shift
@@ -3322,6 +3317,9 @@ function addDashboard(window) {
statusLine.reset();
tabPreview.reset();;
}, false);
+
+ // Start updating the notification in-case it's the first one
+ notifications.startTimer();
};
// Provide a way to pause/unpause
@@ -3334,44 +3332,53 @@ function addDashboard(window) {
return;
notifications._paused = val;
- // Nothing more to do if we're unpausing
- if (!notifications.paused)
+ // Re-start the update timer when unpausing
+ if (!notifications.paused) {
+ notifications.startTimer();
return;
+ }
- // Make all notifications opaque
- Array.forEach(notifications.childNodes, function(notification) {
- notification.style.opacity = "1";
- });
+ // Stop the update timer if necessary
+ notifications.stopTimer();
+
+ // Make sure all notifications are opaque
+ let children = notifications.childNodes;
+ for (let i = children.length; --i >= 0; )
+ children[i].style.opacity = "1";
}
});
notifications._paused = false;
- // Continue updating when closing
- onClose(function() {
- notifications.paused = false;
- });
-
- // Pause updating when opening
- onOpen(function(reason) {
- notifications.paused = true;
+ // Start a repeating timer if not already started
+ notifications.startTimer = function() {
+ if (notifications.updateTimer != null)
+ return;
+ notifications.updateTimer = setInterval(function() {
+ notifications.update();
+ }, 100);
+ };
- // Re-show the notifications that have been hidden
- Array.forEach(notifications.childNodes, function(notification) {
- notification.collapsed = false;
- });
- });
+ // Stop the repeating timer to avoid updating state
+ notifications.stopTimer = function() {
+ if (notifications.updateTimer == null)
+ return;
+ clearInterval(notifications.updateTimer);
+ notifications.updateTimer = null;
+ };
// Keep updating notification icons and remove old ones
- let notifyInt = setInterval(function() {
- // Don't update the state when paused
- if (notifications.paused)
- return;
+ notifications.update = function() {
+ // Remember if there's more to update
+ let moreUpdates = false;
// Figure out opaqueness of all notifications
- Array.forEach(notifications.childNodes, function(notification) {
+ let children = notifications.childNodes;
+ for (let i = children.length; --i >= 0; ) {
+ let notification = children[i];
+
// Skip notifications that aren't visible anyway
if (notification.collapsed)
- return;
+ continue;
// Update until 600 iterations (60 seconds)
let state = ++notification.state;
@@ -3384,10 +3391,35 @@ function addDashboard(window) {
// Decrease opacity to 0 as state -> 600
opacity = Math.pow(opacity * Math.pow(1 - state / 600, .3), .2);
notification.style.opacity = opacity;
+
+ // Not at the last state, so we must have more
+ moreUpdates = true;
}
- });
- }, 100);
- unload(function() clearInterval(notifyInt), window);
+ }
+
+ // Only stop the timer if there's nothing left to update
+ if (moreUpdates)
+ return;
+ notifications.stopTimer();
+ };
+
+ // Make sure to clean up the timer if it's still going when unloading
+ unload(function() notifications.stopTimer(), window);
+
+ // Continue updating when closing
+ onClose(function() {
+ notifications.paused = false;
+ });
+
+ // Pause updating when opening
+ onOpen(function(reason) {
+ notifications.paused = true;
+
+ // Re-show the notifications that have been hidden
+ let children = notifications.childNodes;
+ for (let i = children.length; --i >= 0; )
+ children[i].collapsed = false;
+ });
// Pause updating opacity if the user might click
notifications.addEventListener("mouseover", function() {
@@ -3400,8 +3432,13 @@ function addDashboard(window) {
// Watch for title changes in background tabs
listen(window, gBrowser, "DOMTitleChanged", function(event) {
+ // Ignore blank tabs with no title
+ let targetDoc = event.target;
+ if (targetDoc.location == "about:blank")
+ return;
+
// Only care about top-level title changes
- let content = event.target.defaultView;
+ let content = targetDoc.defaultView;
if (content != content.top)
return;
@@ -3697,7 +3734,7 @@ function activateHomeDash(activating) {
resizeTimer = async(function() {
unload()
activateHomeDash(true);
- }, 1000);
+ }, 1500);
});
});
});
View
2  homeDash/install.rdf
@@ -8,7 +8,7 @@
<iconURL>http://mozillalabs.com/wp-content/themes/labs_project/img/prospector-header.png</iconURL>
<id>home.dash@prospector.labs.mozilla</id>
<name>Mozilla Labs: Prospector - Home Dash</name>
- <version>6</version>
+ <version>7</version>
<bootstrap>true</bootstrap>
<type>2</type>
View
2  homeDash/locales/en-US.properties
@@ -15,8 +15,6 @@ loadref: Jump to %S
loadscript: Run script
loadsecure: Go to secure %S
loadsite: Go to %S
-progressload: Loading\u2026
-progressstart: Connecting\u2026
reload: Reload %S
replace: Replace with %S
return: Return to the current page
View
149 homeDash/scripts/helper.js
@@ -90,7 +90,8 @@ function getAdaptiveInfo(query) {
return false;
// Make sure the page info still matches the query
- if (!queryMatchesPage(query, pageInfo))
+ let {title, url} = pageInfo;
+ if (!queryMatchesPage(query, title, url))
return false;
// Must be a good page!
@@ -308,28 +309,43 @@ function makeWindowHelpers(window) {
function addImage(parent, properties) {
let node = createNode("image");
- // Allow some attributes to be set if provided
- ["bottom", "collapsed", "left", "right", "src", "top"
- ].forEach(function(attribute) {
- let val = properties[attribute];
- if (val != null)
- node.setAttribute(attribute, val + "");
- });
+ // Set some selected attributes or styles if provided
+ for (let key in properties) {
+ let val = properties[key];
+ if (key in addImage.attributes)
+ node.setAttribute(key, val);
+ else if (key in addImage.styles)
+ node.style[key] = val;
+ }
// Add the node now that it has its attributes
parent.appendChild(node);
-
- // Allow some styles to be set if provided
- ["background", "borderRadius", "boxShadow", "cursor", "height", "opacity", "padding", "pointerEvents", "width"
- ].forEach(function(style) {
- let val = properties[style];
- if (val != null)
- node.style[style] = val + "";
- });
-
return node;
}
+ // Only look for certain attributes for adding images
+ addImage.attributes = {
+ bottom: 1,
+ collapsed: 1,
+ left: 1,
+ right: 1,
+ src: 1,
+ top: 1,
+ };
+
+ // Only look for certain styles for adding images
+ addImage.styles = {
+ background: 1,
+ borderRadius: 1,
+ boxShadow: 1,
+ cursor: 1,
+ height: 1,
+ opacity: 1,
+ padding: 1,
+ pointerEvents: 1,
+ width: 1,
+ };
+
// Watch for mouse move events that go further than some threshold
function addMoveLimitListener(threshold, moveExceed) {
let moveRef;
@@ -388,18 +404,26 @@ function makeWindowHelpers(window) {
return node;
// Make a delayable function that uses a sharable timer
- function makeDelayable(timerName, func) {
+ let makeDelayable = function(timerName, func) {
timerName += "Timer";
- return function() {
+ return function(arg) {
// Stop the shared timer if it's still waiting
if (node[timerName] != null)
node[timerName]();
// Pick out the arguments that the function wants
- let args = Array.slice(arguments, 0, func.length);
+ let numArgs = func.length;
+ let args;
+ if (numArgs > 1)
+ args = Array.slice(arguments, 0, func.length);
function callFunc() {
node[timerName] = null;
- func.apply(global, args);
+ if (numArgs == 0)
+ func.call(global);
+ else if (numArgs == 1)
+ func.call(global, arg);
+ else
+ func.apply(global, args);
}
// If we have some amount of time to wait, wait
@@ -536,15 +560,17 @@ function organizeTabsByRelation(tabs, reference) {
});
};
-// Get both the original-case and lowercase prepared text
+// Prepare the text by removing prefixes and shortening
function prepareMatchText(text) {
// Arbitrarily only search through the first some characters
- text = stripPrefix(text).slice(0, 100);
- return [text, text.toLowerCase()];
+ text = stripPrefix(text);
+ if (text.length > 100)
+ text = text.slice(0, 100);
+ return text;
}
// Check if a query string matches some page information
-function queryMatchesPage(query, {title, url}) {
+function queryMatchesPage(query, title, url) {
// Just short circuit if it's the empty query
if (query == "")
return true;
@@ -557,40 +583,77 @@ function queryMatchesPage(query, {title, url}) {
queryParts = queryMatchesPage.queryParts = [];
// Get rid of prefixes and identify each term's case-ness
- stripPrefix(query).split(/[\/\s]+/).forEach(function(part) {
- // NB: Add the term to the front, so the last term is processed first as
- // it will fail-to-match faster than earlier terms that already matched
- // when doing an incremental search.
- queryParts.unshift({
- ignoreCase: part == part.toLowerCase(),
+ let parts = stripPrefix(query).split(/[\/\s]+/);
+ for (let i = 0; i < parts.length; i++) {
+ let part = parts[i];
+ let ignoreCase = part == part.toLowerCase();
+ queryParts.push({
+ ignoreCase: ignoreCase,
term: part
});
- });
+
+ // Remember if any terms are to ignore
+ queryParts.anyIgnore = queryParts.anyIgnore || ignoreCase;
+ }
}
- // Fix up both the title and url in preparation for searching
- let [title, lowerTitle] = prepareMatchText(title);
- let [url, lowerUrl] = prepareMatchText(url);
+ // Fix up the title for searching; lazily fix the others
+ let prepTitle = prepareMatchText(title);
+ let lowerTitle, lowerUrl, prepUrl;
+
+ // Compute the lowercase title immediately if any term needs it
+ if (queryParts.anyIgnore)
+ lowerTitle = prepTitle.toLowerCase();
// Make sure every term in the query matches
- return queryParts.every(function({ignoreCase, term}) {
+ for (let i = queryParts.length; --i >= 0; ) {
+ let queryPart = queryParts[i];
+ let term = queryPart.term;
+
// For case insensitive terms, match against the lowercase text
- if (ignoreCase) {
- return matchesBoundary(term, lowerTitle, title) ||
- matchesBoundary(term, lowerUrl, url);
+ if (queryPart.ignoreCase) {
+ if (matchesBoundary(term, lowerTitle, prepTitle))
+ continue;
+
+ // Now prepare the other text if they aren't ready
+ if (prepUrl == null) {
+ prepUrl = prepareMatchText(url);
+ lowerUrl = prepUrl.toLowerCase();
+ }
+ else if (lowerUrl == null)
+ lowerUrl = prepUrl.toLowerCase();
+
+ // Check the url if the title didn't match
+ if (matchesBoundary(term, lowerUrl, prepUrl))
+ continue;
+ return false;
}
// For case sensitive terms, just use the original casing text
- return matchesBoundary(term, title, title) ||
- matchesBoundary(term, url, url);
- });
+ if (matchesBoundary(term, prepTitle, prepTitle))
+ continue;
+
+ // Prepare the url for a case sensitive check
+ if (prepUrl == null)
+ prepUrl = prepareMatchText(url);
+ if (matchesBoundary(term, prepUrl, prepUrl))
+ continue;
+ return false;
+ }
+ return true;
}
// Remove common protocol and subdomain prefixes
function stripPrefix(text) {
- return text.replace(/^(?:(?:ftp|https?):\/{0,2})?(?:ftp|w{3}\d*)?\.?/, "");
+ // Don't bother creating a new string if there's nothing to replace
+ if (text.search(stripPrefix.pattern) == -1)
+ return text;
+ return text.replace(stripPrefix.pattern, "");
}
+// Look for http/https/ftp and some common subdomains
+stripPrefix.pattern = /^(?:(?:ftp|https?):\/{0,2})?(?:ftp|w{3}\d*)?\.?/;
+
// Update the input history with some input and page info
function updateAdaptive(input, pageInfo) {
// Initialize or use the cached statement

No commit comments for this range

Something went wrong with that request. Please try again.