aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Kovar2010-09-27 11:13:37 -0500
committerAlex Kovar2010-09-27 11:13:37 -0500
commit60ffade9df3f46fca1bf31dc77e46ad9873a9cdf (patch)
tree835c479c6fe501972e305070e902cb8bd9278f2c
parentb2f3db6fe2a3ff8887c5961b868bebf530c4cfaf (diff)
parent9d9bd40ae050ae4b5b9665fcdde4c60e3486cc87 (diff)
downloadvimium-60ffade9df3f46fca1bf31dc77e46ad9873a9cdf.tar.bz2
Merge branch 'master' of http://github.com/philc/vimium
* 'master' of http://github.com/philc/vimium: Revert a rename - not sure why I committed that. Oops, fixed a regression. Code cleanup & README changes for the multiple link hints patch. Fix some frame logic and disable focusing the largest one for now because it's buggy with iframes. A bunch of changes having to do with the frame support patch: Updated README Added ab3 to Credits ;) Clean up code added resetLinkHintsMode Added activeteLinkHintsModeWithQueue and resetLinkHintsMode to linkHints.js and added 'q cmd' and 'q help cmd' to commands.js Update README with new/changed key mappings. Command to go to next frame. Only show the Help Dialog on the focused frame. Fix view source toggle when inside a frame. Basic Support for Frames Conflicts: commands.js manifest.json
-rw-r--r--CREDITS2
-rw-r--r--README.markdown6
-rw-r--r--background_page.html90
-rw-r--r--commands.js18
-rw-r--r--linkHints.js54
-rw-r--r--manifest.json8
-rw-r--r--vimiumFrontend.js65
7 files changed, 194 insertions, 49 deletions
diff --git a/CREDITS b/CREDITS
index 8c986adc..9f814f7a 100644
--- a/CREDITS
+++ b/CREDITS
@@ -14,6 +14,8 @@ Contributors:
lack
markstos
rodimius
+ Tim Morgan <tim@timmorgan.org> (github: seven1m)
tsigo
+ Werner Laurensse (github: ab3)
Feel free to add real names in addition to GitHub usernames.
diff --git a/README.markdown b/README.markdown
index 2e144110..36e267bf 100644
--- a/README.markdown
+++ b/README.markdown
@@ -36,8 +36,9 @@ Navigating the current page:
<c-b> scroll up a full page
f activate link hints mode to open in current tab
F activate link hints mode to open in new tab
+ <a-f> activate link hints mode to open multiple links in a new tab
r reload
- gf view source
+ gs view source
zi zoom in
zo zoom out
/ enter find mode -- type your search query and hit enter to search or esc to cancel
@@ -46,6 +47,7 @@ Navigating the current page:
i enter insert mode -- all commands will be ignored until you hit esc to exit
yy copy the current url to the clipboard
gu go up one level in the URL hierarchy
+ gf cycle forward to the next frame
Navigating your history:
H go back in history
@@ -84,6 +86,8 @@ Release Notes
- In link hints mode, holding down the shift key will now toggle between opening in the current tab and opening in a new tab.
- Two new commands (`zH` and `zL`) to scroll to the left and right edges of the page.
- A new command (`gi`) to focus the first (or n-th) text input box on the page.
+- A new command (`<a-f>`) to open up multiple links at a time in new tabs.
+- Frame support.
- Bug fixes.
1.19 (06/29/2010)
diff --git a/background_page.html b/background_page.html
index 991992b8..e0c1f3ce 100644
--- a/background_page.html
+++ b/background_page.html
@@ -14,6 +14,8 @@
var keyQueue = ""; // Queue of keys typed
var validFirstKeys = {};
var singleKeyCommands = [];
+ var focusedFrame = null;
+ var framesForTab = {};
// Keys are either literal characters, or "named" - for example <a-b> (alt+b), <left> (the left arrow) or <f12>
// This regular expression captures two groups, the first is a named key, the second is the remainder of the string.
@@ -67,7 +69,10 @@
var sendRequestHandlers = {
getCompletionKeys: getCompletionKeys,
getLinkHintCss: getLinkHintCss,
+ openUrlInCurrentTab: openUrlInCurrentTab,
openOptionsPageInNewTab: openOptionsPageInNewTab,
+ registerFrame: registerFrame,
+ frameFocused: handleFrameFocused,
upgradeNotificationClosed: upgradeNotificationClosed,
updateScrollPosition: handleUpdateScrollPosition
};
@@ -91,6 +96,7 @@
}
// domReady is the appropriate time to show the "vimium has been upgraded" message.
+ // TODO: This might be broken on pages with frames.
if (shouldShowUpgradeMessage())
chrome.tabs.sendRequest(senderTabId, { name: "showUpgradeNotification", version: currentVersion });
}
@@ -153,9 +159,9 @@
returnPort.postMessage({ zoomLevel: zoomLevel });
}
- function showHelp() {
+ function showHelp(callback, frameId) {
chrome.tabs.getSelected(null, function(tab) {
- chrome.tabs.sendRequest(tab.id, { name: "showHelpDialog", dialogHtml: helpDialogHtml() });
+ chrome.tabs.sendRequest(tab.id, { name: "showHelpDialog", dialogHtml: helpDialogHtml(), frameId:frameId });
});
}
@@ -220,6 +226,15 @@
return {completionKeys: generateCompletionKeys()};
}
+ /**
+ * Opens the url in the current tab.
+ */
+ function openUrlInCurrentTab(request) {
+ chrome.tabs.getSelected(null, function(tab) {
+ chrome.tabs.update(tab.id, {url: request.url});
+ });
+ }
+
/*
* Returns the core CSS used for link hints, along with any user-provided overrides.
*/
@@ -268,9 +283,9 @@
if (selectionChangedHandlers.length > 0) { selectionChangedHandlers.pop().call(); }
});
- function repeatFunction(func, totalCount, currentCount) {
+ function repeatFunction(func, totalCount, currentCount, frameId) {
if (currentCount < totalCount)
- func(function() { repeatFunction(func, totalCount, currentCount + 1); });
+ func(function() { repeatFunction(func, totalCount, currentCount + 1, frameId); }, frameId);
}
// Returns the scroll coordinates of the given tab. Pass in a callback of the form:
@@ -369,6 +384,7 @@
tabQueue[openTabInfo.windowId] = [openTabInfo];
delete openTabs[tabId];
+ delete framesForTab[tabId];
});
chrome.windows.onRemoved.addListener(function(windowId) {
@@ -487,19 +503,20 @@
return {count: count, command: command};
}
- function handleKeyDown(key, port) {
+ function handleKeyDown(request, port) {
+ var key = request.keyChar;
if (key == "<ESC>") {
console.log("clearing keyQueue");
keyQueue = ""
}
else {
console.log("checking keyQueue: [", keyQueue + key, "]");
- keyQueue = checkKeyQueue(keyQueue + key, port.tab.id);
+ keyQueue = checkKeyQueue(keyQueue + key, port.tab.id, request.frameId);
console.log("new KeyQueue: " + keyQueue);
}
}
- function checkKeyQueue(keysToCheck, tabId) {
+ function checkKeyQueue(keysToCheck, tabId, frameId) {
var refreshedCompletionKeys = false;
var splitHash = splitKeyQueue(keysToCheck);
command = splitHash.command;
@@ -515,6 +532,7 @@
if (!registryEntry.isBackgroundCommand) {
var port = chrome.tabs.connect(tabId, { name: "executePageCommand" });
port.postMessage({ command: registryEntry.command,
+ frameId: frameId,
count: count,
passCountToFunction: registryEntry.passCountToFunction,
completionKeys: generateCompletionKeys("")
@@ -522,7 +540,7 @@
refreshedCompletionKeys = true;
} else {
- repeatFunction(this[registryEntry.command], count, 0);
+ repeatFunction(this[registryEntry.command], count, 0, frameId);
}
newKeyQueue = "";
@@ -592,6 +610,62 @@
});
}
+ function registerFrame(request, sender) {
+ if (!framesForTab[sender.tab.id])
+ framesForTab[sender.tab.id] = { frames: [] };
+
+ if (request.top) {
+ focusedFrame = request.frameId;
+ framesForTab[sender.tab.id].total = request.total;
+ }
+
+ framesForTab[sender.tab.id].frames.push({ id: request.frameId, area: request.area });
+
+ // We've seen all the frames. Time to focus the largest one.
+ // NOTE: Disabled because it's buggy with iframes.
+ // if (framesForTab[sender.tab.id].frames.length >= framesForTab[sender.tab.id].total)
+ // focusLargestFrame(sender.tab.id);
+ }
+
+ function focusLargestFrame(tabId) {
+ var mainFrameId = null;
+ var mainFrameArea = 0;
+
+ for (var i = 0; i < framesForTab[tabId].frames.length; i++) {
+ var currentFrame = framesForTab[tabId].frames[i];
+
+ if (currentFrame.area > mainFrameArea) {
+ mainFrameId = currentFrame.id;
+ mainFrameArea = currentFrame.area;
+ }
+ }
+
+ chrome.tabs.sendRequest(tabId, { name: "focusFrame", frameId: mainFrameId, highlight: false });
+ }
+
+ function handleFrameFocused(request, sender) {
+ focusedFrame = request.frameId;
+ }
+
+ function nextFrame(callback, frameId) {
+ chrome.tabs.getSelected(null, function(tab) {
+ var index;
+ var frames = framesForTab[tab.id].frames;
+
+ for (index=0; index < frames.length; index++) {
+ if (frames[index].id == focusedFrame)
+ break;
+ }
+
+ if (index >= frames.length-1)
+ index = 0;
+ else
+ index++;
+
+ chrome.tabs.sendRequest(tab.id, { name: "focusFrame", frameId: frames[index].id, highlight: true });
+ });
+ }
+
function init() {
clearKeyMappingsAndSetDefaults();
diff --git a/commands.js b/commands.js
index e9a0bd41..fb264510 100644
--- a/commands.js
+++ b/commands.js
@@ -97,7 +97,7 @@ function clearKeyMappingsAndSetDefaults() {
mapKeyToCommand('<c-f>', 'scrollFullPageDown');
mapKeyToCommand('<c-b>', 'scrollFullPageUp');
mapKeyToCommand('r', 'reload');
- mapKeyToCommand('gf', 'toggleViewSource');
+ mapKeyToCommand('gs', 'toggleViewSource');
mapKeyToCommand('i', 'enterInsertMode');
@@ -110,8 +110,9 @@ function clearKeyMappingsAndSetDefaults() {
mapKeyToCommand('gi', 'focusInput');
- mapKeyToCommand('f', 'activateLinkHintsMode');
- mapKeyToCommand('F', 'activateLinkHintsModeToOpenInNewTab');
+ mapKeyToCommand('f', 'activateLinkHintsMode');
+ mapKeyToCommand('F', 'activateLinkHintsModeToOpenInNewTab');
+ mapKeyToCommand('<a-f>', 'activateLinkHintsModeWithQueue');
mapKeyToCommand('/', 'enterFindMode');
mapKeyToCommand('n', 'performFind');
@@ -127,8 +128,12 @@ function clearKeyMappingsAndSetDefaults() {
mapKeyToCommand('t', 'createTab');
mapKeyToCommand('d', 'removeTab');
mapKeyToCommand('u', 'restoreTab');
+
mapKeyToCommand('b', 'activateBookmarkFindMode');
mapKeyToCommand('B', 'activateBookmarkFindModeToOpenInNewTab')
+
+ mapKeyToCommand('gf', 'nextFrame');
+
}
// Navigating the current page:
@@ -158,6 +163,7 @@ addCommand('focusInput', 'Focus the first (or n-th) text box on the pag
addCommand('activateLinkHintsMode', 'Enter link hints mode to open links in current tab');
addCommand('activateLinkHintsModeToOpenInNewTab', 'Enter link hints mode to open links in new tab');
+addCommand('activateLinkHintsModeWithQueue', 'Enter link hints mode to open multiple links in a new tab');
addCommand('activateBookmarkFindMode', 'Find bookmarks to open in current tab');
addCommand('activateBookmarkFindModeToOpenInNewTab', 'Find bookmarks to open in new tab');
@@ -180,6 +186,8 @@ addCommand('createTab', 'Create new tab', true);
addCommand('removeTab', 'Close current tab', true);
addCommand('restoreTab', "Restore closed tab", true);
+addCommand('nextFrame', "Cycle forward to the next frame on the page", true);
+
// An ordered listing of all available commands, grouped by type. This is the order they will
// be shown in the help page.
@@ -190,8 +198,8 @@ var commandGroups = {
"scrollPageUp", "scrollFullPageDown",
"reload", "toggleViewSource", "zoomIn", "zoomOut", "copyCurrentUrl", "goUp",
"enterInsertMode", "focusInput",
- "activateLinkHintsMode", "activateLinkHintsModeToOpenInNewTab",
- "enterFindMode", "performFind", "performBackwardsFind"],
+ "activateLinkHintsMode", "activateLinkHintsModeToOpenInNewTab", "activateLinkHintsModeWithQueue",
+ "enterFindMode", "performFind", "performBackwardsFind", "nextFrame"],
historyNavigation:
["goBack", "goForward"],
tabManipulation:
diff --git a/linkHints.js b/linkHints.js
index fcaa832b..7593a630 100644
--- a/linkHints.js
+++ b/linkHints.js
@@ -13,6 +13,7 @@ var hintMarkerContainingDiv = null;
var hintKeystrokeQueue = [];
var linkHintsModeActivated = false;
var shouldOpenLinkHintInNewTab = false;
+var shouldOpenLinkHintWithQueue = false;
// Whether link hint's "open in current/new tab" setting is currently toggled
var openLinkModeToggle = false;
// Whether we have added to the page the CSS needed to display link hints.
@@ -32,25 +33,32 @@ var clickableElementsXPath = (function() {
})();
// We need this as a top-level function because our command system doesn't yet support arguments.
-function activateLinkHintsModeToOpenInNewTab() { activateLinkHintsMode(true); }
+function activateLinkHintsModeToOpenInNewTab() { activateLinkHintsMode(true, false); }
-function activateLinkHintsMode(openInNewTab) {
+function activateLinkHintsModeWithQueue() { activateLinkHintsMode(true, true); }
+
+function activateLinkHintsMode(openInNewTab, withQueue) {
if (!linkHintsCssAdded)
addCssToPage(linkHintCss); // linkHintCss is declared by vimiumFrontend.js
linkHintCssAdded = true;
linkHintsModeActivated = true;
- setOpenLinkMode(openInNewTab);
+ setOpenLinkMode(openInNewTab, withQueue);
buildLinkHints();
document.addEventListener("keydown", onKeyDownInLinkHintsMode, true);
document.addEventListener("keyup", onKeyUpInLinkHintsMode, true);
}
-function setOpenLinkMode(openInNewTab) {
+function setOpenLinkMode(openInNewTab, withQueue) {
shouldOpenLinkHintInNewTab = openInNewTab;
- if (shouldOpenLinkHintInNewTab)
- HUD.show("Open link in new tab");
- else
- HUD.show("Open link in current tab");
+ shouldOpenLinkHintWithQueue = withQueue;
+ if (shouldOpenLinkHintWithQueue) {
+ HUD.show("Open multiple links in a new tab");
+ } else {
+ if (shouldOpenLinkHintInNewTab)
+ HUD.show("Open link in new tab");
+ else
+ HUD.show("Open link in current tab");
+ }
}
/*
@@ -143,10 +151,11 @@ function isVisible(element, clientRect) {
}
function onKeyDownInLinkHintsMode(event) {
+ console.log("Key Down");
if (event.keyCode == keyCodes.shiftKey && !openLinkModeToggle) {
// Toggle whether to open link in a new or current tab.
- setOpenLinkMode(!shouldOpenLinkHintInNewTab);
- openLinkModeToggle = true;
+ setOpenLinkMode(!shouldOpenLinkHintInNewTab, shouldOpenLinkHintWithQueue);
+ openLinkModeToggle = true;
}
var keyChar = getKeyChar(event);
@@ -177,8 +186,8 @@ function onKeyDownInLinkHintsMode(event) {
function onKeyUpInLinkHintsMode(event) {
if (event.keyCode == keyCodes.shiftKey && openLinkModeToggle) {
// Revert toggle on whether to open link in new or current tab.
- setOpenLinkMode(!shouldOpenLinkHintInNewTab);
- openLinkModeToggle = false;
+ setOpenLinkMode(!shouldOpenLinkHintInNewTab, shouldOpenLinkHintWithQueue);
+ openLinkModeToggle = false;
}
event.stopPropagation();
event.preventDefault();
@@ -202,13 +211,19 @@ function updateLinkHints() {
} else {
// When we're opening the link in the current tab, don't navigate to the selected link immediately;
// we want to give the user some feedback depicting which link they've selected by focusing it.
- if (!shouldOpenLinkHintInNewTab)
- setTimeout(function() { simulateClick(matchedLink); }, 400);
- else
+ if (shouldOpenLinkHintWithQueue) {
simulateClick(matchedLink);
- matchedLink.focus();
+ resetLinkHintsMode();
+ } else if (shouldOpenLinkHintInNewTab) {
+ simulateClick(matchedLink);
+ matchedLink.focus();
+ deactivateLinkHintsMode();
+ } else {
+ setTimeout(function() { simulateClick(matchedLink); }, 400);
+ matchedLink.focus();
+ deactivateLinkHintsMode();
+ }
}
- deactivateLinkHintsMode();
}
}
@@ -289,6 +304,11 @@ function deactivateLinkHintsMode() {
HUD.hide();
}
+function resetLinkHintsMode() {
+ deactivateLinkHintsMode();
+ activateLinkHintsModeWithQueue();
+}
+
/*
* Creates a link marker for the given link.
*/
diff --git a/manifest.json b/manifest.json
index baba4e09..878d8b5c 100644
--- a/manifest.json
+++ b/manifest.json
@@ -8,7 +8,10 @@
"background_page": "background_page.html",
"options_page": "options.html",
"permissions": [
- "tabs", "bookmarks"
+ "tabs",
+ "bookmarks",
+ "http://*/*",
+ "https://*/*"
],
"content_scripts": [
{
@@ -19,7 +22,8 @@
"vimiumFrontend.js",
"bookmarks.js"
],
- "run_at": "document_start"
+ "run_at": "document_start",
+ "all_frames": true
}
]
}
diff --git a/vimiumFrontend.js b/vimiumFrontend.js
index da850909..9e9ec87a 100644
--- a/vimiumFrontend.js
+++ b/vimiumFrontend.js
@@ -26,6 +26,11 @@ var linkHintCss;
// TODO(philc): This should be pulled from the extension's storage when the page loads.
var currentZoomLevel = 100;
+/*
+ * Give this frame a unique id.
+ */
+frameId = Math.floor(Math.random()*999999999)
+
var hasModifiersRegex = /^<([amc]-)+.>/;
function getSetting(key) {
@@ -66,7 +71,10 @@ function initializePreDomReady() {
if (isShowingHelpDialog)
hideHelpDialog();
else
- showHelpDialog(request.dialogHtml);
+ showHelpDialog(request.dialogHtml, request.frameId);
+ else if (request.name == "focusFrame")
+ if(frameId == request.frameId)
+ focusThisFrame(request.highlight);
else if (request.name == "refreshCompletionKeys")
refreshCompletionKeys(request.completionKeys);
sendResponse({}); // Free up the resources used by this open connection.
@@ -75,7 +83,7 @@ function initializePreDomReady() {
chrome.extension.onConnect.addListener(function(port, name) {
if (port.name == "executePageCommand") {
port.onMessage.addListener(function(args) {
- if (this[args.command]) {
+ if (this[args.command] && frameId == args.frameId) {
if (args.passCountToFunction) {
this[args.command].call(null, args.count);
} else {
@@ -138,10 +146,32 @@ function initializeWhenEnabled() {
enterInsertModeIfElementIsFocused();
}
+
+/*
+ * The backend needs to know which frame has focus.
+ */
+window.addEventListener("focus", function(e){
+ chrome.extension.sendRequest({handler: "frameFocused", frameId: frameId});
+});
+
+/*
+ * Called from the backend in order to change frame focus.
+ */
+function focusThisFrame(shouldHighlight) {
+ window.focus();
+ if (document.body && shouldHighlight) {
+ var borderWas = document.body.style.border;
+ document.body.style.border = '5px solid yellow';
+ setTimeout(function(){document.body.style.border = borderWas}, 200);
+ }
+}
+
/*
* Initialization tasks that must wait for the document to be ready.
*/
function initializeOnDomReady() {
+ registerFrameIfSizeAvailable(window.top == window.self);
+
if (isEnabledForUrl)
enterInsertModeIfElementIsFocused();
@@ -149,6 +179,14 @@ function initializeOnDomReady() {
chrome.extension.connect({ name: "domReady" });
};
+// This is a little hacky but sometimes the size wasn't available on domReady?
+function registerFrameIfSizeAvailable (top) {
+ if (innerWidth != undefined && innerWidth != 0 && innerHeight != undefined && innerHeight != 0)
+ chrome.extension.sendRequest({ handler: "registerFrame", frameId: frameId, area: innerWidth * innerHeight, top: top, total: frames.length + 1 });
+ else
+ setTimeout(function () { registerFrameIfSizeAvailable(top); }, 100);
+}
+
/*
* Checks the currently focused element of the document and will enter insert mode if that element is focusable.
*/
@@ -258,9 +296,10 @@ function copyCurrentUrl() {
function toggleViewSourceCallback(url) {
if (url.substr(0, 12) == "view-source:")
{
- window.location.href = url.substr(12, url.length - 12);
+ url = url.substr(12, url.length - 12);
}
- else { window.location.href = "view-source:" + url; }
+ else { url = "view-source:" + url; }
+ chrome.extension.sendRequest({handler: "openUrlInCurrentTab", url:url});
}
/**
@@ -349,10 +388,10 @@ function onKeydown(event) {
event.stopPropagation();
}
- keyPort.postMessage(keyChar);
+ keyPort.postMessage({keyChar:keyChar, frameId:frameId});
}
else if (isEscape(event)) {
- keyPort.postMessage("<ESC>");
+ keyPort.postMessage({keyChar:"<ESC>", frameId:frameId});
}
}
}
@@ -494,8 +533,8 @@ function exitFindMode() {
HUD.hide();
}
-function showHelpDialog(html) {
- if (isShowingHelpDialog || !document.body)
+function showHelpDialog(html, fid) {
+ if (isShowingHelpDialog || !document.body || fid != frameId)
return;
isShowingHelpDialog = true;
var container = document.createElement("div");
@@ -716,14 +755,8 @@ function addCssToPage(css) {
head.appendChild(style);
}
-// Prevent our content script from being run on iframes -- only allow it to run on the top level DOM "window".
-// TODO(philc): We don't want to process multiple keyhandlers etc. when embedded on a page containing IFrames.
-// This should be revisited, because sometimes we *do* want to listen inside of the currently focused iframe.
-var isIframe = (window.self != window.parent);
-if (!isIframe) {
- initializePreDomReady();
- window.addEventListener("DOMContentLoaded", initializeOnDomReady);
-}
+initializePreDomReady();
+window.addEventListener("DOMContentLoaded", initializeOnDomReady);
window.onbeforeunload = function() {
chrome.extension.sendRequest({ handler: "updateScrollPosition",